Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Mar 2014 19:22:17 +0000 (15:22 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 31 Mar 2014 19:22:17 +0000 (15:22 -0400)
2099 files changed:
.gitignore
Documentation/00-INDEX
Documentation/ABI/testing/sysfs-bus-mdio
Documentation/ABI/testing/sysfs-class-net-mesh
Documentation/ABI/testing/sysfs-ptp
Documentation/PCI/MSI-HOWTO.txt
Documentation/RCU/00-INDEX
Documentation/arm/00-INDEX
Documentation/blackfin/00-INDEX
Documentation/block/00-INDEX
Documentation/device-mapper/cache.txt
Documentation/device-mapper/thin-provisioning.txt
Documentation/devicetree/00-INDEX
Documentation/devicetree/bindings/arm/omap/omap.txt
Documentation/devicetree/bindings/clock/renesas,cpg-mstp-clocks.txt
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
Documentation/devicetree/bindings/net/altera_tse.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/arc_emac.txt
Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/can/sja1000.txt
Documentation/devicetree/bindings/net/cavium-mix.txt
Documentation/devicetree/bindings/net/cavium-pip.txt
Documentation/devicetree/bindings/net/cdns-emac.txt
Documentation/devicetree/bindings/net/cpsw.txt
Documentation/devicetree/bindings/net/davicom-dm9000.txt
Documentation/devicetree/bindings/net/davinci_emac.txt
Documentation/devicetree/bindings/net/ethernet.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/fsl-fec.txt
Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
Documentation/devicetree/bindings/net/lpc-eth.txt
Documentation/devicetree/bindings/net/macb.txt
Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
Documentation/devicetree/bindings/net/marvell-orion-net.txt
Documentation/devicetree/bindings/net/micrel-ks8851.txt
Documentation/devicetree/bindings/net/micrel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/opencores-ethoc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/phy.txt
Documentation/devicetree/bindings/net/samsung-sxgbe.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/sh_eth.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/smsc-lan91c111.txt
Documentation/devicetree/bindings/net/smsc911x.txt
Documentation/devicetree/bindings/net/sti-dwmac.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/stmmac.txt
Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt [deleted file]
Documentation/devicetree/bindings/power/bq2415x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/spi/spi_atmel.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/fb/00-INDEX
Documentation/filesystems/00-INDEX
Documentation/filesystems/nfs/00-INDEX
Documentation/i2c/instantiating-devices
Documentation/ide/00-INDEX
Documentation/laptops/00-INDEX
Documentation/leds/00-INDEX
Documentation/m68k/00-INDEX
Documentation/networking/00-INDEX
Documentation/networking/3c505.txt [deleted file]
Documentation/networking/altera_tse.txt [new file with mode: 0644]
Documentation/networking/bonding.txt
Documentation/networking/can.txt
Documentation/networking/filter.txt
Documentation/networking/gianfar.txt
Documentation/networking/igb.txt
Documentation/networking/netlink_mmap.txt
Documentation/networking/packet_mmap.txt
Documentation/networking/phy.txt
Documentation/networking/pktgen.txt
Documentation/networking/rxrpc.txt
Documentation/networking/tcp.txt
Documentation/networking/timestamping.txt
Documentation/phy.txt
Documentation/power/00-INDEX
Documentation/ptp/testptp.c
Documentation/s390/00-INDEX
Documentation/scheduler/00-INDEX
Documentation/scsi/00-INDEX
Documentation/serial/00-INDEX
Documentation/spi/00-INDEX [new file with mode: 0644]
Documentation/spi/spi-summary
Documentation/timers/00-INDEX
Documentation/virtual/kvm/00-INDEX
Documentation/vm/00-INDEX
Documentation/w1/masters/00-INDEX
Documentation/w1/slaves/00-INDEX
Documentation/x86/00-INDEX
Documentation/zh_CN/arm64/booting.txt
Documentation/zh_CN/arm64/memory.txt
Documentation/zh_CN/arm64/tagged-pointers.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/arc/mm/cache_arc700.c
arch/arm/Kconfig
arch/arm/boot/compressed/.gitignore
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am335x-evmsk.dts
arch/arm/boot/dts/armada-xp-mv78260.dtsi
arch/arm/boot/dts/at91-sama5d3_xplained.dts [new file with mode: 0644]
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9n12ek.dts
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/dove.dtsi
arch/arm/boot/dts/imx6dl-hummingboard.dts
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
arch/arm/boot/dts/keystone-clocks.dtsi
arch/arm/boot/dts/omap3-gta04.dts
arch/arm/boot/dts/omap3-igep0020.dts
arch/arm/boot/dts/omap3-igep0030.dts
arch/arm/boot/dts/omap3-n9.dts
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3-n950.dts
arch/arm/boot/dts/omap3-overo-storm-tobi.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-overo-tobi-common.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap3-overo-tobi.dts [new file with mode: 0644]
arch/arm/boot/dts/omap3-overo.dtsi
arch/arm/boot/dts/omap3-tobi.dts [deleted file]
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sama5d36.dtsi
arch/arm/boot/dts/ste-href.dtsi
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a10s.dtsi
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/boot/dts/tegra114.dtsi
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30-cardhu.dtsi
arch/arm/boot/dts/tegra30.dtsi
arch/arm/boot/dts/testcases/tests-interrupts.dtsi [deleted file]
arch/arm/boot/dts/testcases/tests-phandle.dtsi [deleted file]
arch/arm/boot/dts/testcases/tests.dtsi [deleted file]
arch/arm/boot/dts/versatile-pb.dts
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/tegra_defconfig
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/memory.h
arch/arm/include/asm/pgtable-3level.h
arch/arm/include/asm/spinlock.h
arch/arm/kernel/head-common.S
arch/arm/kernel/head.S
arch/arm/kernel/setup.c
arch/arm/kvm/arm.c
arch/arm/kvm/interrupts.S
arch/arm/mach-hisi/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/clk-imx6sl.c
arch/arm/mach-imx/common.h
arch/arm/mach-imx/pm-imx6q.c
arch/arm/mach-moxart/Kconfig
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/dpll3xxx.c
arch/arm/mach-omap2/gpmc.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-pxa/am300epd.c
arch/arm/mach-pxa/include/mach/balloon3.h
arch/arm/mach-pxa/include/mach/corgi.h
arch/arm/mach-pxa/include/mach/csb726.h
arch/arm/mach-pxa/include/mach/gumstix.h
arch/arm/mach-pxa/include/mach/idp.h
arch/arm/mach-pxa/include/mach/palmld.h
arch/arm/mach-pxa/include/mach/palmt5.h
arch/arm/mach-pxa/include/mach/palmtc.h
arch/arm/mach-pxa/include/mach/palmtx.h
arch/arm/mach-pxa/include/mach/pcm027.h
arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
arch/arm/mach-pxa/include/mach/poodle.h
arch/arm/mach-pxa/include/mach/spitz.h
arch/arm/mach-pxa/include/mach/tosa.h
arch/arm/mach-pxa/include/mach/trizeps4.h
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-sa1100/include/mach/collie.h
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/tegra.c
arch/arm/mach-zynq/common.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/dump.c
arch/arm/mm/mm.h
arch/arm/mm/mmu.c
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/net/bpf_jit_32.c
arch/arm64/include/asm/percpu.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/stacktrace.c
arch/arm64/kvm/hyp.S
arch/avr32/Makefile
arch/avr32/boards/mimc200/fram.c
arch/avr32/include/asm/Kbuild
arch/avr32/include/asm/io.h
arch/c6x/include/asm/cache.h
arch/cris/include/asm/bitops.h
arch/ia64/kernel/uncached.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/barrier.h [deleted file]
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/syscalltable.S
arch/microblaze/include/asm/delay.h
arch/microblaze/include/asm/io.h
arch/microblaze/kernel/head.S
arch/mips/Kconfig
arch/mips/alchemy/board-gpr.c
arch/mips/alchemy/board-mtx1.c
arch/mips/bcm47xx/board.c
arch/mips/bcm47xx/nvram.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/include/asm/asmmacro.h
arch/mips/include/asm/fpu.h
arch/mips/include/asm/ftrace.h
arch/mips/include/asm/syscall.h
arch/mips/include/uapi/asm/inst.h
arch/mips/kernel/ftrace.c
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/rtlx-cmp.c
arch/mips/kernel/rtlx-mt.c
arch/mips/math-emu/cp1emu.c
arch/mips/mti-malta/malta-amon.c
arch/mips/mti-malta/malta-int.c
arch/mips/pci/msi-octeon.c
arch/parisc/include/asm/page.h
arch/parisc/include/asm/spinlock.h
arch/parisc/include/uapi/asm/unistd.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/syscall_table.S
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/hugetlb.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/include/asm/sections.h
arch/powerpc/include/asm/vdso.h
arch/powerpc/kernel/crash_dump.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/ftrace.c
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/process.c
arch/powerpc/kernel/reloc_64.S
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/vdso32/vdso32_wrapper.S
arch/powerpc/kernel/vdso64/vdso64_wrapper.S
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/subpage-prot.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power8-pmu.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/opal-xscom.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/powerpc/platforms/powernv/powernv.h
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/eeh_pseries.c
arch/powerpc/platforms/pseries/hotplug-cpu.c
arch/powerpc/platforms/pseries/pci.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/xmon/xmon.c
arch/s390/appldata/appldata_base.c
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/head64.S
arch/s390/mm/page-states.c
arch/s390/net/bpf_jit_comp.c
arch/s390/pci/pci_dma.c
arch/sh/include/cpu-sh2/cpu/cache.h
arch/sh/include/cpu-sh2a/cpu/cache.h
arch/sh/include/cpu-sh3/cpu/cache.h
arch/sh/include/cpu-sh4/cpu/cache.h
arch/sh/kernel/cpu/init.c
arch/sh/mm/cache-debugfs.c
arch/sh/mm/cache-sh2.c
arch/sh/mm/cache-sh2a.c
arch/sh/mm/cache-sh4.c
arch/sh/mm/cache-shx3.c
arch/sh/mm/cache.c
arch/sparc/Kconfig
arch/sparc/kernel/process_64.c
arch/sparc/kernel/syscalls.S
arch/sparc/mm/srmmu.c
arch/sparc/mm/tsb.c
arch/sparc/net/bpf_jit_comp.c
arch/um/drivers/net_kern.c
arch/x86/Kconfig.cpu
arch/x86/boot/compressed/aslr.c
arch/x86/include/asm/barrier.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/io.h
arch/x86/include/asm/spinlock.h
arch/x86/include/asm/topology.h
arch/x86/include/asm/tsc.h
arch/x86/kernel/aperture_64.c
arch/x86/kernel/cpu/centaur.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_p6.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/i387.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/quirks.c
arch/x86/kernel/setup.c
arch/x86/kernel/tsc.c
arch/x86/kernel/tsc_msr.c
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mm/fault.c
arch/x86/net/bpf_jit.S
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi-bgrt.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/efi_32.c
arch/x86/platform/efi/efi_64.c
arch/x86/um/asm/barrier.h
arch/xtensa/Kconfig
arch/xtensa/boot/dts/xtfpga.dtsi
arch/xtensa/include/asm/io.h
arch/xtensa/include/asm/traps.h
arch/xtensa/include/asm/vectors.h
arch/xtensa/include/uapi/asm/unistd.h
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/vectors.S
arch/xtensa/kernel/xtensa_ksyms.c
arch/xtensa/mm/init.c
arch/xtensa/mm/mmu.c
arch/xtensa/platforms/xtfpga/setup.c
arch/xtensa/variants/fsf/include/variant/tie.h
block/blk-cgroup.h
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-lib.c
block/blk-merge.c
block/blk-mq-cpu.c
block/blk-mq-tag.c
block/blk-mq.c
block/blk-mq.h
block/blk-sysfs.c
block/blk-timeout.c
block/blk.h
drivers/acpi/ac.c
drivers/acpi/battery.c
drivers/acpi/blacklist.c
drivers/acpi/button.c
drivers/acpi/container.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/fan.c
drivers/acpi/pci_irq.c
drivers/acpi/processor_throttling.c
drivers/acpi/resource.c
drivers/acpi/sbs.c
drivers/acpi/sleep.c
drivers/acpi/thermal.c
drivers/acpi/video.c
drivers/acpi/video_detect.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/libata-core.c
drivers/ata/libata-pmp.c
drivers/ata/pata_imx.c
drivers/ata/sata_mv.c
drivers/ata/sata_sil.c
drivers/atm/ambassador.c
drivers/atm/firestream.c
drivers/atm/idt77105.c
drivers/atm/nicstar.c
drivers/atm/solos-pci.c
drivers/base/component.c
drivers/base/dma-buf.c
drivers/base/firmware_class.c
drivers/block/aoe/aoecmd.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/null_blk.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/block/zram/zram_drv.c
drivers/char/Kconfig
drivers/char/raw.c
drivers/clk/at91/clk-master.c
drivers/clk/clk-nomadik.c
drivers/clk/clk.c
drivers/clk/keystone/gate.c
drivers/clk/mvebu/armada-370.c
drivers/clk/mvebu/armada-xp.c
drivers/clk/mvebu/dove.c
drivers/clk/mvebu/kirkwood.c
drivers/clk/shmobile/clk-rcar-gen2.c
drivers/clk/tegra/clk-divider.c
drivers/clk/tegra/clk-id.h
drivers/clk/tegra/clk-tegra-periph.c
drivers/clk/tegra/clk-tegra-super-gen4.c
drivers/clk/tegra/clk-tegra114.c
drivers/clk/tegra/clk-tegra124.c
drivers/clk/tegra/clk-tegra20.c
drivers/clocksource/bcm_kona_timer.c
drivers/clocksource/vf_pit_timer.c
drivers/connector/connector.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/intel_pstate.c
drivers/cpufreq/powernow-k8.c
drivers/crypto/nx/nx-842.c
drivers/dma/Kconfig
drivers/dma/imx-sdma.c
drivers/dma/ioat/dma.c
drivers/dma/ioat/dma.h
drivers/dma/ioat/dma_v2.c
drivers/dma/ioat/dma_v3.c
drivers/dma/mv_xor.c
drivers/dma/ste_dma40.c
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_module.h
drivers/edac/i7300_edac.c
drivers/edac/i7core_edac.c
drivers/extcon/extcon-arizona.c
drivers/firewire/core-device.c
drivers/firewire/net.c
drivers/firewire/ohci.c
drivers/firewire/sbp2.c
drivers/fmc/fmc-write-eeprom.c
drivers/gpio/Kconfig
drivers/gpio/gpio-bcm-kona.c
drivers/gpio/gpio-clps711x.c
drivers/gpio/gpio-intel-mid.c
drivers/gpio/gpio-xtensa.c
drivers/gpu/drm/armada/armada_drv.c
drivers/gpu/drm/bochs/Kconfig
drivers/gpu/drm/drm_ioctl.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.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_hdmi.c
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/engine/device/nv40.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
drivers/gpu/drm/nouveau/core/include/subdev/mc.h
drivers/gpu/drm/nouveau/core/subdev/bios/base.c
drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_vga.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/btcd.h
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreen_smc.h
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_audio.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atpx_handler.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_semaphore.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/uvd_v2_2.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/rgb.c
drivers/gpu/drm/ttm/ttm_agp_backend.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/vmwgfx/svga3d_reg.h
drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h
drivers/gpu/drm/vmwgfx/svga_reg.h
drivers/gpu/drm/vmwgfx/vmwgfx_context.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/gpu/host1x/job.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-hyperv.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-microsoft.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/hidraw.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hv/connection.c
drivers/hwmon/max1668.c
drivers/hwmon/ntc_thermistor.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/iio/accel/bma180.c
drivers/iio/adc/max1363.c
drivers/iio/gyro/Kconfig
drivers/iio/gyro/st_gyro.h
drivers/iio/gyro/st_gyro_core.c
drivers/iio/gyro/st_gyro_i2c.c
drivers/iio/gyro/st_gyro_spi.c
drivers/iio/imu/adis16400.h
drivers/iio/imu/adis16400_core.c
drivers/iio/light/cm32181.c
drivers/iio/light/cm36651.c
drivers/iio/light/tsl2563.c
drivers/iio/magnetometer/ak8975.c
drivers/iio/magnetometer/mag3110.c
drivers/infiniband/hw/amso1100/c2.c
drivers/infiniband/hw/amso1100/c2_rnic.c
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/device.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/infiniband/hw/cxgb4/provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/cxgb4/t4.h
drivers/infiniband/hw/cxgb4/user.h
drivers/infiniband/hw/mlx4/alias_GUID.c
drivers/infiniband/hw/mlx4/cm.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/mcg.c
drivers/infiniband/hw/mlx4/mlx4_ib.h
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/mlx4/sysfs.c
drivers/infiniband/hw/mlx5/Kconfig
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/mlx5/user.h
drivers/infiniband/hw/nes/nes.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c
drivers/infiniband/ulp/iser/iser_initiator.c
drivers/infiniband/ulp/iser/iser_verbs.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/keyboard/adp5588-keys.c
drivers/input/misc/arizona-haptics.c
drivers/input/misc/da9052_onkey.c
drivers/input/mouse/cypress_ps2.c
drivers/input/mouse/synaptics.c
drivers/iommu/arm-smmu.c
drivers/iommu/omap-iommu-debug.c
drivers/irqchip/irq-metag-ext.c
drivers/irqchip/irq-metag.c
drivers/irqchip/irq-orion.c
drivers/isdn/act2000/module.c
drivers/isdn/capi/Kconfig
drivers/isdn/divert/divert_procfs.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/elsa_ser.c
drivers/isdn/hisax/q931.c
drivers/isdn/hysdn/hysdn_proclog.c
drivers/isdn/i4l/isdn_common.c
drivers/isdn/i4l/isdn_ppp.c
drivers/isdn/pcbit/drv.c
drivers/isdn/sc/init.c
drivers/md/Kconfig
drivers/md/bcache/bcache.h
drivers/md/bcache/bset.c
drivers/md/bcache/btree.c
drivers/md/bcache/extents.c
drivers/md/bcache/request.c
drivers/md/bcache/sysfs.c
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-target.c
drivers/md/dm-io.c
drivers/md/dm-mpath.c
drivers/md/dm-raid1.c
drivers/md/dm-snap-persistent.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin-metadata.h
drivers/md/dm-thin.c
drivers/md/persistent-data/Kconfig
drivers/md/persistent-data/dm-space-map-metadata.c
drivers/md/persistent-data/dm-space-map-metadata.h
drivers/md/raid1.c
drivers/md/raid5.c
drivers/message/i2o/i2o_config.c
drivers/mfd/da9055-i2c.c
drivers/mfd/max14577.c
drivers/mfd/max8997.c
drivers/mfd/max8998.c
drivers/mfd/sec-core.c
drivers/mfd/tps65217.c
drivers/mfd/wm8994-core.c
drivers/misc/genwqe/card_dev.c
drivers/misc/mei/client.c
drivers/misc/mic/host/mic_virtio.c
drivers/misc/sgi-gru/grukdump.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/mmc/card/queue.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/omap2.c
drivers/mtd/ubi/fastmap.c
drivers/net/Kconfig
drivers/net/bonding/bond_3ad.c
drivers/net/bonding/bond_3ad.h
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_debugfs.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_netlink.c
drivers/net/bonding/bond_options.c
drivers/net/bonding/bond_options.h
drivers/net/bonding/bond_procfs.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/caif/caif_serial.c
drivers/net/caif/caif_spi.c
drivers/net/can/Kconfig
drivers/net/can/at91_can.c
drivers/net/can/bfin_can.c
drivers/net/can/c_can/c_can.c
drivers/net/can/cc770/cc770.c
drivers/net/can/dev.c
drivers/net/can/flexcan.c
drivers/net/can/grcan.c
drivers/net/can/janz-ican3.c
drivers/net/can/mcp251x.c
drivers/net/can/mscan/mscan.c
drivers/net/can/pch_can.c
drivers/net/can/sja1000/Kconfig
drivers/net/can/sja1000/Makefile
drivers/net/can/sja1000/ems_pci.c
drivers/net/can/sja1000/ems_pcmcia.c
drivers/net/can/sja1000/kvaser_pci.c
drivers/net/can/sja1000/peak_pci.c
drivers/net/can/sja1000/peak_pcmcia.c
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/sja1000/sja1000_of_platform.c [deleted file]
drivers/net/can/sja1000/sja1000_platform.c
drivers/net/can/slcan.c
drivers/net/can/softing/softing_main.c
drivers/net/can/ti_hecc.c
drivers/net/can/usb/ems_usb.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/can/usb/peak_usb/pcan_usb_core.c
drivers/net/can/usb/usb_8dev.c
drivers/net/can/vcan.c
drivers/net/dummy.c
drivers/net/ethernet/3com/3c509.c
drivers/net/ethernet/3com/3c589_cs.c
drivers/net/ethernet/3com/3c59x.c
drivers/net/ethernet/8390/lib8390.c
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/adi/bfin_mac.c
drivers/net/ethernet/aeroflex/greth.c
drivers/net/ethernet/allwinner/sun4i-emac.c
drivers/net/ethernet/altera/Kconfig [new file with mode: 0644]
drivers/net/ethernet/altera/Makefile [new file with mode: 0644]
drivers/net/ethernet/altera/altera_msgdma.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_msgdma.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_msgdmahw.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_sgdma.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_sgdma.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_sgdmahw.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_tse.h [new file with mode: 0644]
drivers/net/ethernet/altera/altera_tse_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_tse_main.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_utils.c [new file with mode: 0644]
drivers/net/ethernet/altera/altera_utils.h [new file with mode: 0644]
drivers/net/ethernet/amd/7990.c
drivers/net/ethernet/amd/am79c961a.c
drivers/net/ethernet/amd/amd8111e.c
drivers/net/ethernet/amd/pcnet32.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/atheros/atlx/atl1.c
drivers/net/ethernet/atheros/atlx/atl2.c
drivers/net/ethernet/broadcom/Kconfig
drivers/net/ethernet/broadcom/Makefile
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/broadcom/bnx2.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x.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_fw_defs.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/cnic.h
drivers/net/ethernet/broadcom/cnic_defs.h
drivers/net/ethernet/broadcom/cnic_if.h
drivers/net/ethernet/broadcom/genet/Makefile [new file with mode: 0644]
drivers/net/ethernet/broadcom/genet/bcmgenet.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/genet/bcmgenet.h [new file with mode: 0644]
drivers/net/ethernet/broadcom/genet/bcmmii.c [new file with mode: 0644]
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/brocade/bna/bfa_ioc.c
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/calxeda/xgmac.c
drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c
drivers/net/ethernet/chelsio/cxgb3/sge.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
drivers/net/ethernet/chelsio/cxgb4/sge.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/sge.c
drivers/net/ethernet/cirrus/cs89x0.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/dec/tulip/dmfe.c
drivers/net/ethernet/dec/tulip/tulip_core.c
drivers/net/ethernet/dec/tulip/uli526x.c
drivers/net/ethernet/dlink/sundance.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c
drivers/net/ethernet/emulex/benet/be_hw.h
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/emulex/benet/be_roce.c
drivers/net/ethernet/emulex/benet/be_roce.h
drivers/net/ethernet/ethoc.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/freescale/Makefile
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
drivers/net/ethernet/freescale/fs_enet/mii-fec.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/freescale/gianfar.h
drivers/net/ethernet/freescale/gianfar_ethtool.c
drivers/net/ethernet/freescale/gianfar_ptp.c
drivers/net/ethernet/freescale/gianfar_sysfs.c [deleted file]
drivers/net/ethernet/freescale/ucc_geth.c
drivers/net/ethernet/i825xx/lib82596.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/ibm/ibmveth.h
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/e1000e/80003es2lan.c
drivers/net/ethernet/intel/e1000e/80003es2lan.h
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/82571.h
drivers/net/ethernet/intel/e1000e/Makefile
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/mac.c
drivers/net/ethernet/intel/e1000e/mac.h
drivers/net/ethernet/intel/e1000e/manage.c
drivers/net/ethernet/intel/e1000e/manage.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/e1000e/nvm.c
drivers/net/ethernet/intel/e1000e/nvm.h
drivers/net/ethernet/intel/e1000e/param.c
drivers/net/ethernet/intel/e1000e/phy.c
drivers/net/ethernet/intel/e1000e/phy.h
drivers/net/ethernet/intel/e1000e/ptp.c
drivers/net/ethernet/intel/e1000e/regs.h
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_adminq.c
drivers/net/ethernet/intel/i40e/i40e_common.c
drivers/net/ethernet/intel/i40e/i40e_dcb.c
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_ethtool.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/i40e/i40e_prototype.h
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
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_type.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/Makefile
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_i210.c
drivers/net/ethernet/intel/igb/e1000_i210.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/e1000_mbx.h
drivers/net/ethernet/intel/igb/e1000_nvm.c
drivers/net/ethernet/intel/igb/e1000_nvm.h
drivers/net/ethernet/intel/igb/e1000_phy.c
drivers/net/ethernet/intel/igb/e1000_phy.h
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_hwmon.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/igbvf/netdev.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c
drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.c
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h
drivers/net/ethernet/intel/ixgbe/ixgbe_debugfs.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c
drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c
drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.h
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h
drivers/net/ethernet/intel/ixgbe/ixgbe_sysfs.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
drivers/net/ethernet/intel/ixgbevf/ethtool.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/intel/ixgbevf/regs.h
drivers/net/ethernet/intel/ixgbevf/vf.h
drivers/net/ethernet/jme.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/Kconfig
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/marvell/mvmdio.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/mellanox/mlx4/Kconfig
drivers/net/ethernet/mellanox/mlx4/cmd.c
drivers/net/ethernet/mellanox/mlx4/en_clock.c
drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.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_rx.c
drivers/net/ethernet/mellanox/mlx4/en_selftest.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mcg.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/port.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/micrel/ks8851.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/neterion/vxge/vxge-main.c
drivers/net/ethernet/nvidia/forcedeth.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/qlogic/qlge/qlge_main.c
drivers/net/ethernet/rdc/r6040.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/samsung/Kconfig [new file with mode: 0644]
drivers/net/ethernet/samsung/Makefile [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/Kconfig [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/Makefile [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c [new file with mode: 0644]
drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h [new file with mode: 0644]
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef10_regs.h
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/falcon.c
drivers/net/ethernet/sfc/farch.c
drivers/net/ethernet/sfc/filter.h
drivers/net/ethernet/sfc/mcdi.c
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/net_driver.h
drivers/net/ethernet/sfc/nic.c
drivers/net/ethernet/sfc/ptp.c
drivers/net/ethernet/sfc/selftest.c
drivers/net/ethernet/sfc/siena_sriov.c
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/silan/sc92031.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/smsc/smc91x.c
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/Makefile
drivers/net/ethernet/stmicro/stmmac/chain_mode.c
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
drivers/net/ethernet/sun/niu.c
drivers/net/ethernet/sun/sungem.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpts.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/tile/tilegx.c
drivers/net/ethernet/tile/tilepro.c
drivers/net/ethernet/toshiba/spider_net.c
drivers/net/ethernet/toshiba/tc35815.c
drivers/net/ethernet/via/via-rhine.c
drivers/net/ethernet/via/via-velocity.c
drivers/net/ethernet/wiznet/w5100.c
drivers/net/ethernet/wiznet/w5300.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/hamradio/yam.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/ieee802154/Kconfig
drivers/net/ieee802154/at86rf230.c
drivers/net/ieee802154/fakehard.c
drivers/net/ieee802154/mrf24j40.c
drivers/net/ifb.c
drivers/net/irda/Kconfig
drivers/net/irda/Makefile
drivers/net/irda/ep7211-sir.c [deleted file]
drivers/net/irda/irtty-sir.c
drivers/net/loopback.c
drivers/net/macvlan.c
drivers/net/nlmon.c
drivers/net/phy/Kconfig
drivers/net/phy/Makefile
drivers/net/phy/at803x.c
drivers/net/phy/bcm7xxx.c [new file with mode: 0644]
drivers/net/phy/broadcom.c
drivers/net/phy/dp83640.c
drivers/net/phy/mdio-sun4i.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/ppp/ppp_generic.c
drivers/net/team/team.c
drivers/net/team/team_mode_loadbalance.c
drivers/net/tun.c
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/asix_devices.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/gl620a.c
drivers/net/usb/hso.c
drivers/net/usb/lg-vl600.c
drivers/net/usb/mcs7830.c
drivers/net/usb/net1080.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c [deleted file]
drivers/net/usb/rndis_host.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/sr9800.c [new file with mode: 0644]
drivers/net/usb/sr9800.h [new file with mode: 0644]
drivers/net/usb/usbnet.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vxlan.c
drivers/net/wan/dlci.c
drivers/net/wimax/i2400m/netdev.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wil6210/pcie_bus.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/mwifiex/11ac.c
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netfront.c
drivers/of/address.c
drivers/of/base.c
drivers/of/of_mdio.c
drivers/of/of_net.c
drivers/of/selftest.c
drivers/of/testcase-data/testcases.dtsi [new file with mode: 0644]
drivers/of/testcase-data/tests-interrupts.dtsi [new file with mode: 0644]
drivers/of/testcase-data/tests-match.dtsi [new file with mode: 0644]
drivers/of/testcase-data/tests-phandle.dtsi [new file with mode: 0644]
drivers/pci/bus.c
drivers/pci/host/pci-mvebu.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/msi.c
drivers/pci/pci.c
drivers/phy/Kconfig
drivers/phy/phy-core.c
drivers/phy/phy-exynos-dp-video.c
drivers/phy/phy-exynos-mipi-video.c
drivers/phy/phy-mvebu-sata.c
drivers/phy/phy-omap-usb2.c
drivers/phy/phy-twl4030-usb.c
drivers/pinctrl/Kconfig
drivers/pinctrl/pinctrl-capri.c
drivers/pinctrl/pinctrl-sunxi.c
drivers/pinctrl/pinctrl-sunxi.h
drivers/pinctrl/sh-pfc/pfc-r8a7791.c
drivers/pinctrl/sirf/pinctrl-sirf.c
drivers/pnp/pnpacpi/rsparser.c
drivers/power/ds2782_battery.c
drivers/power/isp1704_charger.c
drivers/power/max17040_battery.c
drivers/ptp/ptp_chardev.c
drivers/ptp/ptp_clock.c
drivers/ptp/ptp_ixp46x.c
drivers/ptp/ptp_pch.c
drivers/ptp/ptp_private.h
drivers/ptp/ptp_sysfs.c
drivers/pwm/pwm-lp3943.c
drivers/rapidio/devices/tsi721.h
drivers/rapidio/devices/tsi721_dma.c
drivers/regulator/core.c
drivers/regulator/da9055-regulator.c
drivers/regulator/da9063-regulator.c
drivers/regulator/max14577.c
drivers/regulator/s5m8767.c
drivers/rtc/rtc-s3c.c
drivers/s390/cio/chsc.c
drivers/s390/cio/cio.c
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_main.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/sbus/char/jsflash.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/bnx2fc/bnx2fc_tgt.c
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/bnx2i/bnx2i_iscsi.c
drivers/scsi/isci/host.h
drivers/scsi/isci/port_config.c
drivers/scsi/isci/task.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.h
drivers/scsi/scsi_lib.c
drivers/scsi/storvsc_drv.c
drivers/spi/Kconfig
drivers/spi/spi-ath79.c
drivers/spi/spi-atmel.c
drivers/spi/spi-coldfire-qspi.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-imx.c
drivers/spi/spi-nuc900.c
drivers/spi/spi-topcliff-pch.c
drivers/spi/spi.c
drivers/staging/android/ashmem.c
drivers/staging/android/binder.c
drivers/staging/android/ion/compat_ion.c
drivers/staging/android/ion/ion_dummy_driver.c
drivers/staging/android/ion/ion_heap.c
drivers/staging/android/ion/ion_priv.h
drivers/staging/android/ion/ion_system_heap.c
drivers/staging/android/sw_sync.h
drivers/staging/android/sync.c
drivers/staging/bcm/Bcmnet.c
drivers/staging/comedi/drivers.c
drivers/staging/comedi/drivers/adv_pci1710.c
drivers/staging/comedi/drivers/usbduxsigma.c
drivers/staging/cxt1e1/linux.c
drivers/staging/dgrp/dgrp_net_ops.c
drivers/staging/gdm72xx/gdm_usb.c
drivers/staging/iio/Documentation/iio_utils.h
drivers/staging/iio/adc/ad799x_core.c
drivers/staging/iio/adc/mxs-lradc.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/imx-drm/imx-drm-core.c
drivers/staging/imx-drm/imx-hdmi.c
drivers/staging/lustre/TODO
drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h
drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
drivers/staging/lustre/lustre/include/lustre/lustre_user.h
drivers/staging/lustre/lustre/llite/dir.c
drivers/staging/lustre/lustre/mdc/mdc_request.c
drivers/staging/netlogic/xlr_net.c
drivers/staging/octeon-usb/octeon-hcd.c
drivers/staging/octeon/ethernet-tx.c
drivers/staging/ozwpan/ozproto.c
drivers/staging/rtl8188eu/core/rtw_wlan_util.c
drivers/staging/rtl8188eu/os_dep/ioctl_linux.c
drivers/staging/rtl8188eu/os_dep/os_intfs.c
drivers/staging/rtl8188eu/os_dep/usb_intf.c
drivers/staging/rtl8821ae/Kconfig
drivers/staging/rtl8821ae/wifi.h
drivers/staging/usbip/userspace/libsrc/names.c
drivers/staging/usbip/vhci_sysfs.c
drivers/staging/wlags49_h2/wl_netdev.c
drivers/staging/wlags49_h2/wl_wext.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/target_core_alua.c
drivers/target/target_core_pr.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_transport.c
drivers/thermal/Kconfig
drivers/thermal/thermal_core.c
drivers/thermal/x86_pkg_temp_thermal.c
drivers/tty/hvc/hvc_opal.c
drivers/tty/hvc/hvc_rtas.c
drivers/tty/hvc/hvc_udbg.c
drivers/tty/hvc/hvc_xen.c
drivers/tty/n_gsm.c
drivers/tty/n_tty.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/sirfsoc_uart.c
drivers/tty/serial/sunhv.c
drivers/tty/serial/sunsab.c
drivers/tty/serial/sunsu.c
drivers/tty/serial/sunzilog.c
drivers/tty/vt/vt.c
drivers/usb/chipidea/udc.c
drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/core/usb.h
drivers/usb/dwc2/core.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/platform.c
drivers/usb/gadget/bcm63xx_udc.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/phy/phy-msm-usb.c
drivers/usb/phy/phy.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/usb-serial-simple.c
drivers/usb/storage/Kconfig
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_cypress.h
drivers/usb/storage/unusual_devs.h
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/video/Kconfig
drivers/video/exynos/Kconfig
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/sdi.c
drivers/vme/bridges/vme_ca91cx42.c
drivers/vme/bridges/vme_tsi148.c
drivers/watchdog/w83697hf_wdt.c
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/events/events_base.c
drivers/xen/xencomm.c [deleted file]
fs/anon_inodes.c
fs/bio-integrity.c
fs/bio.c
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/ceph/acl.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/cifsacl.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/smb1ops.c
fs/cifs/smb2glob.h
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2proto.h
fs/cifs/transport.c
fs/cifs/xattr.c
fs/dcache.c
fs/ext4/ext4.h
fs/ext4/extents.c
fs/ext4/ioctl.c
fs/ext4/resize.c
fs/ext4/super.c
fs/file.c
fs/file_table.c
fs/fs-writeback.c
fs/fscache/object-list.c
fs/fscache/object.c
fs/hfsplus/catalog.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/options.c
fs/jbd2/transaction.c
fs/jfs/acl.c
fs/kernfs/mount.c
fs/lockd/svclock.c
fs/namei.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs4client.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfsd/nfs4acl.c
fs/nfsd/vfs.c
fs/notify/dnotify/dnotify.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify_user.c
fs/notify/fsnotify.c
fs/notify/group.c
fs/notify/inotify/inotify.h
fs/notify/inotify/inotify_fsnotify.c
fs/notify/inotify/inotify_user.c
fs/notify/notification.c
fs/ocfs2/alloc.c
fs/ocfs2/file.c
fs/ocfs2/namei.c
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/stackglue.c
fs/open.c
fs/proc/base.c
fs/proc/page.c
fs/proc/vmcore.c
fs/quota/dquot.c
fs/read_write.c
fs/reiserfs/do_balan.c
fs/sync.c
fs/sysfs/mount.c
fs/udf/file.c
fs/udf/inode.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_sb.c
fs/xfs/xfs_super.c
include/asm-generic/pgtable.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/ttm/ttm_page_alloc.h
include/dt-bindings/clock/tegra124-car.h
include/kvm/arm_vgic.h
include/linux/audit.h
include/linux/bio.h
include/linux/blk-mq.h
include/linux/blkdev.h
include/linux/brcmphy.h
include/linux/can/dev.h
include/linux/can/skb.h
include/linux/ceph/ceph_fs.h
include/linux/cgroup.h
include/linux/clk/ti.h
include/linux/compiler-gcc4.h
include/linux/dma-buf.h
include/linux/ethtool.h
include/linux/file.h
include/linux/filter.h
include/linux/firewire.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/ftrace_event.h
include/linux/gfp.h
include/linux/gpio/consumer.h
include/linux/huge_mm.h
include/linux/hyperv.h
include/linux/if_vlan.h
include/linux/interrupt.h
include/linux/ipc_namespace.h
include/linux/isdn_ppp.h
include/linux/kernfs.h
include/linux/mfd/max8997-private.h
include/linux/mfd/max8998-private.h
include/linux/mfd/tps65217.h
include/linux/mlx4/cmd.h
include/linux/mlx4/device.h
include/linux/mlx4/driver.h
include/linux/mlx4/qp.h
include/linux/mlx5/driver.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/mpls.h [new file with mode: 0644]
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/netfilter/ipset/ip_set.h
include/linux/netfilter/nfnetlink.h
include/linux/netpoll.h
include/linux/nfs_xdr.h
include/linux/nl802154.h
include/linux/of.h
include/linux/of_device.h
include/linux/pci.h
include/linux/phy.h
include/linux/phy/phy.h
include/linux/ptp_classify.h
include/linux/ptp_clock_kernel.h
include/linux/rmap.h
include/linux/seccomp.h
include/linux/security.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/smp.h
include/linux/spi/spi.h
include/linux/sxgbe_platform.h [new file with mode: 0644]
include/linux/syscalls.h
include/linux/tcp.h
include/linux/tracepoint.h
include/linux/u64_stats_sync.h
include/linux/usb.h
include/linux/usb/cdc_ncm.h
include/linux/usb/usbnet.h
include/linux/workqueue.h
include/linux/writeback.h
include/net/6lowpan.h [new file with mode: 0644]
include/net/act_api.h
include/net/addrconf.h
include/net/af_ieee802154.h
include/net/checksum.h
include/net/datalink.h
include/net/dn.h
include/net/dn_route.h
include/net/dst.h
include/net/ethoc.h
include/net/flow.h
include/net/flowcache.h [new file with mode: 0644]
include/net/ieee802154.h
include/net/ieee802154_netdev.h
include/net/if_inet6.h
include/net/ip.h
include/net/ip6_fib.h
include/net/ip6_route.h
include/net/ip_tunnels.h
include/net/ipx.h
include/net/mac802154.h
include/net/net_namespace.h
include/net/netfilter/nf_conntrack.h
include/net/netfilter/nf_conntrack_core.h
include/net/netfilter/nf_conntrack_labels.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nft_reject.h [new file with mode: 0644]
include/net/netns/conntrack.h
include/net/netns/ieee802154_6lowpan.h [new file with mode: 0644]
include/net/netns/xfrm.h
include/net/nl802154.h
include/net/route.h
include/net/rtnetlink.h
include/net/sctp/structs.h
include/net/sock.h
include/net/tc_act/tc_csum.h
include/net/tc_act/tc_defact.h
include/net/tc_act/tc_gact.h
include/net/tc_act/tc_ipt.h
include/net/tc_act/tc_mirred.h
include/net/tc_act/tc_nat.h
include/net/tc_act/tc_pedit.h
include/net/tc_act/tc_skbedit.h
include/net/tcp.h
include/net/wpan-phy.h
include/net/xfrm.h
include/rdma/ib_verbs.h
include/sound/soc-dapm.h
include/target/iscsi/iscsi_transport.h
include/target/target_core_base.h
include/trace/events/net.h
include/trace/events/power.h
include/trace/events/sunrpc.h
include/trace/events/writeback.h
include/trace/ftrace.h
include/uapi/asm-generic/unistd.h
include/uapi/drm/drm.h
include/uapi/drm/vmwgfx_drm.h
include/uapi/linux/btrfs.h
include/uapi/linux/can.h
include/uapi/linux/can/netlink.h
include/uapi/linux/ethtool.h
include/uapi/linux/if.h
include/uapi/linux/if_ether.h
include/uapi/linux/in.h
include/uapi/linux/in6.h
include/uapi/linux/mic_ioctl.h
include/uapi/linux/mpls.h [new file with mode: 0644]
include/uapi/linux/netfilter/ipset/ip_set.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/pfkeyv2.h
include/uapi/linux/ptp_clock.h
include/uapi/linux/snmp.h
include/uapi/linux/tcp.h
include/uapi/linux/tcp_metrics.h
include/uapi/linux/usb/cdc.h
include/uapi/linux/xfrm.h
include/uapi/xen/Kbuild
include/uapi/xen/gntalloc.h [new file with mode: 0644]
include/uapi/xen/gntdev.h [new file with mode: 0644]
include/xen/gntalloc.h [deleted file]
include/xen/gntdev.h [deleted file]
include/xen/interface/io/blkif.h
include/xen/interface/xencomm.h [deleted file]
include/xen/xencomm.h [deleted file]
init/main.c
ipc/mq_sysctl.c
ipc/mqueue.c
ipc/msg.c
kernel/audit.c
kernel/audit.h
kernel/audit_tree.c
kernel/audit_watch.c
kernel/auditfilter.c
kernel/cgroup.c
kernel/cpuset.c
kernel/events/core.c
kernel/futex.c
kernel/irq/devres.c
kernel/irq/irqdesc.c
kernel/irq/irqdomain.c
kernel/irq/manage.c
kernel/power/console.c
kernel/printk/printk.c
kernel/profile.c
kernel/sched/clock.c
kernel/sched/core.c
kernel/sched/cpudeadline.c
kernel/sched/deadline.c
kernel/sched/fair.c
kernel/sched/rt.c
kernel/sched/sched.h
kernel/seccomp.c
kernel/stop_machine.c
kernel/time/jiffies.c
kernel/time/sched_clock.c
kernel/time/tick-broadcast.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_export.c
kernel/tracepoint.c
kernel/user_namespace.c
kernel/workqueue.c
lib/dma-debug.c
lib/fonts/Kconfig
lib/percpu_ida.c
lib/radix-tree.c
lib/random32.c
mm/Kconfig
mm/compaction.c
mm/fremap.c
mm/huge_memory.c
mm/ksm.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/migrate.c
mm/mprotect.c
mm/page_alloc.c
mm/rmap.c
mm/slub.c
mm/swap.c
mm/vmpressure.c
net/8021q/vlan.c
net/8021q/vlan.h
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/8021q/vlan_netlink.c
net/9p/client.c
net/9p/trans_virtio.c
net/appletalk/aarp.c
net/appletalk/ddp.c
net/atm/mpc.c
net/batman-adv/Kconfig
net/batman-adv/Makefile
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/distributed-arp-table.h
net/batman-adv/fragmentation.c
net/batman-adv/gateway_client.c
net/batman-adv/hard-interface.c
net/batman-adv/icmp_socket.c
net/batman-adv/main.c
net/batman-adv/main.h
net/batman-adv/multicast.c [new file with mode: 0644]
net/batman-adv/multicast.h [new file with mode: 0644]
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/sysfs.c
net/batman-adv/translation-table.c
net/batman-adv/translation-table.h
net/batman-adv/types.h
net/bluetooth/6lowpan.c
net/bluetooth/hidp/core.c
net/bluetooth/hidp/hidp.h
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_if.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_netfilter.c
net/bridge/br_private.h
net/bridge/br_stp_if.c
net/bridge/br_vlan.c
net/bridge/netfilter/ebt_among.c
net/bridge/netfilter/ebt_dnat.c
net/bridge/netfilter/ebt_redirect.c
net/bridge/netfilter/ebt_snat.c
net/caif/caif_dev.c
net/caif/cfsrvl.c
net/can/af_can.c
net/can/bcm.c
net/can/raw.c
net/ceph/osd_client.c
net/core/dev.c
net/core/fib_rules.c
net/core/filter.c
net/core/flow.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/netpoll.c
net/core/pktgen.c
net/core/request_sock.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sock_diag.c
net/core/timestamping.c
net/dccp/ccids/lib/tfrc.c
net/dccp/ccids/lib/tfrc.h
net/decnet/af_decnet.c
net/hsr/hsr_device.c
net/hsr/hsr_framereg.c
net/hsr/hsr_main.c
net/ieee802154/6lowpan.c [deleted file]
net/ieee802154/6lowpan.h [deleted file]
net/ieee802154/6lowpan_iphc.c
net/ieee802154/6lowpan_rtnl.c [new file with mode: 0644]
net/ieee802154/Kconfig
net/ieee802154/Makefile
net/ieee802154/af802154.h
net/ieee802154/af_ieee802154.c
net/ieee802154/dgram.c
net/ieee802154/header_ops.c [new file with mode: 0644]
net/ieee802154/ieee802154.h
net/ieee802154/netlink.c
net/ieee802154/nl-mac.c
net/ieee802154/nl-phy.c
net/ieee802154/nl_policy.c
net/ieee802154/raw.c
net/ieee802154/reassembly.c [new file with mode: 0644]
net/ieee802154/reassembly.h [new file with mode: 0644]
net/ieee802154/wpan-class.c
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/ah4.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_frontend.c
net/ipv4/gre_demux.c
net/ipv4/inet_fragment.c
net/ipv4/ip_forward.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_tunnel_core.c
net/ipv4/ip_vti.c
net/ipv4/ipcomp.c
net/ipv4/ipconfig.c
net/ipv4/ipmr.c
net/ipv4/netfilter.c
net/ipv4/netfilter/Kconfig
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/netfilter/nf_nat_snmp_basic.c
net/ipv4/netfilter/nft_reject_ipv4.c [new file with mode: 0644]
net/ipv4/ping.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_highspeed.c
net/ipv4/tcp_hybla.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_lp.c
net/ipv4/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_probe.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_timer.c
net/ipv4/tcp_vegas.c
net/ipv4/tcp_veno.c
net/ipv4/tcp_westwood.c
net/ipv4/tcp_yeah.c
net/ipv4/udp.c
net/ipv4/udp_offload.c
net/ipv4/xfrm4_input.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv4/xfrm4_policy.c
net/ipv4/xfrm4_protocol.c [new file with mode: 0644]
net/ipv6/Kconfig
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/addrlabel.c
net/ipv6/ah6.c
net/ipv6/esp6.c
net/ipv6/exthdrs_core.c
net/ipv6/exthdrs_offload.c
net/ipv6/icmp.c
net/ipv6/ip6_checksum.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_flowlabel.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_offload.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ip6mr.c
net/ipv6/ipcomp6.c
net/ipv6/ipv6_sockglue.c
net/ipv6/netfilter/Kconfig
net/ipv6/netfilter/Makefile
net/ipv6/netfilter/nft_reject_ipv6.c [new file with mode: 0644]
net/ipv6/output_core.c
net/ipv6/ping.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp_offload.c
net/ipv6/xfrm6_mode_tunnel.c
net/ipv6/xfrm6_policy.c
net/ipv6/xfrm6_protocol.c [new file with mode: 0644]
net/ipx/af_ipx.c
net/ipx/ipx_route.c
net/iucv/af_iucv.c
net/key/af_key.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c
net/mac80211/chan.c
net/mac80211/iface.c
net/mac80211/mesh_ps.c
net/mac80211/sta_info.c
net/mac802154/Makefile
net/mac802154/ieee802154_dev.c
net/mac802154/mac802154.h
net/mac802154/mac_cmd.c
net/mac802154/mib.c
net/mac802154/rx.c
net/mac802154/wpan.c
net/netfilter/Kconfig
net/netfilter/Makefile
net/netfilter/ipset/Kconfig
net/netfilter/ipset/Makefile
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipset/ip_set_hash_ip.c
net/netfilter/ipset/ip_set_hash_ipmark.c [new file with mode: 0644]
net/netfilter/ipset/ip_set_hash_ipport.c
net/netfilter/ipset/ip_set_hash_ipportip.c
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netnet.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipset/ip_set_hash_netportnet.c
net/netfilter/ipset/pfxlen.c
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_h323_main.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_sip.c
net/netfilter/nf_nat_core.c
net/netfilter/nf_synproxy_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue_core.c
net/netfilter/nft_compat.c
net/netfilter/nft_ct.c
net/netfilter/nft_hash.c
net/netfilter/nft_immediate.c
net/netfilter/nft_log.c
net/netfilter/nft_lookup.c
net/netfilter/nft_meta.c
net/netfilter/nft_nat.c
net/netfilter/nft_payload.c
net/netfilter/nft_queue.c
net/netfilter/nft_rbtree.c
net/netfilter/nft_reject.c
net/netfilter/nft_reject_inet.c [new file with mode: 0644]
net/netfilter/xt_AUDIT.c
net/netfilter/xt_CT.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_ipcomp.c
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/openvswitch/datapath.c
net/openvswitch/datapath.h
net/openvswitch/flow.c
net/openvswitch/flow_table.c
net/openvswitch/flow_table.h
net/openvswitch/vport.c
net/packet/af_packet.c
net/rxrpc/Makefile
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-ack.c
net/rxrpc/ar-call.c
net/rxrpc/ar-connection.c
net/rxrpc/ar-error.c
net/rxrpc/ar-input.c
net/rxrpc/ar-internal.h
net/rxrpc/ar-output.c
net/rxrpc/ar-recvmsg.c
net/rxrpc/ar-skbuff.c
net/rxrpc/ar-transport.c
net/rxrpc/sysctl.c [new file with mode: 0644]
net/sched/act_api.c
net/sched/act_csum.c
net/sched/act_gact.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_nat.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_simple.c
net/sched/act_skbedit.c
net/sched/cls_fw.c
net/sched/sch_api.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_fq.c
net/sched/sch_fq_codel.c
net/sched/sch_hfsc.c
net/sched/sch_hhf.c
net/sched/sch_htb.c
net/sched/sch_ingress.c
net/sched/sch_netem.c
net/sched/sch_pie.c
net/sched/sch_tbf.c
net/sctp/associola.c
net/sctp/ipv6.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sctp/transport.c
net/sctp/ulpevent.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/backchannel_rqst.c
net/sunrpc/svc_xprt.c
net/sunrpc/xprtsock.c
net/tipc/addr.h
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/config.c
net/tipc/config.h
net/tipc/core.c
net/tipc/core.h
net/tipc/discover.c
net/tipc/discover.h
net/tipc/handler.c
net/tipc/link.c
net/tipc/link.h
net/tipc/name_distr.c
net/tipc/name_distr.h
net/tipc/name_table.c
net/tipc/net.c
net/tipc/netlink.c
net/tipc/node.c
net/tipc/node.h
net/tipc/port.c
net/tipc/port.h
net/tipc/ref.c
net/tipc/ref.h
net/tipc/server.c
net/tipc/server.h
net/tipc/socket.c
net/tipc/socket.h [new file with mode: 0644]
net/tipc/subscr.c
net/unix/af_unix.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/util.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/Makefile.lib
scripts/checkpatch.pl
scripts/gen_initramfs_list.sh
scripts/get_maintainer.pl
scripts/mod/file2alias.c
scripts/mod/modpost.c
security/capability.c
security/keys/keyring.c
security/security.c
security/selinux/hooks.c
security/selinux/include/security.h
security/selinux/include/xfrm.h
security/selinux/selinuxfs.c
security/selinux/ss/policydb.c
security/selinux/ss/services.c
security/selinux/xfrm.c
sound/core/compress_offload.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_generic.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/thinkpad_helper.c
sound/pci/oxygen/xonar_dg.c
sound/soc/blackfin/Kconfig
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/da732x.c
sound/soc/codecs/da9055.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/max98090.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/si476x.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_esai.h
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-wm8962.c
sound/soc/omap/n810.c
sound/soc/samsung/Kconfig
sound/soc/soc-dapm.c
sound/soc/soc-pcm.c
sound/soc/txx9/txx9aclc-ac97.c
sound/usb/mixer.c
sound/usb/mixer_maps.c
tools/lib/lockdep/Makefile
tools/lib/lockdep/preload.c
tools/lib/lockdep/run_tests.sh [changed mode: 0644->0755]
tools/lib/lockdep/uinclude/asm/hash.h [new file with mode: 0644]
tools/lib/lockdep/uinclude/linux/rcu.h
tools/net/Makefile
tools/net/bpf_dbg.c
tools/perf/bench/numa.c
tools/perf/builtin-bench.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/include/linux/bitops.h
tools/perf/util/machine.c
tools/perf/util/parse-events.c
tools/perf/util/probe-event.c
tools/perf/util/session.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/testing/selftests/ipc/msgque.c
virt/kvm/arm/vgic.c
virt/kvm/coalesced_mmio.c

index 7e9932e55475cef2891a790e391011b77b9ff666..42fa0d5626a9560d74d16b2df5250b300543b67e 100644 (file)
@@ -92,3 +92,6 @@ extra_certificates
 signing_key.priv
 signing_key.x509
 x509.genkey
+
+# Kconfig presets
+all.config
index 38f8444bdd0e2b6df55d5643f5ac73319e2663ad..07de7e19b4ce4b2255c5ddf0c046fa5515733203 100644 (file)
@@ -29,6 +29,8 @@ DMA-ISA-LPC.txt
        - How to do DMA with ISA (and LPC) devices.
 DMA-attributes.txt
        - listing of the various possible attributes a DMA region can have
+dmatest.txt
+       - how to compile, configure and use the dmatest system.
 DocBook/
        - directory with DocBook templates etc. for kernel documentation.
 EDID/
@@ -77,6 +79,8 @@ arm/
        - directory with info about Linux on the ARM architecture.
 arm64/
        - directory with info about Linux on the 64 bit ARM architecture.
+assoc_array.txt
+       - generic associative array intro.
 atomic_ops.txt
        - semantics and behavior of atomic and bitmask operations.
 auxdisplay/
@@ -87,6 +91,8 @@ bad_memory.txt
        - how to use kernel parameters to exclude bad RAM regions.
 basic_profiling.txt
        - basic instructions for those who wants to profile Linux kernel.
+bcache.txt
+       - Block-layer cache on fast SSDs to improve slow (raid) I/O performance.
 binfmt_misc.txt
        - info on the kernel support for extra binary formats.
 blackfin/
@@ -171,6 +177,8 @@ early-userspace/
        - info about initramfs, klibc, and userspace early during boot.
 edac.txt
        - information on EDAC - Error Detection And Correction
+efi-stub.txt
+       - How to use the EFI boot stub to bypass GRUB or elilo on EFI systems.
 eisa.txt
        - info on EISA bus support.
 email-clients.txt
@@ -195,8 +203,8 @@ futex-requeue-pi.txt
        - info on requeueing of tasks from a non-PI futex to a PI futex
 gcov.txt
        - use of GCC's coverage testing tool "gcov" with the Linux kernel
-gpio.txt
-       - overview of GPIO (General Purpose Input/Output) access conventions.
+gpio/
+       - gpio related documentation
 hid/
        - directory with information on human interface devices
 highuid.txt
@@ -255,6 +263,8 @@ kernel-docs.txt
        - listing of various WWW + books that document kernel internals.
 kernel-parameters.txt
        - summary listing of command line / boot prompt args for the kernel.
+kernel-per-CPU-kthreads.txt
+       - List of all per-CPU kthreads and how they introduce jitter.
 kmemcheck.txt
        - info on dynamic checker that detects uses of uninitialized memory.
 kmemleak.txt
@@ -299,8 +309,6 @@ memory-devices/
        - directory with info on parts like the Texas Instruments EMIF driver
 memory-hotplug.txt
        - Hotpluggable memory support, how to use and current status.
-memory.txt
-       - info on typical Linux memory problems.
 metag/
        - directory with info about Linux on Meta architecture.
 mips/
@@ -311,6 +319,8 @@ mmc/
        - directory with info about the MMC subsystem
 mn10300/
        - directory with info about the mn10300 architecture port
+module-signing.txt
+       - Kernel module signing for increased security when loading modules.
 mtd/
        - directory with info about memory technology devices (flash)
 mono.txt
@@ -343,6 +353,8 @@ pcmcia/
        - info on the Linux PCMCIA driver.
 percpu-rw-semaphore.txt
        - RCU based read-write semaphore optimized for locking for reading
+phy.txt
+       - Description of the generic PHY framework.
 pi-futex.txt
        - documentation on lightweight priority inheritance futexes.
 pinctrl.txt
@@ -431,6 +443,8 @@ sysrq.txt
        - info on the magic SysRq key.
 target/
        - directory with info on generating TCM v4 fabric .ko modules
+this_cpu_ops.txt
+       - List rationale behind and the way to use this_cpu operations.
 thermal/
        - directory with information on managing thermal issues (CPU/temp)
 trace/
@@ -469,6 +483,8 @@ wimax/
        - directory with info about Intel Wireless Wimax Connections
 workqueue.txt
        - information on the Concurrency Managed Workqueue implementation
+ww-mutex-design.txt
+       - Intro to Mutex wait/would deadlock handling.s
 x86/x86_64/
        - directory with info on Linux support for AMD x86-64 (Hammer) machines.
 xtensa/
index 6349749ebc2986ef0433263ee87487479f173549..491baaf4285f64d7a4e822359a43ad8c5f9d6c54 100644 (file)
@@ -7,3 +7,23 @@ Description:
                by the device during bus enumeration, encoded in hexadecimal.
                This ID is used to match the device with the appropriate
                driver.
+
+What:          /sys/bus/mdio_bus/devices/.../phy_interface
+Date:          February 2014
+KernelVersion: 3.15
+Contact:       netdev@vger.kernel.org
+Description:
+               This attribute contains the PHY interface as configured by the
+               Ethernet driver during bus enumeration, encoded in string.
+               This interface mode is used to configure the Ethernet MAC with the
+               appropriate mode for its data lines to the PHY hardware.
+
+What:          /sys/bus/mdio_bus/devices/.../phy_has_fixups
+Date:          February 2014
+KernelVersion: 3.15
+Contact:       netdev@vger.kernel.org
+Description:
+               This attribute contains the boolean value whether a given PHY
+               device has had any "fixup" workaround running on it, encoded as
+               a boolean. This information is provided to help troubleshooting
+               PHY configurations.
index 4793d3dff6af04e7ac4a736ccfdbd794d5a4d7f0..c464062966317b71838454a5de532095f4027851 100644 (file)
@@ -76,6 +76,15 @@ Description:
                is used to classify clients as "isolated" by the
                Extended Isolation feature.
 
+What:           /sys/class/net/<mesh_iface>/mesh/multicast_mode
+Date:           Feb 2014
+Contact:        Linus Lüssing <linus.luessing@web.de>
+Description:
+                Indicates whether multicast optimizations are enabled
+                or disabled. If set to zero then all nodes in the
+                mesh are going to use classic flooding for any
+                multicast packet with no optimizations.
+
 What:           /sys/class/net/<mesh_iface>/mesh/network_coding
 Date:           Nov 2012
 Contact:        Martin Hundeboll <martin@hundeboll.net>
index 05aeedf177946a9f9eb99a9f6b4b26a488f2f74a..44806a678f12a21a3ff149bc1b7838a4c14da602 100644 (file)
@@ -54,6 +54,26 @@ Description:
                This file contains the number of programmable periodic
                output channels offered by the PTP hardware clock.
 
+What:          /sys/class/ptp/ptpN/n_pins
+Date:          March 2014
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This file contains the number of programmable pins
+               offered by the PTP hardware clock.
+
+What:          /sys/class/ptp/ptpN/pins
+Date:          March 2014
+Contact:       Richard Cochran <richardcochran@gmail.com>
+Description:
+               This directory contains one file for each programmable
+               pin offered by the PTP hardware clock. The file name
+               is the hardware dependent pin name. Reading from this
+               file produces two numbers, the assigned function (see
+               the PTP_PF_ enumeration values in linux/ptp_clock.h)
+               and the channel number. The function and channel
+               assignment may be changed by two writing numbers into
+               the file.
+
 What:          /sys/class/ptp/ptpN/pps_avaiable
 Date:          September 2010
 Contact:       Richard Cochran <richardcochran@gmail.com>
index a8d01005f480ad6be4c86f187665e9ef3d75d08e..10a93696e55ad33c821a5466ed813a07e9fb9930 100644 (file)
@@ -82,7 +82,19 @@ Most of the hard work is done for the driver in the PCI layer.  It simply
 has to request that the PCI layer set up the MSI capability for this
 device.
 
-4.2.1 pci_enable_msi_range
+4.2.1 pci_enable_msi
+
+int pci_enable_msi(struct pci_dev *dev)
+
+A successful call allocates ONE interrupt to the device, regardless
+of how many MSIs the device supports.  The device is switched from
+pin-based interrupt mode to MSI mode.  The dev->irq number is changed
+to a new number which represents the message signaled interrupt;
+consequently, this function should be called before the driver calls
+request_irq(), because an MSI is delivered via a vector that is
+different from the vector of a pin-based interrupt.
+
+4.2.2 pci_enable_msi_range
 
 int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
 
@@ -147,6 +159,11 @@ static int foo_driver_enable_msi(struct pci_dev *pdev, int nvec)
        return pci_enable_msi_range(pdev, nvec, nvec);
 }
 
+Note, unlike pci_enable_msi_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msi_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msi_exact() does).
+
 4.2.1.3 Single MSI mode
 
 The most notorious example of the request type described above is
@@ -158,7 +175,27 @@ static int foo_driver_enable_single_msi(struct pci_dev *pdev)
        return pci_enable_msi_range(pdev, 1, 1);
 }
 
-4.2.2 pci_disable_msi
+Note, unlike pci_enable_msi() function, which could be also used to
+enable the single MSI mode, pci_enable_msi_range() returns either a
+negative errno or 1 (not negative errno or 0 - as pci_enable_msi()
+does).
+
+4.2.3 pci_enable_msi_exact
+
+int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+
+This variation on pci_enable_msi_range() call allows a device driver to
+request exactly 'nvec' MSIs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to request any more MSI interrupts for
+this device.
+
+By contrast with pci_enable_msi_range() function, pci_enable_msi_exact()
+returns zero in case of success, which indicates MSI interrupts have been
+successfully allocated.
+
+4.2.4 pci_disable_msi
 
 void pci_disable_msi(struct pci_dev *dev)
 
@@ -172,7 +209,7 @@ on any interrupt for which it previously called request_irq().
 Failure to do so results in a BUG_ON(), leaving the device with
 MSI enabled and thus leaking its vector.
 
-4.2.3 pci_msi_vec_count
+4.2.4 pci_msi_vec_count
 
 int pci_msi_vec_count(struct pci_dev *dev)
 
@@ -257,8 +294,8 @@ possible, likely up to the limit returned by pci_msix_vec_count() function:
 
 static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 {
-       return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
-                                   1, nvec);
+       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                    1, nvec);
 }
 
 Note the value of 'minvec' parameter is 1.  As 'minvec' is inclusive,
@@ -269,8 +306,8 @@ In this case the function could look like this:
 
 static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 {
-       return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
-                                   FOO_DRIVER_MINIMUM_NVEC, nvec);
+       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                    FOO_DRIVER_MINIMUM_NVEC, nvec);
 }
 
 4.3.1.2 Exact number of MSI-X interrupts
@@ -282,10 +319,15 @@ parameters:
 
 static int foo_driver_enable_msix(struct foo_adapter *adapter, int nvec)
 {
-       return pci_enable_msi_range(adapter->pdev, adapter->msix_entries,
-                                   nvec, nvec);
+       return pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                    nvec, nvec);
 }
 
+Note, unlike pci_enable_msix_exact() function, which could be also used to
+enable a particular number of MSI-X interrupts, pci_enable_msix_range()
+returns either a negative errno or 'nvec' (not negative errno or 0 - as
+pci_enable_msix_exact() does).
+
 4.3.1.3 Specific requirements to the number of MSI-X interrupts
 
 As noted above, there could be devices that can not operate with just any
@@ -332,7 +374,64 @@ Note how pci_enable_msix_range() return value is analized for a fallback -
 any error code other than -ENOSPC indicates a fatal error and should not
 be retried.
 
-4.3.2 pci_disable_msix
+4.3.2 pci_enable_msix_exact
+
+int pci_enable_msix_exact(struct pci_dev *dev,
+                         struct msix_entry *entries, int nvec)
+
+This variation on pci_enable_msix_range() call allows a device driver to
+request exactly 'nvec' MSI-Xs.
+
+If this function returns a negative number, it indicates an error and
+the driver should not attempt to allocate any more MSI-X interrupts for
+this device.
+
+By contrast with pci_enable_msix_range() function, pci_enable_msix_exact()
+returns zero in case of success, which indicates MSI-X interrupts have been
+successfully allocated.
+
+Another version of a routine that enables MSI-X mode for a device with
+specific requirements described in chapter 4.3.1.3 might look like this:
+
+/*
+ * Assume 'minvec' and 'maxvec' are non-zero
+ */
+static int foo_driver_enable_msix(struct foo_adapter *adapter,
+                                 int minvec, int maxvec)
+{
+       int rc;
+
+       minvec = roundup_pow_of_two(minvec);
+       maxvec = rounddown_pow_of_two(maxvec);
+
+       if (minvec > maxvec)
+               return -ERANGE;
+
+retry:
+       rc = pci_enable_msix_exact(adapter->pdev,
+                                  adapter->msix_entries, maxvec);
+
+       /*
+        * -ENOSPC is the only error code allowed to be analyzed
+        */
+       if (rc == -ENOSPC) {
+               if (maxvec == 1)
+                       return -ENOSPC;
+
+               maxvec /= 2;
+
+               if (minvec > maxvec)
+                       return -ENOSPC;
+
+               goto retry;
+       } else if (rc < 0) {
+               return rc;
+       }
+
+       return maxvec;
+}
+
+4.3.3 pci_disable_msix
 
 void pci_disable_msix(struct pci_dev *dev)
 
index 1d7a885761f51f07a8e46be9199ac67d5939f946..fa57139f50bf771b0aeacafaa4a5c4836a847f43 100644 (file)
@@ -8,6 +8,8 @@ listRCU.txt
        - Using RCU to Protect Read-Mostly Linked Lists
 lockdep.txt
        - RCU and lockdep checking
+lockdep-splat.txt
+       - RCU Lockdep splats explained.
 NMI-RCU.txt
        - Using RCU to Protect Dynamic NMI Handlers
 rcubarrier.txt
index 36420e116c908bc7fd6dea9bd3b55081c0addad1..a94090cc785d06eee25e0daa8150157f2125b9a8 100644 (file)
@@ -4,6 +4,8 @@ Booting
        - requirements for booting
 Interrupts
        - ARM Interrupt subsystem documentation
+IXP4xx
+       - Intel IXP4xx Network processor.
 msm
        - MSM specific documentation
 Netwinder
@@ -24,8 +26,16 @@ SPEAr
        - ST SPEAr platform Linux Overview
 VFP/
        - Release notes for Linux Kernel Vector Floating Point support code
+cluster-pm-race-avoidance.txt
+       - Algorithm for CPU and Cluster setup/teardown
 empeg/
        - Ltd's Empeg MP3 Car Audio Player
+firmware.txt
+       - Secure firmware registration and calling.
+kernel_mode_neon.txt
+       - How to use NEON instructions in kernel mode
+kernel_user_helpers.txt
+       - Helper functions in kernel space made available for userspace.
 mem_alignment
        - alignment abort handler documentation
 memory.txt
@@ -34,3 +44,7 @@ nwfpe/
        - NWFPE floating point emulator documentation
 swp_emulation
        - SWP/SWPB emulation handler/logging description
+tcm.txt
+       - ARM Tightly Coupled Memory
+vlocks.txt
+       - Voting locks, low-level mechanism relying on memory system atomic writes.
index 2df0365f2dff0ec2a02fd35025f0565ae31648fa..c54fcdd4ae9f68ce6ee439722c0bfac494651406 100644 (file)
@@ -1,8 +1,10 @@
 00-INDEX
        - This file
-
+Makefile
+       - Makefile for gptimers example file.
 bfin-gpio-notes.txt
        - Notes in developing/using bfin-gpio driver.
-
 bfin-spi-notes.txt
        - Notes for using bfin spi bus driver.
+gptimers-example.c
+       - gptimers example
index 929d9904f74b7eb94bac71e81308b0bf335c3108..e840b47613f78f9f9efa6843cc90c997a36ccdce 100644 (file)
@@ -14,6 +14,8 @@ deadline-iosched.txt
        - Deadline IO scheduler tunables
 ioprio.txt
        - Block io priorities (in CFQ scheduler)
+null_blk.txt
+       - Null block for block-layer benchmarking.
 queue-sysfs.txt
        - Queue's sysfs entries
 request.txt
index e6b72d35515123ad0aff423999aeef359183bb3d..68c0f517c60edb1ab7a61e990720c7c8f097bb16 100644 (file)
@@ -124,12 +124,11 @@ the default being 204800 sectors (or 100MB).
 Updating on-disk metadata
 -------------------------
 
-On-disk metadata is committed every time a REQ_SYNC or REQ_FUA bio is
-written.  If no such requests are made then commits will occur every
-second.  This means the cache behaves like a physical disk that has a
-write cache (the same is true of the thin-provisioning target).  If
-power is lost you may lose some recent writes.  The metadata should
-always be consistent in spite of any crash.
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second.  This
+means the cache behaves like a physical disk that has a volatile write
+cache.  If power is lost you may lose some recent writes.  The metadata
+should always be consistent in spite of any crash.
 
 The 'dirty' state for a cache block changes far too frequently for us
 to keep updating it on the fly.  So we treat it as a hint.  In normal
index 8a7a3d46e0daa00d6f87315648b7cb292e8c05b4..05a27e9442bd4e5c4d3e618a6a0594e55466b192 100644 (file)
@@ -116,6 +116,35 @@ Resuming a device with a new table itself triggers an event so the
 userspace daemon can use this to detect a situation where a new table
 already exceeds the threshold.
 
+A low water mark for the metadata device is maintained in the kernel and
+will trigger a dm event if free space on the metadata device drops below
+it.
+
+Updating on-disk metadata
+-------------------------
+
+On-disk metadata is committed every time a FLUSH or FUA bio is written.
+If no such requests are made then commits will occur every second.  This
+means the thin-provisioning target behaves like a physical disk that has
+a volatile write cache.  If power is lost you may lose some recent
+writes.  The metadata should always be consistent in spite of any crash.
+
+If data space is exhausted the pool will either error or queue IO
+according to the configuration (see: error_if_no_space).  If metadata
+space is exhausted or a metadata operation fails: the pool will error IO
+until the pool is taken offline and repair is performed to 1) fix any
+potential inconsistencies and 2) clear the flag that imposes repair.
+Once the pool's metadata device is repaired it may be resized, which
+will allow the pool to return to normal operation.  Note that if a pool
+is flagged as needing repair, the pool's data and metadata devices
+cannot be resized until repair is performed.  It should also be noted
+that when the pool's metadata space is exhausted the current metadata
+transaction is aborted.  Given that the pool will cache IO whose
+completion may have already been acknowledged to upper IO layers
+(e.g. filesystem) it is strongly suggested that consistency checks
+(e.g. fsck) be performed on those layers when repair of the pool is
+required.
+
 Thin provisioning
 -----------------
 
@@ -258,10 +287,9 @@ ii) Status
        should register for the event and then check the target's status.
 
     held metadata root:
-       The location, in sectors, of the metadata root that has been
+       The location, in blocks, of the metadata root that has been
        'held' for userspace read access.  '-' indicates there is no
-       held root.  This feature is not yet implemented so '-' is
-       always returned.
+       held root.
 
     discard_passdown|no_discard_passdown
        Whether or not discards are actually being passed down to the
index b78f691fd84705d0e557ae540732445bde7dbf62..8c4102c6a5e77b108522a00d40274ea6bcc03126 100644 (file)
@@ -8,3 +8,5 @@ https://lists.ozlabs.org/listinfo/devicetree-discuss
        - this file
 booting-without-of.txt
        - Booting Linux without Open Firmware, describes history and format of device trees.
+usage-model.txt
+       - How Linux uses DT and what DT aims to solve.
\ No newline at end of file
index 34dc40cffdfd8bfa316d55c2db5cc7a49fc1e999..af9b4a0d902b3f7a182864b02dbfec13fb6c2cba 100644 (file)
@@ -91,7 +91,7 @@ Boards:
   compatible = "ti,omap3-beagle", "ti,omap3"
 
 - OMAP3 Tobi with Overo : Commercial expansion board with daughter board
-  compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3"
+  compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3"
 
 - OMAP4 SDP : Software Development Board
   compatible = "ti,omap4-sdp", "ti,omap4430"
index a6a352c2771e74da0064ec9ce93a87c44ce2fe07..5992dceec7af7d1e9d1ac8f329b831d48e409d87 100644 (file)
@@ -21,9 +21,9 @@ Required Properties:
     must appear in the same order as the output clocks.
   - #clock-cells: Must be 1
   - clock-output-names: The name of the clocks as free-form strings
-  - renesas,indices: Indices of the gate clocks into the group (0 to 31)
+  - renesas,clock-indices: Indices of the gate clocks into the group (0 to 31)
 
-The clocks, clock-output-names and renesas,indices properties contain one
+The clocks, clock-output-names and renesas,clock-indices properties contain one
 entry per gate clock. The MSTP groups are sparsely populated. Unimplemented
 gate clocks must not be declared.
 
index 68b83ecc385007216d391f1a0edf06527dad5fb9..ee9be9961524cdcb45a0c43890064e8483702323 100644 (file)
@@ -1,12 +1,16 @@
 * Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
 
 Required properties:
-- compatible : Should be "fsl,imx31-sdma", "fsl,imx31-to1-sdma",
-  "fsl,imx31-to2-sdma", "fsl,imx35-sdma", "fsl,imx35-to1-sdma",
-  "fsl,imx35-to2-sdma", "fsl,imx51-sdma", "fsl,imx53-sdma" or
-  "fsl,imx6q-sdma". The -to variants should be preferred since they
-  allow to determnine the correct ROM script addresses needed for
-  the driver to work without additional firmware.
+- compatible : Should be one of
+      "fsl,imx25-sdma"
+      "fsl,imx31-sdma", "fsl,imx31-to1-sdma", "fsl,imx31-to2-sdma"
+      "fsl,imx35-sdma", "fsl,imx35-to1-sdma", "fsl,imx35-to2-sdma"
+      "fsl,imx51-sdma"
+      "fsl,imx53-sdma"
+      "fsl,imx6q-sdma"
+  The -to variants should be preferred since they allow to determnine the
+  correct ROM script addresses needed for the driver to work without additional
+  firmware.
 - reg : Should contain SDMA registers location and length
 - interrupts : Should contain SDMA interrupt
 - #dma-cells : Must be <3>.
index 0a85c70cd30a6eed9196f20c3a7eda14db71a9ae..07ad02075a935455387f684c4b94435a68c70255 100644 (file)
@@ -13,6 +13,9 @@ Required properties:
 - #address-cells: should be one. The cell is the slot id.
 - #size-cells: should be zero.
 - at least one slot node
+- clock-names: tuple listing input clock names.
+       Required elements: "mci_clk"
+- clocks: phandles to input clocks.
 
 The node contains child nodes for each slot that the platform uses
 
@@ -24,6 +27,8 @@ mmc0: mmc@f0008000 {
        interrupts = <12 4>;
        #address-cells = <1>;
        #size-cells = <0>;
+       clock-names = "mci_clk";
+       clocks = <&mci0_clk>;
 
        [ child node definitions...]
 };
index b90bfcd138fff1ab7b92f97b2323afcac60bdca0..10640b17c8668b5bc53a1e50813e6e6155b9458c 100644 (file)
@@ -1,20 +1,17 @@
 * Allwinner EMAC ethernet controller
 
 Required properties:
-- compatible: should be "allwinner,sun4i-emac".
+- compatible: should be "allwinner,sun4i-a10-emac" (Deprecated:
+              "allwinner,sun4i-emac")
 - reg: address and length of the register set for the device.
 - interrupts: interrupt for the device
-- phy: A phandle to a phy node defining the PHY address (as the reg
-  property, a single integer).
+- phy: see ethernet.txt file in the same directory.
 - clocks: A phandle to the reference clock for this device
 
-Optional properties:
-- (local-)mac-address: mac address to be used by this driver
-
 Example:
 
 emac: ethernet@01c0b000 {
-       compatible = "allwinner,sun4i-emac";
+       compatible = "allwinner,sun4i-a10-emac";
        reg = <0x01c0b000 0x1000>;
        interrupts = <55>;
        clocks = <&ahb_gates 17>;
index 00b9f9a3ec1d8bcce665a5c31645456de7e012a3..4ec56413779d3af28b60b3b647d4134d7f3e42bb 100644 (file)
@@ -1,7 +1,8 @@
 * Allwinner A10 MDIO Ethernet Controller interface
 
 Required properties:
-- compatible: should be "allwinner,sun4i-mdio".
+- compatible: should be "allwinner,sun4i-a10-mdio"
+              (Deprecated: "allwinner,sun4i-mdio").
 - reg: address and length of the register set for the device.
 
 Optional properties:
@@ -9,7 +10,7 @@ Optional properties:
 
 Example at the SoC level:
 mdio@01c0b080 {
-       compatible = "allwinner,sun4i-mdio";
+       compatible = "allwinner,sun4i-a10-mdio";
        reg = <0x01c0b080 0x14>;
        #address-cells = <1>;
        #size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/net/altera_tse.txt b/Documentation/devicetree/bindings/net/altera_tse.txt
new file mode 100644 (file)
index 0000000..a706297
--- /dev/null
@@ -0,0 +1,114 @@
+* Altera Triple-Speed Ethernet MAC driver (TSE)
+
+Required properties:
+- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should
+               be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE.
+               ALTR is supported for legacy device trees, but is deprecated.
+               altr should be used for all new designs.
+- reg: Address and length of the register set for the device. It contains
+  the information of registers in the same order as described by reg-names
+- reg-names: Should contain the reg names
+  "control_port": MAC configuration space region
+  "tx_csr":       xDMA Tx dispatcher control and status space region
+  "tx_desc":      MSGDMA Tx dispatcher descriptor space region
+  "rx_csr" :      xDMA Rx dispatcher control and status space region
+  "rx_desc":      MSGDMA Rx dispatcher descriptor space region
+  "rx_resp":      MSGDMA Rx dispatcher response space region
+  "s1":                  SGDMA descriptor memory
+- interrupts: Should contain the TSE interrupts and it's mode.
+- interrupt-names: Should contain the interrupt names
+  "rx_irq":       xDMA Rx dispatcher interrupt
+  "tx_irq":       xDMA Tx dispatcher interrupt
+- rx-fifo-depth: MAC receive FIFO buffer depth in bytes
+- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes
+- phy-mode: See ethernet.txt in the same directory.
+- phy-handle: See ethernet.txt in the same directory.
+- phy-addr: See ethernet.txt in the same directory. A configuration should
+               include phy-handle or phy-addr.
+- altr,has-supplementary-unicast:
+               If present, TSE supports additional unicast addresses.
+               Otherwise additional unicast addresses are not supported.
+- altr,has-hash-multicast-filter:
+               If present, TSE supports a hash based multicast filter.
+               Otherwise, hash-based multicast filtering is not supported.
+
+- mdio device tree subnode: When the TSE has a phy connected to its local
+               mdio, there must be device tree subnode with the following
+               required properties:
+
+       - compatible: Must be "altr,tse-mdio".
+       - #address-cells: Must be <1>.
+       - #size-cells: Must be <0>.
+
+       For each phy on the mdio bus, there must be a node with the following
+       fields:
+
+       - reg: phy id used to communicate to phy.
+       - device_type: Must be "ethernet-phy".
+
+Optional properties:
+- local-mac-address: See ethernet.txt in the same directory.
+- max-frame-size: See ethernet.txt in the same directory.
+
+Example:
+
+       tse_sub_0_eth_tse_0: ethernet@0x1,00000000 {
+               compatible = "altr,tse-msgdma-1.0";
+               reg =   <0x00000001 0x00000000 0x00000400>,
+                       <0x00000001 0x00000460 0x00000020>,
+                       <0x00000001 0x00000480 0x00000020>,
+                       <0x00000001 0x000004A0 0x00000008>,
+                       <0x00000001 0x00000400 0x00000020>,
+                       <0x00000001 0x00000420 0x00000020>;
+               reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+               interrupt-parent = <&hps_0_arm_gic_0>;
+               interrupts = <0 41 4>, <0 40 4>;
+               interrupt-names = "rx_irq", "tx_irq";
+               rx-fifo-depth = <2048>;
+               tx-fifo-depth = <2048>;
+               address-bits = <48>;
+               max-frame-size = <1500>;
+               local-mac-address = [ 00 00 00 00 00 00 ];
+               phy-mode = "gmii";
+               altr,has-supplementary-unicast;
+               altr,has-hash-multicast-filter;
+               phy-handle = <&phy0>;
+               mdio {
+                       compatible = "altr,tse-mdio";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       phy0: ethernet-phy@0 {
+                               reg = <0x0>;
+                               device_type = "ethernet-phy";
+                       };
+
+                       phy1: ethernet-phy@1 {
+                               reg = <0x1>;
+                               device_type = "ethernet-phy";
+                       };
+
+               };
+       };
+
+       tse_sub_1_eth_tse_0: ethernet@0x1,00001000 {
+               compatible = "altr,tse-msgdma-1.0";
+               reg =   <0x00000001 0x00001000 0x00000400>,
+                       <0x00000001 0x00001460 0x00000020>,
+                       <0x00000001 0x00001480 0x00000020>,
+                       <0x00000001 0x000014A0 0x00000008>,
+                       <0x00000001 0x00001400 0x00000020>,
+                       <0x00000001 0x00001420 0x00000020>;
+               reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
+               interrupt-parent = <&hps_0_arm_gic_0>;
+               interrupts = <0 43 4>, <0 42 4>;
+               interrupt-names = "rx_irq", "tx_irq";
+               rx-fifo-depth = <2048>;
+               tx-fifo-depth = <2048>;
+               address-bits = <48>;
+               max-frame-size = <1500>;
+               local-mac-address = [ 00 00 00 00 00 00 ];
+               phy-mode = "gmii";
+               altr,has-supplementary-unicast;
+               altr,has-hash-multicast-filter;
+               phy-handle = <&phy1>;
+       };
index bcbc3f009158c0ad1b5c9f285fce5c207057d664..7fbb027218a126002312a829c6cd273ac715b030 100644 (file)
@@ -6,19 +6,12 @@ Required properties:
 - interrupts: Should contain the EMAC interrupts
 - clock-frequency: CPU frequency. It is needed to calculate and set polling
 period of EMAC.
-- max-speed: Maximum supported data-rate in Mbit/s. In some HW configurations
-bandwidth of external memory controller might be a limiting factor. That's why
-it's required to specify which data-rate is supported on current SoC or FPGA.
-For example if only 10 Mbit/s is supported (10BASE-T) set "10". If 100 Mbit/s is
-supported (100BASE-TX) set "100".
-- phy: PHY device attached to the EMAC via MDIO bus
+- max-speed: see ethernet.txt file in the same directory.
+- phy: see ethernet.txt file in the same directory.
 
 Child nodes of the driver are the individual PHY devices connected to the
 MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus.
 
-Optional properties:
-- mac-address: 6 bytes, mac address
-
 Examples:
 
        ethernet@c0fc2000 {
diff --git a/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt b/Documentation/devicetree/bindings/net/broadcom-bcmgenet.txt
new file mode 100644 (file)
index 0000000..f2febb9
--- /dev/null
@@ -0,0 +1,121 @@
+* Broadcom BCM7xxx Ethernet Controller (GENET)
+
+Required properties:
+- compatible: should contain one of "brcm,genet-v1", "brcm,genet-v2",
+  "brcm,genet-v3", "brcm,genet-v4".
+- reg: address and length of the register set for the device
+- interrupts: must be two cells, the first cell is the general purpose
+  interrupt line, while the second cell is the interrupt for the ring
+  RX and TX queues operating in ring mode
+- phy-mode: see ethernet.txt file in the same directory
+- #address-cells: should be 1
+- #size-cells: should be 1
+
+Optional properties:
+- clocks: When provided, must be two phandles to the functional clocks nodes
+  of the GENET block. The first phandle is the main GENET clock used during
+  normal operation, while the second phandle is the Wake-on-LAN clock.
+- clock-names: When provided, names of the functional clock phandles, first
+  name should be "enet" and second should be "enet-wol".
+
+- phy-handle: See ethernet.txt file in the same directory; used to describe
+  configurations where a PHY (internal or external) is used.
+
+- fixed-link: When the GENET interface is connected to a MoCA hardware block or
+  when operating in a RGMII to RGMII type of connection, or when the MDIO bus is
+  voluntarily disabled, this property should be used to describe the "fixed link".
+  See Documentation/devicetree/bindings/net/fsl-tsec-phy.txt for information on
+  the property specifics
+
+Required child nodes:
+
+- mdio bus node: this node should always be present regarless of the PHY
+  configuration of the GENET instance
+
+MDIO bus node required properties:
+
+- compatible: should contain one of "brcm,genet-mdio-v1", "brcm,genet-mdio-v2"
+  "brcm,genet-mdio-v3", "brcm,genet-mdio-v4", the version has to match the
+  parent node compatible property (e.g: brcm,genet-v4 pairs with
+  brcm,genet-mdio-v4)
+- reg: address and length relative to the parent node base register address
+- #address-cells: address cell for MDIO bus addressing, should be 1
+- #size-cells: size of the cells for MDIO bus addressing, should be 0
+
+Ethernet PHY node properties:
+
+See Documentation/devicetree/bindings/net/phy.txt for the list of required and
+optional properties.
+
+Internal Gigabit PHY example:
+
+ethernet@f0b60000 {
+       phy-mode = "internal";
+       phy-handle = <&phy1>;
+       mac-address = [ 00 10 18 36 23 1a ];
+       compatible = "brcm,genet-v4";
+       #address-cells = <0x1>;
+       #size-cells = <0x1>;
+       reg = <0xf0b60000 0xfc4c>;
+       interrupts = <0x0 0x14 0x0>, <0x0 0x15 0x0>;
+
+       mdio@e14 {
+               compatible = "brcm,genet-mdio-v4";
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               reg = <0xe14 0x8>;
+
+               phy1: ethernet-phy@1 {
+                       max-speed = <1000>;
+                       reg = <0x1>;
+                       compatible = "brcm,28nm-gphy", "ethernet-phy-ieee802.3-c22";
+               };
+       };
+};
+
+MoCA interface / MAC to MAC example:
+
+ethernet@f0b80000 {
+       phy-mode = "moca";
+       fixed-link = <1 0 1000 0 0>;
+       mac-address = [ 00 10 18 36 24 1a ];
+       compatible = "brcm,genet-v4";
+       #address-cells = <0x1>;
+       #size-cells = <0x1>;
+       reg = <0xf0b80000 0xfc4c>;
+       interrupts = <0x0 0x16 0x0>, <0x0 0x17 0x0>;
+
+       mdio@e14 {
+               compatible = "brcm,genet-mdio-v4";
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               reg = <0xe14 0x8>;
+       };
+};
+
+
+External MDIO-connected Gigabit PHY/switch:
+
+ethernet@f0ba0000 {
+       phy-mode = "rgmii";
+       phy-handle = <&phy0>;
+       mac-address = [ 00 10 18 36 26 1a ];
+       compatible = "brcm,genet-v4";
+       #address-cells = <0x1>;
+       #size-cells = <0x1>;
+       reg = <0xf0ba0000 0xfc4c>;
+       interrupts = <0x0 0x18 0x0>, <0x0 0x19 0x0>;
+
+       mdio@0e14 {
+               compatible = "brcm,genet-mdio-v4";
+               #address-cells = <0x1>;
+               #size-cells = <0x0>;
+               reg = <0xe14 0x8>;
+
+               phy0: ethernet-phy@0 {
+                       max-speed = <1000>;
+                       reg = <0x0>;
+                       compatible = "brcm,bcm53125", "ethernet-phy-ieee802.3-c22";
+               };
+       };
+};
index f2105a47ec87c547fcd88d383d136ec4d11eb65b..b4a6d53fb01ae8827ba69b33bbc60e6db21d90a7 100644 (file)
@@ -12,6 +12,10 @@ Required properties:
 
 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.
+       Default to 1 (8 bits).
+
 - nxp,external-clock-frequency : Frequency of the external oscillator
        clock in Hz. Note that the internal clock frequency used by the
        SJA1000 is half of that value. If not specified, a default value
index 5da628db68bf4eaf29fa0aa86d32500481da32fb..8d7c3096390f59506552340b94bdba83dc717d30 100644 (file)
@@ -18,12 +18,7 @@ Properties:
 - interrupts: Two interrupt specifiers.  The first is the MIX
   interrupt routing and the second the routing for the AGL interrupts.
 
-- mac-address: Optional, the MAC address to assign to the device.
-
-- local-mac-address: Optional, the MAC address to assign to the device
-  if mac-address is not specified.
-
-- phy-handle: Optional, a phandle for the PHY device connected to this device.
+- phy-handle: Optional, see ethernet.txt file in the same directory.
 
 Example:
        ethernet@1070000100800 {
index d4c53ba04b3bad857d5f30c051c5e867653e31e5..7dbd158810d293b597d76f909d5544b3411bb641 100644 (file)
@@ -35,12 +35,7 @@ Properties for PIP port which is a child the PIP interface:
 
 - reg: The port number within the interface group.
 
-- mac-address: Optional, the MAC address to assign to the device.
-
-- local-mac-address: Optional, the MAC address to assign to the device
-  if mac-address is not specified.
-
-- phy-handle: Optional, a phandle for the PHY device connected to this device.
+- phy-handle: Optional, see ethernet.txt file in the same directory.
 
 Example:
 
index 09055c2495f0299f29597aeb76bfe199e4197126..abd67c13d3442228834e7df36a53a71454132160 100644 (file)
@@ -6,11 +6,7 @@ Required properties:
   or the generic form: "cdns,emac".
 - reg: Address and length of the register set for the device
 - interrupts: Should contain macb interrupt
-- phy-mode: String, operation mode of the PHY interface.
-  Supported values are: "mii", "rmii".
-
-Optional properties:
-- local-mac-address: 6 bytes, mac address
+- phy-mode: see ethernet.txt file in the same directory.
 
 Examples:
 
index 05d660e4ac6402f57be201105b94147c69776b53..ae2b8b7f9c38f0bb3d233588b1b2a4cc01f6c900 100644 (file)
@@ -28,9 +28,8 @@ Optional properties:
 Slave Properties:
 Required properties:
 - phy_id               : Specifies slave phy id
-- phy-mode             : The interface between the SoC and the PHY (a string
-                         that of_get_phy_mode() can understand)
-- mac-address          : Specifies slave MAC address
+- phy-mode             : See ethernet.txt file in the same directory
+- mac-address          : See ethernet.txt file in the same directory
 
 Optional properties:
 - dual_emac_res_vlan   : Specifies VID to be used to segregate the ports
index 2d39c990e641170ac22e5ff1e9d0caf1740c2d50..28767ed7c1bdcf44b43be8fdd50182706fd2a5f1 100644 (file)
@@ -9,8 +9,6 @@ Required properties:
 - interrupts : interrupt specifier specific to interrupt controller
 
 Optional properties:
-- local-mac-address : A bytestring of 6 bytes specifying Ethernet MAC address
-    to use (from firmware or bootloader)
 - davicom,no-eeprom : Configuration EEPROM is not available
 - davicom,ext-phy : Use external PHY
 
index 6e356d15154a9603c8ce2b73f57edbd0c326c60c..032808843f90a3b1db0389b0a60dd075c9ea3ac6 100644 (file)
@@ -17,9 +17,8 @@ Required properties:
                          Miscellaneous Interrupt>
 
 Optional properties:
-- phy-handle: Contains a phandle to an Ethernet PHY.
+- phy-handle: See ethernet.txt file in the same directory.
               If absent, davinci_emac driver defaults to 100/FULL.
-- local-mac-address : 6 bytes, mac address
 - ti,davinci-rmii-en: 1 byte, 1 means use RMII
 - ti,davinci-no-bd-ram: boolean, does EMAC have BD RAM?
 
diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt
new file mode 100644 (file)
index 0000000..9ecd43d
--- /dev/null
@@ -0,0 +1,25 @@
+The following properties are common to the Ethernet controllers:
+
+- local-mac-address: array of 6 bytes, specifies the MAC address that was
+  assigned to the network device;
+- mac-address: array of 6 bytes, specifies the MAC address that was last used by
+  the boot program; should be used in cases where the MAC address assigned to
+  the device by the boot program is different from the "local-mac-address"
+  property;
+- max-speed: number, specifies maximum speed in Mbit/s supported by the device;
+- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
+  the maximum frame size (there's contradiction in ePAPR).
+- phy-mode: string, operation mode of the PHY interface; supported values are
+  "mii", "gmii", "sgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id",
+  "rgmii-rxid", "rgmii-txid", "rtbi", "smii", "xgmii"; this is now a de-facto
+  standard property;
+- phy-connection-type: the same as "phy-mode" property but described in ePAPR;
+- phy-handle: phandle, specifies a reference to a node representing a PHY
+  device; this property is described in ePAPR and so preferred;
+- phy: the same as "phy-handle" property, not recommended for new bindings.
+- phy-device: the same as "phy-handle" property, not recommended for new
+  bindings.
+
+Child nodes of the Ethernet controller are typically the individual PHY devices
+connected via the MDIO bus (sometimes the MDIO bus controller is separate).
+They are described in the phy.txt file in this same directory.
index 845ff848d8950b546e7243fbc9568847ed2f87ab..6bc84adb10c0ca6f278cc30d40e0b802c12adfd8 100644 (file)
@@ -4,12 +4,9 @@ Required properties:
 - compatible : Should be "fsl,<soc>-fec"
 - reg : Address and length of the register set for the device
 - interrupts : Should contain fec interrupt
-- phy-mode : String, operation mode of the PHY interface.
-  Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
-  "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+- phy-mode : See ethernet.txt file in the same directory
 
 Optional properties:
-- local-mac-address : 6 bytes, mac address
 - phy-reset-gpios : Should specify the gpio for phy reset
 - phy-reset-duration : Reset duration in milliseconds.  Should present
   only if property "phy-reset-gpios" is available.  Missing the property
index d2ea4605d0789dc8d11ff3e1fd8686a30431a43b..737cdef4f9036eb6069b9f536f137351dc42b137 100644 (file)
@@ -38,22 +38,17 @@ Properties:
   - model : Model of the device.  Can be "TSEC", "eTSEC", or "FEC"
   - compatible : Should be "gianfar"
   - reg : Offset and length of the register set for the device
-  - local-mac-address : List of bytes representing the ethernet address of
-    this controller
   - interrupts : For FEC devices, the first interrupt is the device's
     interrupt.  For TSEC and eTSEC devices, the first interrupt is
     transmit, the second is receive, and the third is error.
-  - phy-handle : The phandle for the PHY connected to this ethernet
-    controller.
+  - phy-handle : See ethernet.txt file in the same directory.
   - fixed-link : <a b c d e> where a is emulated phy id - choose any,
     but unique to the all specified fixed-links, b is duplex - 0 half,
     1 full, c is link speed - d#10/d#100/d#1000, d is pause - 0 no
     pause, 1 pause, e is asym_pause - 0 no asym_pause, 1 asym_pause.
-  - phy-connection-type : a string naming the controller/PHY interface type,
-    i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
-    "tbi", or "rtbi".  This property is only really needed if the connection
-    is of type "rgmii-id", as all other connection types are detected by
-    hardware.
+  - phy-connection-type : See ethernet.txt file in the same directory.
+    This property is only really needed if the connection is of type
+    "rgmii-id", as all other connection types are detected by hardware.
   - fsl,magic-packet : If present, indicates that the hardware supports
     waking up via magic packet.
   - bd-stash : If present, indicates that the hardware supports stashing
index 585021acd1786d8b8413effddd3caa514c3aef5c..b92e927808b607e96c36d66f61fa6499c7ac0f1f 100644 (file)
@@ -6,10 +6,9 @@ Required properties:
 - interrupts: Should contain ethernet controller interrupt
 
 Optional properties:
-- phy-mode: String, operation mode of the PHY interface.
-  Supported values are: "mii", "rmii" (default)
+- phy-mode: See ethernet.txt file in the same directory. If the property is
+  absent, "rmii" is assumed.
 - use-iram: Use LPC32xx internal SRAM (IRAM) for DMA buffering
-- local-mac-address : 6 bytes, mac address
 
 Example:
 
index 70af2ec12b09306eebc6a809a9cf55feefc1635a..aaa696414f57a1012b5fc18586ce06da6a899309 100644 (file)
@@ -8,16 +8,12 @@ Required properties:
   the Cadence GEM, or the generic form: "cdns,gem".
 - reg: Address and length of the register set for the device
 - interrupts: Should contain macb interrupt
-- phy-mode: String, operation mode of the PHY interface.
-  Supported values are: "mii", "rmii", "gmii", "rgmii".
+- phy-mode: See ethernet.txt file in the same directory.
 - clock-names: Tuple listing input clock names.
        Required elements: 'pclk', 'hclk'
        Optional elements: 'tx_clk'
 - clocks: Phandles to input clocks.
 
-Optional properties:
-- local-mac-address: 6 bytes, mac address
-
 Examples:
 
        macb0: ethernet@fffc4000 {
index 859a6fa7569c07f93eac4a629969a7bf664e4a6e..750d577e8083ee3f96c8bf823c986c162d4ac5b3 100644 (file)
@@ -4,10 +4,8 @@ Required properties:
 - compatible: should be "marvell,armada-370-neta".
 - reg: address and length of the register set for the device.
 - interrupts: interrupt for the device
-- phy: A phandle to a phy node defining the PHY address (as the reg
-  property, a single integer).
-- phy-mode: The interface between the SoC and the PHY (a string that
-  of_get_phy_mode() can understand)
+- phy: See ethernet.txt file in the same directory.
+- phy-mode: See ethernet.txt file in the same directory
 - clocks: a pointer to the reference clock for this device.
 
 Example:
index c233b61142427c0c2793b936798aad4eaf17403b..bce52b2ec55ece41a14b997772956e077a7259e6 100644 (file)
@@ -36,7 +36,7 @@ Required port properties:
       "marvell,kirkwood-eth-port".
  - reg: port number relative to ethernet controller, shall be 0, 1, or 2.
  - interrupts: port interrupt.
- - local-mac-address: 6 bytes MAC address.
+ - local-mac-address: See ethernet.txt file in the same directory.
 
 Optional port properties:
  - marvell,tx-queue-size: size of the transmit ring buffer.
@@ -48,7 +48,7 @@ Optional port properties:
 
 and
 
- - phy-handle: phandle reference to ethernet PHY.
+ - phy-handle: See ethernet.txt file in the same directory.
 
 or
 
index 11ace3c3d805f872990ad82f721af2d7c8bd86b7..d54d0cc794871b29cbbbf9fbedd6242defa63677 100644 (file)
@@ -6,4 +6,4 @@ Required properties:
 - interrupts : interrupt connection
 
 Optional properties:
-- local-mac-address : Ethernet mac address to use
+- vdd-supply:  supply for Ethernet mac
diff --git a/Documentation/devicetree/bindings/net/micrel.txt b/Documentation/devicetree/bindings/net/micrel.txt
new file mode 100644 (file)
index 0000000..98a3e61
--- /dev/null
@@ -0,0 +1,18 @@
+Micrel PHY properties.
+
+These properties cover the base properties Micrel PHYs.
+
+Optional properties:
+
+ - micrel,led-mode : LED mode value to set for PHYs with configurable LEDs.
+
+              Configure the LED mode with single value. The list of PHYs and
+             the bits that are currently supported:
+
+             KSZ8001: register 0x1e, bits 15..14
+             KSZ8041: register 0x1e, bits 15..14
+             KSZ8021: register 0x1f, bits 5..4
+             KSZ8031: register 0x1f, bits 5..4
+             KSZ8051: register 0x1f, bits 5..4
+
+              See the respective PHY datasheet for the mode values.
diff --git a/Documentation/devicetree/bindings/net/opencores-ethoc.txt b/Documentation/devicetree/bindings/net/opencores-ethoc.txt
new file mode 100644 (file)
index 0000000..2dc127c
--- /dev/null
@@ -0,0 +1,22 @@
+* OpenCores MAC 10/100 Mbps
+
+Required properties:
+- compatible: Should be "opencores,ethoc".
+- reg: two memory regions (address and length),
+  first region is for the device registers and descriptor rings,
+  second is for the device packet memory.
+- interrupts: interrupt for the device.
+
+Optional properties:
+- clocks: phandle to refer to the clk used as per
+  Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Examples:
+
+       enet0: ethoc@fd030000 {
+               compatible = "opencores,ethoc";
+               reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
+               interrupts = <1>;
+               local-mac-address = [00 50 c2 13 6f 00];
+               clocks = <&osc>;
+        };
index 58307d0931c84294ec0ebfd75d6a215db4b5bf3f..5b8c5890307773cf52b62eded7c1869a9b7aa2a3 100644 (file)
@@ -21,10 +21,18 @@ Optional Properties:
   elements.
 - max-speed: Maximum PHY supported speed (10, 100, 1000...)
 
+  If the phy's identifier is known then the list may contain an entry
+  of the form: "ethernet-phy-idAAAA.BBBB" where
+     AAAA - The value of the 16 bit Phy Identifier 1 register as
+            4 hex digits. This is the chip vendor OUI bits 3:18
+     BBBB - The value of the 16 bit Phy Identifier 2 register as
+            4 hex digits. This is the chip vendor OUI bits 19:24,
+            followed by 10 bits of a vendor specific ID.
+
 Example:
 
 ethernet-phy@0 {
-       compatible = "ethernet-phy-ieee802.3-c22";
+       compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22";
        interrupt-parent = <40000>;
        interrupts = <35 1>;
        reg = <0>;
diff --git a/Documentation/devicetree/bindings/net/samsung-sxgbe.txt b/Documentation/devicetree/bindings/net/samsung-sxgbe.txt
new file mode 100644 (file)
index 0000000..989f6c9
--- /dev/null
@@ -0,0 +1,52 @@
+* Samsung 10G Ethernet driver (SXGBE)
+
+Required properties:
+- compatible: Should be "samsung,sxgbe-v2.0a"
+- reg: Address and length of the register set for the device
+- interrupt-parent: Should be the phandle for the interrupt controller
+  that services interrupts for this device
+- interrupts: Should contain the SXGBE interrupts
+  These interrupts are ordered by fixed and follows variable
+  trasmit DMA interrupts, receive DMA interrupts and lpi interrupt.
+  index 0 - this is fixed common interrupt of SXGBE and it is always
+  available.
+  index 1 to 25 - 8 variable trasmit interrupts, variable 16 receive interrupts
+  and 1 optional lpi interrupt.
+- phy-mode: String, operation mode of the PHY interface.
+  Supported values are: "sgmii", "xgmii".
+- samsung,pbl: Integer, Programmable Burst Length.
+  Supported values are 1, 2, 4, 8, 16, or 32.
+- samsung,burst-map: Integer, Program the possible bursts supported by sxgbe
+  This is an interger and represents allowable DMA bursts when fixed burst.
+  Allowable range is 0x01-0x3F. When this field is set fixed burst is enabled.
+  When fixed length is needed for burst mode, it can be set within allowable
+  range.
+
+Optional properties:
+- mac-address: 6 bytes, mac address
+- max-frame-size: Maximum Transfer Unit (IEEE defined MTU), rather
+                 than the maximum frame size.
+
+Example:
+
+       aliases {
+               ethernet0 = <&sxgbe0>;
+       };
+
+       sxgbe0: ethernet@1a040000 {
+               compatible = "samsung,sxgbe-v2.0a";
+               reg = <0 0x1a040000 0 0x10000>;
+               interrupt-parent = <&gic>;
+               interrupts = <0 209 4>, <0 185 4>, <0 186 4>, <0 187 4>,
+                            <0 188 4>, <0 189 4>, <0 190 4>, <0 191 4>,
+                            <0 192 4>, <0 193 4>, <0 194 4>, <0 195 4>,
+                            <0 196 4>, <0 197 4>, <0 198 4>, <0 199 4>,
+                            <0 200 4>, <0 201 4>, <0 202 4>, <0 203 4>,
+                            <0 204 4>, <0 205 4>, <0 206 4>, <0 207 4>,
+                            <0 208 4>, <0 210 4>;
+               samsung,pbl = <0x08>
+               samsung,burst-map = <0x20>
+               mac-address = [ 00 11 22 33 44 55 ]; /* Filled in by U-Boot */
+               max-frame-size = <9000>;
+               phy-mode = "xgmii";
+       };
diff --git a/Documentation/devicetree/bindings/net/sh_eth.txt b/Documentation/devicetree/bindings/net/sh_eth.txt
new file mode 100644 (file)
index 0000000..e7106b5
--- /dev/null
@@ -0,0 +1,55 @@
+* Renesas Electronics SH EtherMAC
+
+This file provides information on what the device node for the SH EtherMAC
+interface contains.
+
+Required properties:
+- compatible: "renesas,gether-r8a7740" if the device is a part of R8A7740 SoC.
+             "renesas,ether-r8a7778"  if the device is a part of R8A7778 SoC.
+             "renesas,ether-r8a7779"  if the device is a part of R8A7779 SoC.
+             "renesas,ether-r8a7790"  if the device is a part of R8A7790 SoC.
+             "renesas,ether-r8a7791"  if the device is a part of R8A7791 SoC.
+             "renesas,ether-r7s72100" if the device is a part of R7S72100 SoC.
+- reg: offset and length of (1) the E-DMAC/feLic register block (required),
+       (2) the TSU register block (optional).
+- interrupts: interrupt specifier for the sole interrupt.
+- phy-mode: see ethernet.txt file in the same directory.
+- phy-handle: see ethernet.txt file in the same directory.
+- #address-cells: number of address cells for the MDIO bus, must be equal to 1.
+- #size-cells: number of size cells on the MDIO bus, must be equal to 0.
+- clocks: clock phandle and specifier pair.
+- pinctrl-0: phandle, referring to a default pin configuration node.
+
+Optional properties:
+- interrupt-parent: the phandle for the interrupt controller that services
+                   interrupts for this device.
+- pinctrl-names: pin configuration state name ("default").
+- renesas,no-ether-link: boolean, specify when a board does not provide a proper
+                        Ether LINK signal.
+- renesas,ether-link-active-low: boolean, specify when the Ether LINK signal is
+                                active-low instead of normal active-high.
+
+Example (Lager board):
+
+       ethernet@ee700000 {
+               compatible = "renesas,ether-r8a7790";
+               reg = <0 0xee700000 0 0x400>;
+               interrupt-parent = <&gic>;
+               interrupts = <0 162 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&mstp8_clks R8A7790_CLK_ETHER>;
+               phy-mode = "rmii";
+               phy-handle = <&phy1>;
+               pinctrl-0 = <&ether_pins>;
+               pinctrl-names = "default";
+               renesas,ether-link-active-low;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               phy1: ethernet-phy@1 {
+                       reg = <1>;
+                       interrupt-parent = <&irqc0>;
+                       interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+                       pinctrl-0 = <&phy1_pins>;
+                       pinctrl-names = "default";
+               };
+       };
index 5a41a8658daa12087678a7d81f5f60038cbeddf8..0f8487b888221e6344dec76afd6a8ffa44242306 100644 (file)
@@ -6,8 +6,7 @@ Required properties:
 - interrupts : interrupt connection
 
 Optional properties:
-- phy-device : phandle to Ethernet phy
-- local-mac-address : Ethernet mac address to use
+- phy-device : see ethernet.txt file in the same directory
 - reg-io-width : Mask of sizes (in bytes) of the IO accesses that
   are supported on the device.  Valid value for SMSC LAN91c111 are
   1, 2 or 4.  If it's omitted or invalid, the size would be 2 meaning
index adb5b5744ecd6a7809457061721a16479bdc59b2..3fed3c12441161926fb78590016b59bb90c78448 100644 (file)
@@ -6,9 +6,7 @@ Required properties:
 - interrupts : Should contain SMSC LAN interrupt line
 - interrupt-parent : Should be the phandle for the interrupt controller
   that services interrupts for this device
-- phy-mode : String, operation mode of the PHY interface.
-  Supported values are: "mii", "gmii", "sgmii", "tbi", "rmii",
-  "rgmii", "rgmii-id", "rgmii-rxid", "rgmii-txid", "rtbi", "smii".
+- phy-mode : See ethernet.txt file in the same directory
 
 Optional properties:
 - reg-shift : Specify the quantity to shift the register offsets by
@@ -23,7 +21,6 @@ Optional properties:
   external PHY
 - smsc,save-mac-address : Indicates that mac address needs to be saved
   before resetting the controller
-- local-mac-address : 6 bytes, mac address
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/net/sti-dwmac.txt b/Documentation/devicetree/bindings/net/sti-dwmac.txt
new file mode 100644 (file)
index 0000000..3dd3d0b
--- /dev/null
@@ -0,0 +1,58 @@
+STMicroelectronics SoC DWMAC glue layer controller
+
+The device node has following properties.
+
+Required properties:
+ - compatible  : Can be "st,stih415-dwmac", "st,stih416-dwmac" or
+   "st,stid127-dwmac".
+ - reg         : Offset of the glue configuration register map in system
+   configuration regmap pointed by st,syscon property and size.
+
+ - reg-names   : Should be "sti-ethconf".
+
+ - st,syscon   : Should be phandle to system configuration node which
+   encompases this glue registers.
+
+ - st,tx-retime-src: On STi Parts for Giga bit speeds, 125Mhz clocks can be
+   wired up in from different sources. One via TXCLK pin and other via CLK_125
+   pin. This wiring is totally board dependent. However the retiming glue
+   logic should be configured accordingly. Possible values for this property
+
+          "txclk" - if 125Mhz clock is wired up via txclk line.
+          "clk_125" - if 125Mhz clock is wired up via clk_125 line.
+
+   This property is only valid for Giga bit setup( GMII, RGMII), and it is
+   un-used for non-giga bit (MII and RMII) setups. Also note that internal
+   clockgen can not generate stable 125Mhz clock.
+
+ - st,ext-phyclk: This boolean property indicates who is generating the clock
+  for tx and rx. This property is only valid for RMII case where the clock can
+  be generated from the MAC or PHY.
+
+ - clock-names: should be "sti-ethclk".
+ - clocks: Should point to ethernet clockgen which can generate phyclk.
+
+
+Example:
+
+ethernet0: dwmac@fe810000 {
+       device_type     = "network";
+       compatible      = "st,stih416-dwmac", "snps,dwmac", "snps,dwmac-3.710";
+       reg             = <0xfe810000 0x8000>, <0x8bc 0x4>;
+       reg-names       = "stmmaceth", "sti-ethconf";
+       interrupts      = <0 133 0>, <0 134 0>, <0 135 0>;
+       interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
+       phy-mode        = "mii";
+
+       st,syscon       = <&syscfg_rear>;
+
+       snps,pbl        = <32>;
+       snps,mixed-burst;
+
+       resets          = <&softreset STIH416_ETH0_SOFTRESET>;
+       reset-names     = "stmmaceth";
+       pinctrl-0       = <&pinctrl_mii0>;
+       pinctrl-names   = "default";
+       clocks          = <&CLK_S_GMAC0_PHY>;
+       clock-names     = "stmmaceth";
+};
index 9d92d42140f22109143f9d975a9fd2c96fec9837..5748351fb9dfce76f148772e4546e97684fb6b67 100644 (file)
@@ -10,8 +10,7 @@ Required properties:
 - interrupt-names: Should contain the interrupt names "macirq"
   "eth_wake_irq" if this interrupt is supported in the "interrupts"
   property
-- phy-mode: String, operation mode of the PHY interface.
-  Supported values are: "mii", "rmii", "gmii", "rgmii".
+- phy-mode: See ethernet.txt file in the same directory.
 - snps,reset-gpio      gpio number for phy reset.
 - snps,reset-active-low boolean flag to indicate if phy reset is active low.
 - snps,reset-delays-us  is triplet of delays
@@ -28,12 +27,10 @@ Required properties:
                                ignored if force_thresh_dma_mode is set.
 
 Optional properties:
-- mac-address: 6 bytes, mac address
 - 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:      Maximum Transfer Unit (IEEE defined MTU), rather
-                       than the maximum frame size.
+- max-frame-size: See ethernet.txt file in the same directory
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,bcm11351-pinctrl.txt
new file mode 100644 (file)
index 0000000..c119deb
--- /dev/null
@@ -0,0 +1,461 @@
+Broadcom BCM281xx Pin Controller
+
+This is a pin controller for the Broadcom BCM281xx SoC family, which includes
+BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
+
+=== Pin Controller Node ===
+
+Required Properties:
+
+- compatible:  Must be "brcm,bcm11351-pinctrl"
+- reg:         Base address of the PAD Controller register block and the size
+               of the block.
+
+For example, the following is the bare minimum node:
+
+       pinctrl@35004800 {
+               compatible = "brcm,bcm11351-pinctrl";
+               reg = <0x35004800 0x430>;
+       };
+
+As a pin controller device, in addition to the required properties, this node
+should also contain the pin configuration nodes that client devices reference,
+if any.
+
+=== Pin Configuration Node ===
+
+Each pin configuration node is a sub-node of the pin controller node and is a
+container of an arbitrary number of subnodes, called pin group nodes in this
+document.
+
+Please refer to the pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the definition of a
+"pin configuration node".
+
+=== Pin Group Node ===
+
+A pin group node specifies the desired pin mux and/or pin configuration for an
+arbitrary number of pins.  The name of the pin group node is optional and not
+used.
+
+A pin group node only affects the properties specified in the node, and has no
+effect on any properties that are omitted.
+
+The pin group node accepts a subset of the generic pin config properties. For
+details generic pin config properties, please refer to pinctrl-bindings.txt
+and <include/linux/pinctrl/pinconfig-generic.h>.
+
+Each pin controlled by this pin controller belong to one of three types:
+Standard, I2C, and HDMI.  Each type accepts a different set of pin config
+properties.  A list of pins and their types is provided below.
+
+Required Properties (applicable to all pins):
+
+- pins:                Multiple strings.  Specifies the name(s) of one or more pins to
+               be configured by this node.
+
+Optional Properties (for standard pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- input-schmitt-enable:                No arguments. Enable schmitt-trigger mode.
+- input-schmitt-disable:       No arguments. Disable schmitt-trigger mode.
+- bias-pull-up:                        No arguments. Pull up on pin.
+- bias-pull-down:              No arguments. Pull down on pin.
+- bias-disable:                        No arguments. Disable pin bias.
+- slew-rate:                   Integer. Meaning depends on configured pin mux:
+                               *_SCL or *_SDA:
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+                               IC_DM or IC_DP:
+                                       0: normal slew rate
+                                       1: fast slew rate
+                               Otherwise:
+                                       0: fast slew rate
+                                       1: normal slew rate
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+- drive-strength:              Integer. Drive strength in mA.  Valid values are
+                               2, 4, 6, 8, 10, 12, 14, 16 mA.
+
+Optional Properties (for I2C pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- bias-pull-up:                        Integer. Pull up strength in Ohm. There are 3
+                               pull-up resisitors (1.2k, 1.8k, 2.7k) available
+                               in parallel for I2C pins, so the valid values
+                               are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm.
+- bias-disable:                        No arguments. Disable pin bias.
+- slew-rate:                   Integer. Meaning depends on configured pin mux:
+                               *_SCL or *_SDA:
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+                               IC_DM or IC_DP:
+                                       0: normal slew rate
+                                       1: fast slew rate
+                               Otherwise:
+                                       0: fast slew rate
+                                       1: normal slew rate
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+
+Optional Properties (for HDMI pins):
+
+- function:                    String. Specifies the pin mux selection. Values
+                               must be one of: "alt1", "alt2", "alt3", "alt4"
+- slew-rate:                   Integer. Controls slew rate.
+                                       0: Standard(100kbps)& Fast(400kbps) mode
+                                       1: Highspeed (3.4Mbps) mode
+- input-enable:                        No arguements. Enable input (does not affect
+                               output.)
+- input-disable:               No arguements. Disable input (does not affect
+                               output.)
+
+Example:
+// pin controller node
+pinctrl@35004800 {
+       compatible = "brcmbcm11351-pinctrl";
+       reg = <0x35004800 0x430>;
+
+       // pin configuration node
+       dev_a_default: dev_a_active {
+               //group node defining 1 standard pin
+               grp_1 {
+                       pins            = "std_pin1";
+                       function        = "alt1";
+                       input-schmitt-enable;
+                       bias-disable;
+                       slew-rate       = <1>;
+                       drive-strength  = <4>;
+               };
+
+               // group node defining 2 I2C pins
+               grp_2 {
+                       pins            = "i2c_pin1", "i2c_pin2";
+                       function        = "alt2";
+                       bias-pull-up    = <720>;
+                       input-enable;
+               };
+
+               // group node defining 2 HDMI pins
+               grp_3 {
+                       pins            = "hdmi_pin1", "hdmi_pin2";
+                       function        = "alt3";
+                       slew-rate       = <1>;
+               };
+
+               // other pin group nodes
+               ...
+       };
+
+       // other pin configuration nodes
+       ...
+};
+
+In the example above, "dev_a_active" is a pin configuration node with a number
+of sub-nodes.  In the pin group node "grp_1", one pin, "std_pin1", is defined in
+the "pins" property.  Thus, the remaining properties in the "grp_1" node applies
+only to this pin, including the following settings:
+ - setting pinmux to "alt1"
+ - enabling schmitt-trigger (hystersis) mode
+ - disabling pin bias
+ - setting the slew-rate to 1
+ - setting the drive strength to 4 mA
+Note that neither "input-enable" nor "input-disable" was specified - the pinctrl
+subsystem will therefore leave this property unchanged from whatever state it
+was in before applying these changes.
+
+The "pins" property in the pin group node "grp_2" specifies two pins -
+"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node,
+therefore, applies to both of these pins.  The properties include:
+ - setting pinmux to "alt2"
+ - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors
+   in parallel)
+ - enabling both pins' input
+"slew-rate" is not specified in this pin group node, so the slew-rate for these
+pins are left as-is.
+
+Finally, "grp_3" defines two HDMI pins.  The following properties are applied to
+both pins:
+ - setting pinmux to "alt3"
+ - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps
+   Highspeed mode
+The input is neither enabled or disabled, and is left untouched.
+
+=== Pin Names and Type ===
+
+The following are valid pin names and their pin types:
+
+       "adcsync",              Standard
+       "bat_rm",               Standard
+       "bsc1_scl",             I2C
+       "bsc1_sda",             I2C
+       "bsc2_scl",             I2C
+       "bsc2_sda",             I2C
+       "classgpwr",            Standard
+       "clk_cx8",              Standard
+       "clkout_0",             Standard
+       "clkout_1",             Standard
+       "clkout_2",             Standard
+       "clkout_3",             Standard
+       "clkreq_in_0",          Standard
+       "clkreq_in_1",          Standard
+       "cws_sys_req1",         Standard
+       "cws_sys_req2",         Standard
+       "cws_sys_req3",         Standard
+       "digmic1_clk",          Standard
+       "digmic1_dq",           Standard
+       "digmic2_clk",          Standard
+       "digmic2_dq",           Standard
+       "gpen13",               Standard
+       "gpen14",               Standard
+       "gpen15",               Standard
+       "gpio00",               Standard
+       "gpio01",               Standard
+       "gpio02",               Standard
+       "gpio03",               Standard
+       "gpio04",               Standard
+       "gpio05",               Standard
+       "gpio06",               Standard
+       "gpio07",               Standard
+       "gpio08",               Standard
+       "gpio09",               Standard
+       "gpio10",               Standard
+       "gpio11",               Standard
+       "gpio12",               Standard
+       "gpio13",               Standard
+       "gpio14",               Standard
+       "gps_pablank",          Standard
+       "gps_tmark",            Standard
+       "hdmi_scl",             HDMI
+       "hdmi_sda",             HDMI
+       "ic_dm",                Standard
+       "ic_dp",                Standard
+       "kp_col_ip_0",          Standard
+       "kp_col_ip_1",          Standard
+       "kp_col_ip_2",          Standard
+       "kp_col_ip_3",          Standard
+       "kp_row_op_0",          Standard
+       "kp_row_op_1",          Standard
+       "kp_row_op_2",          Standard
+       "kp_row_op_3",          Standard
+       "lcd_b_0",              Standard
+       "lcd_b_1",              Standard
+       "lcd_b_2",              Standard
+       "lcd_b_3",              Standard
+       "lcd_b_4",              Standard
+       "lcd_b_5",              Standard
+       "lcd_b_6",              Standard
+       "lcd_b_7",              Standard
+       "lcd_g_0",              Standard
+       "lcd_g_1",              Standard
+       "lcd_g_2",              Standard
+       "lcd_g_3",              Standard
+       "lcd_g_4",              Standard
+       "lcd_g_5",              Standard
+       "lcd_g_6",              Standard
+       "lcd_g_7",              Standard
+       "lcd_hsync",            Standard
+       "lcd_oe",               Standard
+       "lcd_pclk",             Standard
+       "lcd_r_0",              Standard
+       "lcd_r_1",              Standard
+       "lcd_r_2",              Standard
+       "lcd_r_3",              Standard
+       "lcd_r_4",              Standard
+       "lcd_r_5",              Standard
+       "lcd_r_6",              Standard
+       "lcd_r_7",              Standard
+       "lcd_vsync",            Standard
+       "mdmgpio0",             Standard
+       "mdmgpio1",             Standard
+       "mdmgpio2",             Standard
+       "mdmgpio3",             Standard
+       "mdmgpio4",             Standard
+       "mdmgpio5",             Standard
+       "mdmgpio6",             Standard
+       "mdmgpio7",             Standard
+       "mdmgpio8",             Standard
+       "mphi_data_0",          Standard
+       "mphi_data_1",          Standard
+       "mphi_data_2",          Standard
+       "mphi_data_3",          Standard
+       "mphi_data_4",          Standard
+       "mphi_data_5",          Standard
+       "mphi_data_6",          Standard
+       "mphi_data_7",          Standard
+       "mphi_data_8",          Standard
+       "mphi_data_9",          Standard
+       "mphi_data_10",         Standard
+       "mphi_data_11",         Standard
+       "mphi_data_12",         Standard
+       "mphi_data_13",         Standard
+       "mphi_data_14",         Standard
+       "mphi_data_15",         Standard
+       "mphi_ha0",             Standard
+       "mphi_hat0",            Standard
+       "mphi_hat1",            Standard
+       "mphi_hce0_n",          Standard
+       "mphi_hce1_n",          Standard
+       "mphi_hrd_n",           Standard
+       "mphi_hwr_n",           Standard
+       "mphi_run0",            Standard
+       "mphi_run1",            Standard
+       "mtx_scan_clk",         Standard
+       "mtx_scan_data",        Standard
+       "nand_ad_0",            Standard
+       "nand_ad_1",            Standard
+       "nand_ad_2",            Standard
+       "nand_ad_3",            Standard
+       "nand_ad_4",            Standard
+       "nand_ad_5",            Standard
+       "nand_ad_6",            Standard
+       "nand_ad_7",            Standard
+       "nand_ale",             Standard
+       "nand_cen_0",           Standard
+       "nand_cen_1",           Standard
+       "nand_cle",             Standard
+       "nand_oen",             Standard
+       "nand_rdy_0",           Standard
+       "nand_rdy_1",           Standard
+       "nand_wen",             Standard
+       "nand_wp",              Standard
+       "pc1",                  Standard
+       "pc2",                  Standard
+       "pmu_int",              Standard
+       "pmu_scl",              I2C
+       "pmu_sda",              I2C
+       "rfst2g_mtsloten3g",    Standard
+       "rgmii_0_rx_ctl",       Standard
+       "rgmii_0_rxc",          Standard
+       "rgmii_0_rxd_0",        Standard
+       "rgmii_0_rxd_1",        Standard
+       "rgmii_0_rxd_2",        Standard
+       "rgmii_0_rxd_3",        Standard
+       "rgmii_0_tx_ctl",       Standard
+       "rgmii_0_txc",          Standard
+       "rgmii_0_txd_0",        Standard
+       "rgmii_0_txd_1",        Standard
+       "rgmii_0_txd_2",        Standard
+       "rgmii_0_txd_3",        Standard
+       "rgmii_1_rx_ctl",       Standard
+       "rgmii_1_rxc",          Standard
+       "rgmii_1_rxd_0",        Standard
+       "rgmii_1_rxd_1",        Standard
+       "rgmii_1_rxd_2",        Standard
+       "rgmii_1_rxd_3",        Standard
+       "rgmii_1_tx_ctl",       Standard
+       "rgmii_1_txc",          Standard
+       "rgmii_1_txd_0",        Standard
+       "rgmii_1_txd_1",        Standard
+       "rgmii_1_txd_2",        Standard
+       "rgmii_1_txd_3",        Standard
+       "rgmii_gpio_0",         Standard
+       "rgmii_gpio_1",         Standard
+       "rgmii_gpio_2",         Standard
+       "rgmii_gpio_3",         Standard
+       "rtxdata2g_txdata3g1",  Standard
+       "rtxen2g_txdata3g2",    Standard
+       "rxdata3g0",            Standard
+       "rxdata3g1",            Standard
+       "rxdata3g2",            Standard
+       "sdio1_clk",            Standard
+       "sdio1_cmd",            Standard
+       "sdio1_data_0",         Standard
+       "sdio1_data_1",         Standard
+       "sdio1_data_2",         Standard
+       "sdio1_data_3",         Standard
+       "sdio4_clk",            Standard
+       "sdio4_cmd",            Standard
+       "sdio4_data_0",         Standard
+       "sdio4_data_1",         Standard
+       "sdio4_data_2",         Standard
+       "sdio4_data_3",         Standard
+       "sim_clk",              Standard
+       "sim_data",             Standard
+       "sim_det",              Standard
+       "sim_resetn",           Standard
+       "sim2_clk",             Standard
+       "sim2_data",            Standard
+       "sim2_det",             Standard
+       "sim2_resetn",          Standard
+       "sri_c",                Standard
+       "sri_d",                Standard
+       "sri_e",                Standard
+       "ssp_extclk",           Standard
+       "ssp0_clk",             Standard
+       "ssp0_fs",              Standard
+       "ssp0_rxd",             Standard
+       "ssp0_txd",             Standard
+       "ssp2_clk",             Standard
+       "ssp2_fs_0",            Standard
+       "ssp2_fs_1",            Standard
+       "ssp2_fs_2",            Standard
+       "ssp2_fs_3",            Standard
+       "ssp2_rxd_0",           Standard
+       "ssp2_rxd_1",           Standard
+       "ssp2_txd_0",           Standard
+       "ssp2_txd_1",           Standard
+       "ssp3_clk",             Standard
+       "ssp3_fs",              Standard
+       "ssp3_rxd",             Standard
+       "ssp3_txd",             Standard
+       "ssp4_clk",             Standard
+       "ssp4_fs",              Standard
+       "ssp4_rxd",             Standard
+       "ssp4_txd",             Standard
+       "ssp5_clk",             Standard
+       "ssp5_fs",              Standard
+       "ssp5_rxd",             Standard
+       "ssp5_txd",             Standard
+       "ssp6_clk",             Standard
+       "ssp6_fs",              Standard
+       "ssp6_rxd",             Standard
+       "ssp6_txd",             Standard
+       "stat_1",               Standard
+       "stat_2",               Standard
+       "sysclken",             Standard
+       "traceclk",             Standard
+       "tracedt00",            Standard
+       "tracedt01",            Standard
+       "tracedt02",            Standard
+       "tracedt03",            Standard
+       "tracedt04",            Standard
+       "tracedt05",            Standard
+       "tracedt06",            Standard
+       "tracedt07",            Standard
+       "tracedt08",            Standard
+       "tracedt09",            Standard
+       "tracedt10",            Standard
+       "tracedt11",            Standard
+       "tracedt12",            Standard
+       "tracedt13",            Standard
+       "tracedt14",            Standard
+       "tracedt15",            Standard
+       "txdata3g0",            Standard
+       "txpwrind",             Standard
+       "uartb1_ucts",          Standard
+       "uartb1_urts",          Standard
+       "uartb1_urxd",          Standard
+       "uartb1_utxd",          Standard
+       "uartb2_urxd",          Standard
+       "uartb2_utxd",          Standard
+       "uartb3_ucts",          Standard
+       "uartb3_urts",          Standard
+       "uartb3_urxd",          Standard
+       "uartb3_utxd",          Standard
+       "uartb4_ucts",          Standard
+       "uartb4_urts",          Standard
+       "uartb4_urxd",          Standard
+       "uartb4_utxd",          Standard
+       "vc_cam1_scl",          I2C
+       "vc_cam1_sda",          I2C
+       "vc_cam2_scl",          I2C
+       "vc_cam2_sda",          I2C
+       "vc_cam3_scl",          I2C
+       "vc_cam3_sda",          I2C
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/brcm,capri-pinctrl.txt
deleted file mode 100644 (file)
index 9e9e9ef..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-Broadcom Capri Pin Controller
-
-This is a pin controller for the Broadcom BCM281xx SoC family, which includes
-BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs.
-
-=== Pin Controller Node ===
-
-Required Properties:
-
-- compatible:  Must be "brcm,capri-pinctrl".
-- reg:         Base address of the PAD Controller register block and the size
-               of the block.
-
-For example, the following is the bare minimum node:
-
-       pinctrl@35004800 {
-               compatible = "brcm,capri-pinctrl";
-               reg = <0x35004800 0x430>;
-       };
-
-As a pin controller device, in addition to the required properties, this node
-should also contain the pin configuration nodes that client devices reference,
-if any.
-
-=== Pin Configuration Node ===
-
-Each pin configuration node is a sub-node of the pin controller node and is a
-container of an arbitrary number of subnodes, called pin group nodes in this
-document.
-
-Please refer to the pinctrl-bindings.txt in this directory for details of the
-common pinctrl bindings used by client devices, including the definition of a
-"pin configuration node".
-
-=== Pin Group Node ===
-
-A pin group node specifies the desired pin mux and/or pin configuration for an
-arbitrary number of pins.  The name of the pin group node is optional and not
-used.
-
-A pin group node only affects the properties specified in the node, and has no
-effect on any properties that are omitted.
-
-The pin group node accepts a subset of the generic pin config properties. For
-details generic pin config properties, please refer to pinctrl-bindings.txt
-and <include/linux/pinctrl/pinconfig-generic.h>.
-
-Each pin controlled by this pin controller belong to one of three types:
-Standard, I2C, and HDMI.  Each type accepts a different set of pin config
-properties.  A list of pins and their types is provided below.
-
-Required Properties (applicable to all pins):
-
-- pins:                Multiple strings.  Specifies the name(s) of one or more pins to
-               be configured by this node.
-
-Optional Properties (for standard pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- input-schmitt-enable:                No arguments. Enable schmitt-trigger mode.
-- input-schmitt-disable:       No arguments. Disable schmitt-trigger mode.
-- bias-pull-up:                        No arguments. Pull up on pin.
-- bias-pull-down:              No arguments. Pull down on pin.
-- bias-disable:                        No arguments. Disable pin bias.
-- slew-rate:                   Integer. Meaning depends on configured pin mux:
-                               *_SCL or *_SDA:
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-                               IC_DM or IC_DP:
-                                       0: normal slew rate
-                                       1: fast slew rate
-                               Otherwise:
-                                       0: fast slew rate
-                                       1: normal slew rate
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-- drive-strength:              Integer. Drive strength in mA.  Valid values are
-                               2, 4, 6, 8, 10, 12, 14, 16 mA.
-
-Optional Properties (for I2C pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- bias-pull-up:                        Integer. Pull up strength in Ohm. There are 3
-                               pull-up resisitors (1.2k, 1.8k, 2.7k) available
-                               in parallel for I2C pins, so the valid values
-                               are: 568, 720, 831, 1080, 1200, 1800, 2700 Ohm.
-- bias-disable:                        No arguments. Disable pin bias.
-- slew-rate:                   Integer. Meaning depends on configured pin mux:
-                               *_SCL or *_SDA:
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-                               IC_DM or IC_DP:
-                                       0: normal slew rate
-                                       1: fast slew rate
-                               Otherwise:
-                                       0: fast slew rate
-                                       1: normal slew rate
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-
-Optional Properties (for HDMI pins):
-
-- function:                    String. Specifies the pin mux selection. Values
-                               must be one of: "alt1", "alt2", "alt3", "alt4"
-- slew-rate:                   Integer. Controls slew rate.
-                                       0: Standard(100kbps)& Fast(400kbps) mode
-                                       1: Highspeed (3.4Mbps) mode
-- input-enable:                        No arguements. Enable input (does not affect
-                               output.)
-- input-disable:               No arguements. Disable input (does not affect
-                               output.)
-
-Example:
-// pin controller node
-pinctrl@35004800 {
-       compatible = "brcm,capri-pinctrl";
-       reg = <0x35004800 0x430>;
-
-       // pin configuration node
-       dev_a_default: dev_a_active {
-               //group node defining 1 standard pin
-               grp_1 {
-                       pins            = "std_pin1";
-                       function        = "alt1";
-                       input-schmitt-enable;
-                       bias-disable;
-                       slew-rate       = <1>;
-                       drive-strength  = <4>;
-               };
-
-               // group node defining 2 I2C pins
-               grp_2 {
-                       pins            = "i2c_pin1", "i2c_pin2";
-                       function        = "alt2";
-                       bias-pull-up    = <720>;
-                       input-enable;
-               };
-
-               // group node defining 2 HDMI pins
-               grp_3 {
-                       pins            = "hdmi_pin1", "hdmi_pin2";
-                       function        = "alt3";
-                       slew-rate       = <1>;
-               };
-
-               // other pin group nodes
-               ...
-       };
-
-       // other pin configuration nodes
-       ...
-};
-
-In the example above, "dev_a_active" is a pin configuration node with a number
-of sub-nodes.  In the pin group node "grp_1", one pin, "std_pin1", is defined in
-the "pins" property.  Thus, the remaining properties in the "grp_1" node applies
-only to this pin, including the following settings:
- - setting pinmux to "alt1"
- - enabling schmitt-trigger (hystersis) mode
- - disabling pin bias
- - setting the slew-rate to 1
- - setting the drive strength to 4 mA
-Note that neither "input-enable" nor "input-disable" was specified - the pinctrl
-subsystem will therefore leave this property unchanged from whatever state it
-was in before applying these changes.
-
-The "pins" property in the pin group node "grp_2" specifies two pins -
-"i2c_pin1" and "i2c_pin2"; the remaining properties in this pin group node,
-therefore, applies to both of these pins.  The properties include:
- - setting pinmux to "alt2"
- - setting pull-up resistance to 720 Ohm (ie. enabling 1.2k and 1.8k resistors
-   in parallel)
- - enabling both pins' input
-"slew-rate" is not specified in this pin group node, so the slew-rate for these
-pins are left as-is.
-
-Finally, "grp_3" defines two HDMI pins.  The following properties are applied to
-both pins:
- - setting pinmux to "alt3"
- - setting slew-rate to 1; for HDMI pins, this corresponds to the 3.4 Mbps
-   Highspeed mode
-The input is neither enabled or disabled, and is left untouched.
-
-=== Pin Names and Type ===
-
-The following are valid pin names and their pin types:
-
-       "adcsync",              Standard
-       "bat_rm",               Standard
-       "bsc1_scl",             I2C
-       "bsc1_sda",             I2C
-       "bsc2_scl",             I2C
-       "bsc2_sda",             I2C
-       "classgpwr",            Standard
-       "clk_cx8",              Standard
-       "clkout_0",             Standard
-       "clkout_1",             Standard
-       "clkout_2",             Standard
-       "clkout_3",             Standard
-       "clkreq_in_0",          Standard
-       "clkreq_in_1",          Standard
-       "cws_sys_req1",         Standard
-       "cws_sys_req2",         Standard
-       "cws_sys_req3",         Standard
-       "digmic1_clk",          Standard
-       "digmic1_dq",           Standard
-       "digmic2_clk",          Standard
-       "digmic2_dq",           Standard
-       "gpen13",               Standard
-       "gpen14",               Standard
-       "gpen15",               Standard
-       "gpio00",               Standard
-       "gpio01",               Standard
-       "gpio02",               Standard
-       "gpio03",               Standard
-       "gpio04",               Standard
-       "gpio05",               Standard
-       "gpio06",               Standard
-       "gpio07",               Standard
-       "gpio08",               Standard
-       "gpio09",               Standard
-       "gpio10",               Standard
-       "gpio11",               Standard
-       "gpio12",               Standard
-       "gpio13",               Standard
-       "gpio14",               Standard
-       "gps_pablank",          Standard
-       "gps_tmark",            Standard
-       "hdmi_scl",             HDMI
-       "hdmi_sda",             HDMI
-       "ic_dm",                Standard
-       "ic_dp",                Standard
-       "kp_col_ip_0",          Standard
-       "kp_col_ip_1",          Standard
-       "kp_col_ip_2",          Standard
-       "kp_col_ip_3",          Standard
-       "kp_row_op_0",          Standard
-       "kp_row_op_1",          Standard
-       "kp_row_op_2",          Standard
-       "kp_row_op_3",          Standard
-       "lcd_b_0",              Standard
-       "lcd_b_1",              Standard
-       "lcd_b_2",              Standard
-       "lcd_b_3",              Standard
-       "lcd_b_4",              Standard
-       "lcd_b_5",              Standard
-       "lcd_b_6",              Standard
-       "lcd_b_7",              Standard
-       "lcd_g_0",              Standard
-       "lcd_g_1",              Standard
-       "lcd_g_2",              Standard
-       "lcd_g_3",              Standard
-       "lcd_g_4",              Standard
-       "lcd_g_5",              Standard
-       "lcd_g_6",              Standard
-       "lcd_g_7",              Standard
-       "lcd_hsync",            Standard
-       "lcd_oe",               Standard
-       "lcd_pclk",             Standard
-       "lcd_r_0",              Standard
-       "lcd_r_1",              Standard
-       "lcd_r_2",              Standard
-       "lcd_r_3",              Standard
-       "lcd_r_4",              Standard
-       "lcd_r_5",              Standard
-       "lcd_r_6",              Standard
-       "lcd_r_7",              Standard
-       "lcd_vsync",            Standard
-       "mdmgpio0",             Standard
-       "mdmgpio1",             Standard
-       "mdmgpio2",             Standard
-       "mdmgpio3",             Standard
-       "mdmgpio4",             Standard
-       "mdmgpio5",             Standard
-       "mdmgpio6",             Standard
-       "mdmgpio7",             Standard
-       "mdmgpio8",             Standard
-       "mphi_data_0",          Standard
-       "mphi_data_1",          Standard
-       "mphi_data_2",          Standard
-       "mphi_data_3",          Standard
-       "mphi_data_4",          Standard
-       "mphi_data_5",          Standard
-       "mphi_data_6",          Standard
-       "mphi_data_7",          Standard
-       "mphi_data_8",          Standard
-       "mphi_data_9",          Standard
-       "mphi_data_10",         Standard
-       "mphi_data_11",         Standard
-       "mphi_data_12",         Standard
-       "mphi_data_13",         Standard
-       "mphi_data_14",         Standard
-       "mphi_data_15",         Standard
-       "mphi_ha0",             Standard
-       "mphi_hat0",            Standard
-       "mphi_hat1",            Standard
-       "mphi_hce0_n",          Standard
-       "mphi_hce1_n",          Standard
-       "mphi_hrd_n",           Standard
-       "mphi_hwr_n",           Standard
-       "mphi_run0",            Standard
-       "mphi_run1",            Standard
-       "mtx_scan_clk",         Standard
-       "mtx_scan_data",        Standard
-       "nand_ad_0",            Standard
-       "nand_ad_1",            Standard
-       "nand_ad_2",            Standard
-       "nand_ad_3",            Standard
-       "nand_ad_4",            Standard
-       "nand_ad_5",            Standard
-       "nand_ad_6",            Standard
-       "nand_ad_7",            Standard
-       "nand_ale",             Standard
-       "nand_cen_0",           Standard
-       "nand_cen_1",           Standard
-       "nand_cle",             Standard
-       "nand_oen",             Standard
-       "nand_rdy_0",           Standard
-       "nand_rdy_1",           Standard
-       "nand_wen",             Standard
-       "nand_wp",              Standard
-       "pc1",                  Standard
-       "pc2",                  Standard
-       "pmu_int",              Standard
-       "pmu_scl",              I2C
-       "pmu_sda",              I2C
-       "rfst2g_mtsloten3g",    Standard
-       "rgmii_0_rx_ctl",       Standard
-       "rgmii_0_rxc",          Standard
-       "rgmii_0_rxd_0",        Standard
-       "rgmii_0_rxd_1",        Standard
-       "rgmii_0_rxd_2",        Standard
-       "rgmii_0_rxd_3",        Standard
-       "rgmii_0_tx_ctl",       Standard
-       "rgmii_0_txc",          Standard
-       "rgmii_0_txd_0",        Standard
-       "rgmii_0_txd_1",        Standard
-       "rgmii_0_txd_2",        Standard
-       "rgmii_0_txd_3",        Standard
-       "rgmii_1_rx_ctl",       Standard
-       "rgmii_1_rxc",          Standard
-       "rgmii_1_rxd_0",        Standard
-       "rgmii_1_rxd_1",        Standard
-       "rgmii_1_rxd_2",        Standard
-       "rgmii_1_rxd_3",        Standard
-       "rgmii_1_tx_ctl",       Standard
-       "rgmii_1_txc",          Standard
-       "rgmii_1_txd_0",        Standard
-       "rgmii_1_txd_1",        Standard
-       "rgmii_1_txd_2",        Standard
-       "rgmii_1_txd_3",        Standard
-       "rgmii_gpio_0",         Standard
-       "rgmii_gpio_1",         Standard
-       "rgmii_gpio_2",         Standard
-       "rgmii_gpio_3",         Standard
-       "rtxdata2g_txdata3g1",  Standard
-       "rtxen2g_txdata3g2",    Standard
-       "rxdata3g0",            Standard
-       "rxdata3g1",            Standard
-       "rxdata3g2",            Standard
-       "sdio1_clk",            Standard
-       "sdio1_cmd",            Standard
-       "sdio1_data_0",         Standard
-       "sdio1_data_1",         Standard
-       "sdio1_data_2",         Standard
-       "sdio1_data_3",         Standard
-       "sdio4_clk",            Standard
-       "sdio4_cmd",            Standard
-       "sdio4_data_0",         Standard
-       "sdio4_data_1",         Standard
-       "sdio4_data_2",         Standard
-       "sdio4_data_3",         Standard
-       "sim_clk",              Standard
-       "sim_data",             Standard
-       "sim_det",              Standard
-       "sim_resetn",           Standard
-       "sim2_clk",             Standard
-       "sim2_data",            Standard
-       "sim2_det",             Standard
-       "sim2_resetn",          Standard
-       "sri_c",                Standard
-       "sri_d",                Standard
-       "sri_e",                Standard
-       "ssp_extclk",           Standard
-       "ssp0_clk",             Standard
-       "ssp0_fs",              Standard
-       "ssp0_rxd",             Standard
-       "ssp0_txd",             Standard
-       "ssp2_clk",             Standard
-       "ssp2_fs_0",            Standard
-       "ssp2_fs_1",            Standard
-       "ssp2_fs_2",            Standard
-       "ssp2_fs_3",            Standard
-       "ssp2_rxd_0",           Standard
-       "ssp2_rxd_1",           Standard
-       "ssp2_txd_0",           Standard
-       "ssp2_txd_1",           Standard
-       "ssp3_clk",             Standard
-       "ssp3_fs",              Standard
-       "ssp3_rxd",             Standard
-       "ssp3_txd",             Standard
-       "ssp4_clk",             Standard
-       "ssp4_fs",              Standard
-       "ssp4_rxd",             Standard
-       "ssp4_txd",             Standard
-       "ssp5_clk",             Standard
-       "ssp5_fs",              Standard
-       "ssp5_rxd",             Standard
-       "ssp5_txd",             Standard
-       "ssp6_clk",             Standard
-       "ssp6_fs",              Standard
-       "ssp6_rxd",             Standard
-       "ssp6_txd",             Standard
-       "stat_1",               Standard
-       "stat_2",               Standard
-       "sysclken",             Standard
-       "traceclk",             Standard
-       "tracedt00",            Standard
-       "tracedt01",            Standard
-       "tracedt02",            Standard
-       "tracedt03",            Standard
-       "tracedt04",            Standard
-       "tracedt05",            Standard
-       "tracedt06",            Standard
-       "tracedt07",            Standard
-       "tracedt08",            Standard
-       "tracedt09",            Standard
-       "tracedt10",            Standard
-       "tracedt11",            Standard
-       "tracedt12",            Standard
-       "tracedt13",            Standard
-       "tracedt14",            Standard
-       "tracedt15",            Standard
-       "txdata3g0",            Standard
-       "txpwrind",             Standard
-       "uartb1_ucts",          Standard
-       "uartb1_urts",          Standard
-       "uartb1_urxd",          Standard
-       "uartb1_utxd",          Standard
-       "uartb2_urxd",          Standard
-       "uartb2_utxd",          Standard
-       "uartb3_ucts",          Standard
-       "uartb3_urts",          Standard
-       "uartb3_urxd",          Standard
-       "uartb3_utxd",          Standard
-       "uartb4_ucts",          Standard
-       "uartb4_urts",          Standard
-       "uartb4_urxd",          Standard
-       "uartb4_utxd",          Standard
-       "vc_cam1_scl",          I2C
-       "vc_cam1_sda",          I2C
-       "vc_cam2_scl",          I2C
-       "vc_cam2_sda",          I2C
-       "vc_cam3_scl",          I2C
-       "vc_cam3_sda",          I2C
diff --git a/Documentation/devicetree/bindings/power/bq2415x.txt b/Documentation/devicetree/bindings/power/bq2415x.txt
new file mode 100644 (file)
index 0000000..d0327f0
--- /dev/null
@@ -0,0 +1,47 @@
+Binding for TI bq2415x Li-Ion Charger
+
+Required properties:
+- compatible: Should contain one of the following:
+ * "ti,bq24150"
+ * "ti,bq24150"
+ * "ti,bq24150a"
+ * "ti,bq24151"
+ * "ti,bq24151a"
+ * "ti,bq24152"
+ * "ti,bq24153"
+ * "ti,bq24153a"
+ * "ti,bq24155"
+ * "ti,bq24156"
+ * "ti,bq24156a"
+ * "ti,bq24158"
+- reg:                    integer, i2c address of the device.
+- ti,current-limit:       integer, initial maximum current charger can pull
+                          from power supply in mA.
+- ti,weak-battery-voltage: integer, weak battery voltage threshold in mV.
+                          The chip will use slow precharge if battery voltage
+                          is below this value.
+- ti,battery-regulation-voltage: integer, maximum charging voltage in mV.
+- ti,charge-current:      integer, maximum charging current in mA.
+- ti,termination-current:  integer, charge will be terminated when current in
+                          constant-voltage phase drops below this value (in mA).
+- ti,resistor-sense:      integer, value of sensing resistor in milliohm.
+
+Optional properties:
+- ti,usb-charger-detection: phandle to usb charger detection device.
+                           (required for auto mode)
+
+Example from Nokia N900:
+
+bq24150a {
+       compatible = "ti,bq24150a";
+       reg = <0x6b>;
+
+       ti,current-limit = <100>;
+       ti,weak-battery-voltage = <3400>;
+       ti,battery-regulation-voltage = <4200>;
+       ti,charge-current = <650>;
+       ti,termination-current = <100>;
+       ti,resistor-sense = <68>;
+
+       ti,usb-charger-detection = <&isp1704>;
+};
index 07e04cdc0c9e0c3619347791f40d1177e6707fe2..4f8184d069cb5a472058a59578101d7b70896367 100644 (file)
@@ -5,6 +5,9 @@ Required properties:
 - reg: Address and length of the register set for the device
 - interrupts: Should contain spi interrupt
 - cs-gpios: chipselects
+- clock-names: tuple listing input clock names.
+       Required elements: "spi_clk"
+- clocks: phandles to input clocks.
 
 Example:
 
@@ -14,6 +17,8 @@ spi1: spi@fffcc000 {
        interrupts = <13 4 5>;
        #address-cells = <1>;
        #size-cells = <0>;
+       clocks = <&spi1_clk>;
+       clock-names = "spi_clk";
        cs-gpios = <&pioB 3 0>;
        status = "okay";
 
index 3f900cd51bf00eb546a765145f671dde71fc3d00..40ce2df0e0e95add31ca573c65fc48227e2c1739 100644 (file)
@@ -8,6 +8,7 @@ ad      Avionic Design GmbH
 adi    Analog Devices, Inc.
 aeroflexgaisler        Aeroflex Gaisler AB
 ak     Asahi Kasei Corp.
+allwinner      Allwinner Technology Co., Ltd.
 altr   Altera Corp.
 amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
 amstaos        AMS-Taos Inc.
@@ -40,6 +41,7 @@ gmt   Global Mixed-mode Technology, Inc.
 gumstix        Gumstix, Inc.
 haoyu  Haoyu Microelectronic Co. Ltd.
 hisilicon      Hisilicon Limited.
+honeywell      Honeywell
 hp     Hewlett Packard
 ibm    International Business Machines (IBM)
 idt    Integrated Device Technologies, Inc.
@@ -55,6 +57,7 @@ maxim Maxim Integrated Products
 microchip      Microchip Technology Inc.
 mosaixtech     Mosaix Technologies, Inc.
 national       National Semiconductor
+neonode                Neonode Inc.
 nintendo       Nintendo
 nvidia NVIDIA
 nxp    NXP Semiconductors
@@ -64,7 +67,7 @@ phytec        PHYTEC Messtechnik GmbH
 picochip       Picochip Ltd
 powervr        PowerVR (deprecated, use img)
 qca    Qualcomm Atheros, Inc.
-qcom   Qualcomm, Inc.
+qcom   Qualcomm Technologies, Inc
 ralink Mediatek/Ralink Technology Corp.
 ramtron        Ramtron International
 realtek Realtek Semiconductor Corp.
@@ -78,6 +81,7 @@ silabs        Silicon Laboratories
 simtek
 sirf   SiRF Technology, Inc.
 snps   Synopsys, Inc.
+spansion       Spansion Inc.
 st     STMicroelectronics
 ste    ST-Ericsson
 stericsson     ST-Ericsson
index 30a70542e8235d5939056e311dd933597ef49e2a..fe85e7c5907a540305b3de5d6c227db5ad0dbdcf 100644 (file)
@@ -5,6 +5,8 @@ please mail me.
 
 00-INDEX
        - this file.
+api.txt
+       - The frame buffer API between applications and buffer devices.
 arkfb.txt
        - info on the fbdev driver for ARK Logic chips.
 aty128fb.txt
@@ -51,12 +53,16 @@ sh7760fb.txt
        - info on the SH7760/SH7763 integrated LCDC Framebuffer driver.
 sisfb.txt
        - info on the framebuffer device driver for various SiS chips.
+sm501.txt
+       - info on the framebuffer device driver for sm501 videoframebuffer.
 sstfb.txt
        - info on the frame buffer driver for 3dfx' Voodoo Graphics boards.
 tgafb.txt
        - info on the TGA (DECChip 21030) frame buffer driver.
 tridentfb.txt
        info on the framebuffer driver for some Trident chip based cards.
+udlfb.txt
+       - Driver for DisplayLink USB 2.0 chips.
 uvesafb.txt
        - info on the userspace VESA (VBE2+ compliant) frame buffer device.
 vesafb.txt
index 632211cbdd569292b4f8c2e47676a0d0b66049a9..ac28149aede4c15704aaee0b1941aebe30f25eb7 100644 (file)
@@ -2,6 +2,8 @@
        - this file (info on some of the filesystems supported by linux).
 Locking
        - info on locking rules as they pertain to Linux VFS.
+Makefile
+       - Makefile for building the filsystems-part of DocBook.
 9p.txt
        - 9p (v9fs) is an implementation of the Plan 9 remote fs protocol.
 adfs.txt
index 66eb6c8c5334518ddbc10115c7b34b4dfb1b3c0e..53f3b596ac0dd93d1d623e35577f1dfb30205394 100644 (file)
@@ -12,6 +12,8 @@ nfs41-server.txt
        - info on the Linux server implementation of NFSv4 minor version 1.
 nfs-rdma.txt
        - how to install and setup the Linux NFS/RDMA client and server software
+nfsd-admin-interfaces.txt
+       - Administrative interfaces for nfsd.
 nfsroot.txt
        - short guide on setting up a diskless box with NFS root filesystem.
 pnfs.txt
@@ -20,5 +22,5 @@ rpc-cache.txt
        - introduction to the caching mechanisms in the sunrpc layer.
 idmapper.txt
        - information for configuring request-keys to be used by idmapper
-knfsd-rpcgss.txt
+rpc-server-gss.txt
        - Information on GSS authentication support in the NFS Server
index c70e7a7638d1e6e66cbddd3cf7800325560cad28..0d85ac1935b73a98251a434054105c6d28eb7334 100644 (file)
@@ -8,8 +8,8 @@ reason, the kernel code must instantiate I2C devices explicitly. There are
 several ways to achieve this, depending on the context and requirements.
 
 
-Method 1: Declare the I2C devices by bus number
------------------------------------------------
+Method 1a: Declare the I2C devices by bus number
+------------------------------------------------
 
 This method is appropriate when the I2C bus is a system bus as is the case
 for many embedded systems. On such systems, each I2C bus has a number
@@ -51,6 +51,43 @@ The devices will be automatically unbound and destroyed when the I2C bus
 they sit on goes away (if ever.)
 
 
+Method 1b: Declare the I2C devices via devicetree
+-------------------------------------------------
+
+This method has the same implications as method 1a. The declaration of I2C
+devices is here done via devicetree as subnodes of the master controller.
+
+Example:
+
+       i2c1: i2c@400a0000 {
+               /* ... master properties skipped ... */
+               clock-frequency = <100000>;
+
+               flash@50 {
+                       compatible = "atmel,24c256";
+                       reg = <0x50>;
+               };
+
+               pca9532: gpio@60 {
+                       compatible = "nxp,pca9532";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       reg = <0x60>;
+               };
+       };
+
+Here, two devices are attached to the bus using a speed of 100kHz. For
+additional properties which might be needed to set up the device, please refer
+to its devicetree documentation in Documentation/devicetree/bindings/.
+
+
+Method 1c: Declare the I2C devices via ACPI
+-------------------------------------------
+
+ACPI can also describe I2C devices. There is special documentation for this
+which is currently located at Documentation/acpi/enumeration.txt.
+
+
 Method 2: Instantiate the devices explicitly
 --------------------------------------------
 
index d6b778842b754c31dbf14460bf6b8ed09ad34c53..22f98ca79539d57ce309d6d33400dffc19b2b9cf 100644 (file)
@@ -10,3 +10,5 @@ ide-tape.txt
        - info on the IDE ATAPI streaming tape driver
 ide.txt
        - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS).
+warm-plug-howto.txt
+       - using sysfs to remove and add IDE devices.
\ No newline at end of file
index fa688538e757e9e1f17f8a3f0374764821e94653..d13b9a9a9e002920ff6835cb56191ac61ccb3a32 100644 (file)
@@ -1,13 +1,15 @@
 00-INDEX
        - This file
-acer-wmi.txt
-       - information on the Acer Laptop WMI Extras driver.
+Makefile
+       - Makefile for building dslm example program.
 asus-laptop.txt
        - information on the Asus Laptop Extras driver.
 disk-shock-protection.txt
        - information on hard disk shock protection.
 dslm.c
        - Simple Disk Sleep Monitor program
+hpfall.c
+       - (HP) laptop accelerometer program for disk protection.
 laptop-mode.txt
        - how to conserve battery power using laptop-mode.
 sony-laptop.txt
index 1ecd1596633e58c1d89398c681b18ec645dc2c97..b4ef1f34e25faafe544971f619019d748538e4de 100644 (file)
@@ -1,3 +1,7 @@
+00-INDEX
+       - This file
+leds-blinkm.txt
+       - Driver for BlinkM LED-devices.
 leds-class.txt
        - documents LED handling under Linux.
 leds-lp3944.txt
@@ -12,3 +16,7 @@ leds-lp55xx.txt
        - description about lp55xx common driver.
 leds-lm3556.txt
        - notes on how to use the leds-lm3556 driver.
+ledtrig-oneshot.txt
+       - One-shot LED trigger for both sporadic and dense events.
+ledtrig-transient.txt
+       - LED Transient Trigger, one shot timer activation.
index a014e9f0076511da0a86ae3f7140a8c420327553..2be8c6b00e74642203a8f4bb085f19adbde5f3b0 100644 (file)
@@ -1,5 +1,7 @@
 00-INDEX
        - this file
+README.buddha
+       - Amiga Buddha and Catweasel IDE Driver
 kernel-options.txt
        - command line options for Linux/m68k
 
index f11580f8719a0cf6d939cbd0fd067c54bc9636db..557b6ef70c265da48afbb3df27b03ca4fef6ea3d 100644 (file)
@@ -6,8 +6,14 @@
        - information on the 3Com Etherlink III Series Ethernet cards.
 6pack.txt
        - info on the 6pack protocol, an alternative to KISS for AX.25
-DLINK.txt
-       - info on the D-Link DE-600/DE-620 parallel port pocket adapters
+LICENSE.qla3xxx
+       - GPLv2 for QLogic Linux Networking HBA Driver
+LICENSE.qlge
+       - GPLv2 for QLogic Linux qlge NIC Driver
+LICENSE.qlcnic
+       - GPLv2 for QLogic Linux qlcnic NIC Driver
+Makefile
+       - Makefile for docsrc.
 PLIP.txt
        - PLIP: The Parallel Line Internet Protocol device driver
 README.ipw2100
@@ -17,7 +23,7 @@ README.ipw2200
 README.sb1000
        - info on General Instrument/NextLevel SURFboard1000 cable modem.
 alias.txt
-       - info on using alias network devices 
+       - info on using alias network devices.
 arcnet-hardware.txt
        - tons of info on ARCnet, hubs, jumper settings for ARCnet cards, etc.
 arcnet.txt
@@ -80,7 +86,7 @@ framerelay.txt
        - info on using Frame Relay/Data Link Connection Identifier (DLCI).
 gen_stats.txt
        - Generic networking statistics for netlink users.
-generic_hdlc.txt
+generic-hdlc.txt
        - The generic High Level Data Link Control (HDLC) layer.
 generic_netlink.txt
        - info on Generic Netlink
@@ -88,6 +94,8 @@ gianfar.txt
        - Gianfar Ethernet Driver.
 i40e.txt
        - README for the Intel Ethernet Controller XL710 Driver (i40e).
+i40evf.txt
+       - Short note on the Driver for the Intel(R) XL710 X710 Virtual Function
 ieee802154.txt
        - Linux IEEE 802.15.4 implementation, API and drivers
 igb.txt
@@ -102,6 +110,8 @@ ipddp.txt
        - AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
 iphase.txt
        - Interphase PCI ATM (i)Chip IA Linux driver info.
+ipsec.txt
+       - Note on not compressing IPSec payload and resulting failed policy check.
 ipv6.txt
        - Options to the ipv6 kernel module.
 ipvs-sysctl.txt
@@ -120,6 +130,8 @@ lapb-module.txt
        - programming information of the LAPB module.
 ltpc.txt
        - the Apple or Farallon LocalTalk PC card driver
+mac80211-auth-assoc-deauth.txt
+       - authentication and association / deauth-disassoc with max80211
 mac80211-injection.txt
        - HOWTO use packet injection with mac80211
 multiqueue.txt
@@ -134,6 +146,10 @@ netdevices.txt
        - info on network device driver functions exported to the kernel.
 netif-msg.txt
        - Design of the network interface message level setting (NETIF_MSG_*).
+netlink_mmap.txt
+       - memory mapped I/O with netlink
+nf_conntrack-sysctl.txt
+       - list of netfilter-sysctl knobs.
 nfc.txt
        - The Linux Near Field Communication (NFS) subsystem.
 openvswitch.txt
@@ -176,7 +192,7 @@ skfp.txt
        - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
 smc9.txt
        - the driver for SMC's 9000 series of Ethernet cards
-spider-net.txt
+spider_net.txt
        - README for the Spidernet Driver (as found in PS3 / Cell BE).
 stmmac.txt
        - README for the STMicro Synopsys Ethernet driver.
@@ -188,6 +204,8 @@ tcp.txt
        - short blurb on how TCP output takes place.
 tcp-thin.txt
        - kernel tuning options for low rate 'thin' TCP streams.
+team.txt
+       - pointer to information for ethernet teaming devices.
 tlan.txt
        - ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info.
 tproxy.txt
@@ -200,6 +218,8 @@ vortex.txt
        - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
 vxge.txt
        - README for the Neterion X3100 PCIe Server Adapter.
+vxlan.txt
+       - Virtual extensible LAN overview
 x25.txt
        - general info on X.25 development.
 x25-iface.txt
diff --git a/Documentation/networking/3c505.txt b/Documentation/networking/3c505.txt
deleted file mode 100644 (file)
index 72f38b1..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-The 3Com Etherlink Plus (3c505) driver.
-
-This driver now uses DMA.  There is currently no support for PIO operation.
-The default DMA channel is 6; this is _not_ autoprobed, so you must
-make sure you configure it correctly.  If loading the driver as a
-module, you can do this with "modprobe 3c505 dma=n".  If the driver is
-linked statically into the kernel, you must either use an "ether="
-statement on the command line, or change the definition of ELP_DMA in 3c505.h.
-
-The driver will warn you if it has to fall back on the compiled in
-default DMA channel. 
-
-If no base address is given at boot time, the driver will autoprobe
-ports 0x300, 0x280 and 0x310 (in that order).  If no IRQ is given, the driver
-will try to probe for it.
-
-The driver can be used as a loadable module.
-
-Theoretically, one instance of the driver can now run multiple cards,
-in the standard way (when loading a module, say "modprobe 3c505
-io=0x300,0x340 irq=10,11 dma=6,7" or whatever).  I have not tested
-this, though.
-
-The driver may now support revision 2 hardware; the dependency on
-being able to read the host control register has been removed.  This
-is also untested, since I don't have a suitable card.
-
-Known problems:
- I still see "DMA upload timed out" messages from time to time.  These
-seem to be fairly non-fatal though.
- The card is old and slow.
-
-To do:
- Improve probe/setup code
- Test multicast and promiscuous operation
-
-Authors:
- The driver is mainly written by Craig Southeren, email
- <craigs@ineluki.apana.org.au>.
- Parts of the driver (adapting the driver to 1.1.4+ kernels,
- IRQ/address detection, some changes) and this README by
- Juha Laiho <jlaiho@ichaos.nullnet.fi>.
- DMA mode, more fixes, etc, by Philip Blundell <pjb27@cam.ac.uk>
- Multicard support, Software configurable DMA, etc., by
- Christopher Collins <ccollins@pcug.org.au>
diff --git a/Documentation/networking/altera_tse.txt b/Documentation/networking/altera_tse.txt
new file mode 100644 (file)
index 0000000..3f24df8
--- /dev/null
@@ -0,0 +1,263 @@
+       Altera Triple-Speed Ethernet MAC driver
+
+Copyright (C) 2008-2014 Altera Corporation
+
+This is the driver for the Altera Triple-Speed Ethernet (TSE) controllers
+using the SGDMA and MSGDMA soft DMA IP components. The driver uses the
+platform bus to obtain component resources. The designs used to test this
+driver were built for a Cyclone(R) V SOC FPGA board, a Cyclone(R) V FPGA board,
+and tested with ARM and NIOS processor hosts seperately. The anticipated use
+cases are simple communications between an embedded system and an external peer
+for status and simple configuration of the embedded system.
+
+For more information visit www.altera.com and www.rocketboards.org. Support
+forums for the driver may be found on www.rocketboards.org, and a design used
+to test this driver may be found there as well. Support is also available from
+the maintainer of this driver, found in MAINTAINERS.
+
+The Triple-Speed Ethernet, SGDMA, and MSGDMA components are all soft IP
+components that can be assembled and built into an FPGA using the Altera
+Quartus toolchain. Quartus 13.1 and 14.0 were used to build the design that
+this driver was tested against. The sopc2dts tool is used to create the
+device tree for the driver, and may be found at rocketboards.org.
+
+The driver probe function examines the device tree and determines if the
+Triple-Speed Ethernet instance is using an SGDMA or MSGDMA component. The
+probe function then installs the appropriate set of DMA routines to
+initialize, setup transmits, receives, and interrupt handling primitives for
+the respective configurations.
+
+The SGDMA component is to be deprecated in the near future (over the next 1-2
+years as of this writing in early 2014) in favor of the MSGDMA component.
+SGDMA support is included for existing designs and reference in case a
+developer wishes to support their own soft DMA logic and driver support. Any
+new designs should not use the SGDMA.
+
+The SGDMA supports only a single transmit or receive operation at a time, and
+therefore will not perform as well compared to the MSGDMA soft IP. Please
+visit www.altera.com for known, documented SGDMA errata.
+
+Scatter-gather DMA is not supported by the SGDMA or MSGDMA at this time.
+Scatter-gather DMA will be added to a future maintenance update to this
+driver.
+
+Jumbo frames are not supported at this time.
+
+The driver limits PHY operations to 10/100Mbps, and has not yet been fully
+tested for 1Gbps. This support will be added in a future maintenance update.
+
+1) Kernel Configuration
+The kernel configuration option is ALTERA_TSE:
+ Device Drivers ---> Network device support ---> Ethernet driver support --->
+ Altera Triple-Speed Ethernet MAC support (ALTERA_TSE)
+
+2) Driver parameters list:
+       debug: message level (0: no output, 16: all);
+       dma_rx_num: Number of descriptors in the RX list (default is 64);
+       dma_tx_num: Number of descriptors in the TX list (default is 64).
+
+3) Command line options
+Driver parameters can be also passed in command line by using:
+       altera_tse=dma_rx_num:128,dma_tx_num:512
+
+4) Driver information and notes
+
+4.1) Transmit process
+When the driver's transmit routine is called by the kernel, it sets up a
+transmit descriptor by calling the underlying DMA transmit routine (SGDMA or
+MSGDMA), and initites a transmit operation. Once the transmit is complete, an
+interrupt is driven by the transmit DMA logic. The driver handles the transmit
+completion in the context of the interrupt handling chain by recycling
+resource required to send and track the requested transmit operation.
+
+4.2) Receive process
+The driver will post receive buffers to the receive DMA logic during driver
+intialization. Receive buffers may or may not be queued depending upon the
+underlying DMA logic (MSGDMA is able queue receive buffers, SGDMA is not able
+to queue receive buffers to the SGDMA receive logic). When a packet is
+received, the DMA logic generates an interrupt. The driver handles a receive
+interrupt by obtaining the DMA receive logic status, reaping receive
+completions until no more receive completions are available.
+
+4.3) Interrupt Mitigation
+The driver is able to mitigate the number of its DMA interrupts
+using NAPI for receive operations. Interrupt mitigation is not yet supported
+for transmit operations, but will be added in a future maintenance release.
+
+4.4) Ethtool support
+Ethtool is supported. Driver statistics and internal errors can be taken using:
+ethtool -S ethX command. It is possible to dump registers etc.
+
+4.5) PHY Support
+The driver is compatible with PAL to work with PHY and GPHY devices.
+
+4.7) List of source files:
+ o Kconfig
+ o Makefile
+ o altera_tse_main.c: main network device driver
+ o altera_tse_ethtool.c: ethtool support
+ o altera_tse.h: private driver structure and common definitions
+ o altera_msgdma.h: MSGDMA implementation function definitions
+ o altera_sgdma.h: SGDMA implementation function definitions
+ o altera_msgdma.c: MSGDMA implementation
+ o altera_sgdma.c: SGDMA implementation
+ o altera_sgdmahw.h: SGDMA register and descriptor definitions
+ o altera_msgdmahw.h: MSGDMA register and descriptor definitions
+ o altera_utils.c: Driver utility functions
+ o altera_utils.h: Driver utility function definitions
+
+5) Debug Information
+
+The driver exports debug information such as internal statistics,
+debug information, MAC and DMA registers etc.
+
+A user may use the ethtool support to get statistics:
+e.g. using: ethtool -S ethX (that shows the statistics counters)
+or sees the MAC registers: e.g. using: ethtool -d ethX
+
+The developer can also use the "debug" module parameter to get
+further debug information.
+
+6) Statistics Support
+
+The controller and driver support a mix of IEEE standard defined statistics,
+RFC defined statistics, and driver or Altera defined statistics. The four
+specifications containing the standard definitions for these statistics are
+as follows:
+
+ o IEEE 802.3-2012 - IEEE Standard for Ethernet.
+ o RFC 2863 found at http://www.rfc-editor.org/rfc/rfc2863.txt.
+ o RFC 2819 found at http://www.rfc-editor.org/rfc/rfc2819.txt.
+ o Altera Triple Speed Ethernet User Guide, found at http://www.altera.com
+
+The statistics supported by the TSE and the device driver are as follows:
+
+"tx_packets" is equivalent to aFramesTransmittedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.2. This statistics is the count of frames that are successfully
+transmitted.
+
+"rx_packets" is equivalent to aFramesReceivedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.5. This statistic is the count of frames that are successfully
+received. This count does not include any error packets such as CRC errors,
+length errors, or alignment errors.
+
+"rx_crc_errors" is equivalent to aFrameCheckSequenceErrors defined in IEEE
+802.3-2012, Section 5.2.2.1.6. This statistic is the count of frames that are
+an integral number of bytes in length and do not pass the CRC test as the frame
+is received.
+
+"rx_align_errors" is equivalent to aAlignmentErrors defined in IEEE 802.3-2012,
+Section 5.2.2.1.7. This statistic is the count of frames that are not an
+integral number of bytes in length and do not pass the CRC test as the frame is
+received.
+
+"tx_bytes" is equivalent to aOctetsTransmittedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.8. This statistic is the count of data and pad bytes
+successfully transmitted from the interface.
+
+"rx_bytes" is equivalent to aOctetsReceivedOK defined in IEEE 802.3-2012,
+Section 5.2.2.1.14. This statistic is the count of data and pad bytes
+successfully received by the controller.
+
+"tx_pause" is equivalent to aPAUSEMACCtrlFramesTransmitted defined in IEEE
+802.3-2012, Section 30.3.4.2. This statistic is a count of PAUSE frames
+transmitted from the network controller.
+
+"rx_pause" is equivalent to aPAUSEMACCtrlFramesReceived defined in IEEE
+802.3-2012, Section 30.3.4.3. This statistic is a count of PAUSE frames
+received by the network controller.
+
+"rx_errors" is equivalent to ifInErrors defined in RFC 2863. This statistic is
+a count of the number of packets received containing errors that prevented the
+packet from being delivered to a higher level protocol.
+
+"tx_errors" is equivalent to ifOutErrors defined in RFC 2863. This statistic
+is a count of the number of packets that could not be transmitted due to errors.
+
+"rx_unicast" is equivalent to ifInUcastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were not addressed
+to the broadcast address or a multicast group.
+
+"rx_multicast" is equivalent to ifInMulticastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were addressed to
+a multicast address group.
+
+"rx_broadcast" is equivalent to ifInBroadcastPkts defined in RFC 2863. This
+statistic is a count of the number of packets received that were addressed to
+the broadcast address.
+
+"tx_discards" is equivalent to ifOutDiscards defined in RFC 2863. This
+statistic is the number of outbound packets not transmitted even though an
+error was not detected. An example of a reason this might occur is to free up
+internal buffer space.
+
+"tx_unicast" is equivalent to ifOutUcastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were not addressed to
+a multicast group or broadcast address.
+
+"tx_multicast" is equivalent to ifOutMulticastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were addressed to a
+multicast group.
+
+"tx_broadcast" is equivalent to ifOutBroadcastPkts defined in RFC 2863. This
+statistic counts the number of packets transmitted that were addressed to a
+broadcast address.
+
+"ether_drops" is equivalent to etherStatsDropEvents defined in RFC 2819.
+This statistic counts the number of packets dropped due to lack of internal
+controller resources.
+
+"rx_total_bytes" is equivalent to etherStatsOctets defined in RFC 2819.
+This statistic counts the total number of bytes received by the controller,
+including error and discarded packets.
+
+"rx_total_packets" is equivalent to etherStatsPkts defined in RFC 2819.
+This statistic counts the total number of packets received by the controller,
+including error, discarded, unicast, multicast, and broadcast packets.
+
+"rx_undersize" is equivalent to etherStatsUndersizePkts defined in RFC 2819.
+This statistic counts the number of correctly formed packets received less
+than 64 bytes long.
+
+"rx_oversize" is equivalent to etherStatsOversizePkts defined in RFC 2819.
+This statistic counts the number of correctly formed packets greater than 1518
+bytes long.
+
+"rx_64_bytes" is equivalent to etherStatsPkts64Octets defined in RFC 2819.
+This statistic counts the total number of packets received that were 64 octets
+in length.
+
+"rx_65_127_bytes" is equivalent to etherStatsPkts65to127Octets defined in RFC
+2819. This statistic counts the total number of packets received that were
+between 65 and 127 octets in length inclusive.
+
+"rx_128_255_bytes" is equivalent to etherStatsPkts128to255Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 128 and 255 octets in length inclusive.
+
+"rx_256_511_bytes" is equivalent to etherStatsPkts256to511Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 256 and 511 octets in length inclusive.
+
+"rx_512_1023_bytes" is equivalent to etherStatsPkts512to1023Octets defined in
+RFC 2819. This statistic is the total number of packets received that were
+between 512 and 1023 octets in length inclusive.
+
+"rx_1024_1518_bytes" is equivalent to etherStatsPkts1024to1518Octets define
+in RFC 2819. This statistic is the total number of packets received that were
+between 1024 and 1518 octets in length inclusive.
+
+"rx_gte_1519_bytes" is a statistic defined specific to the behavior of the
+Altera TSE. This statistics counts the number of received good and errored
+frames between the length of 1519 and the maximum frame length configured
+in the frm_length register. See the Altera TSE User Guide for More details.
+
+"rx_jabbers" is equivalent to etherStatsJabbers defined in RFC 2819. This
+statistic is the total number of packets received that were longer than 1518
+octets, and had either a bad CRC with an integral number of octets (CRC Error)
+or a bad CRC with a non-integral number of octets (Alignment Error).
+
+"rx_runts" is equivalent to etherStatsFragments defined in RFC 2819. This
+statistic is the total number of packets received that were less than 64 octets
+in length and had either a bad CRC with an integral number of octets (CRC
+error) or a bad CRC with a non-integral number of octets (Alignment Error).
index 5cdb22971d19753607739a66108bd85fdf4a492c..a383c00392d03f2e316f7fe7dd954c7d8b71f274 100644 (file)
@@ -270,16 +270,15 @@ arp_ip_target
 arp_validate
 
        Specifies whether or not ARP probes and replies should be
-       validated in the active-backup mode.  This causes the ARP
-       monitor to examine the incoming ARP requests and replies, and
-       only consider a slave to be up if it is receiving the
-       appropriate ARP traffic.
+       validated in any mode that supports arp monitoring, or whether
+       non-ARP traffic should be filtered (disregarded) for link
+       monitoring purposes.
 
        Possible values are:
 
        none or 0
 
-               No validation is performed.  This is the default.
+               No validation or filtering is performed.
 
        active or 1
 
@@ -293,31 +292,68 @@ arp_validate
 
                Validation is performed for all slaves.
 
-       For the active slave, the validation checks ARP replies to
-       confirm that they were generated by an arp_ip_target.  Since
-       backup slaves do not typically receive these replies, the
-       validation performed for backup slaves is on the ARP request
-       sent out via the active slave.  It is possible that some
-       switch or network configurations may result in situations
-       wherein the backup slaves do not receive the ARP requests; in
-       such a situation, validation of backup slaves must be
-       disabled.
-
-       The validation of ARP requests on backup slaves is mainly
-       helping bonding to decide which slaves are more likely to
-       work in case of the active slave failure, it doesn't really
-       guarantee that the backup slave will work if it's selected
-       as the next active slave.
-
-       This option is useful in network configurations in which
-       multiple bonding hosts are concurrently issuing ARPs to one or
-       more targets beyond a common switch.  Should the link between
-       the switch and target fail (but not the switch itself), the
-       probe traffic generated by the multiple bonding instances will
-       fool the standard ARP monitor into considering the links as
-       still up.  Use of the arp_validate option can resolve this, as
-       the ARP monitor will only consider ARP requests and replies
-       associated with its own instance of bonding.
+       filter or 4
+
+               Filtering is applied to all slaves. No validation is
+               performed.
+
+       filter_active or 5
+
+               Filtering is applied to all slaves, validation is performed
+               only for the active slave.
+
+       filter_backup or 6
+
+               Filtering is applied to all slaves, validation is performed
+               only for backup slaves.
+
+       Validation:
+
+       Enabling validation causes the ARP monitor to examine the incoming
+       ARP requests and replies, and only consider a slave to be up if it
+       is receiving the appropriate ARP traffic.
+
+       For an active slave, the validation checks ARP replies to confirm
+       that they were generated by an arp_ip_target.  Since backup slaves
+       do not typically receive these replies, the validation performed
+       for backup slaves is on the broadcast ARP request sent out via the
+       active slave.  It is possible that some switch or network
+       configurations may result in situations wherein the backup slaves
+       do not receive the ARP requests; in such a situation, validation
+       of backup slaves must be disabled.
+
+       The validation of ARP requests on backup slaves is mainly helping
+       bonding to decide which slaves are more likely to work in case of
+       the active slave failure, it doesn't really guarantee that the
+       backup slave will work if it's selected as the next active slave.
+
+       Validation is useful in network configurations in which multiple
+       bonding hosts are concurrently issuing ARPs to one or more targets
+       beyond a common switch.  Should the link between the switch and
+       target fail (but not the switch itself), the probe traffic
+       generated by the multiple bonding instances will fool the standard
+       ARP monitor into considering the links as still up.  Use of
+       validation can resolve this, as the ARP monitor will only consider
+       ARP requests and replies associated with its own instance of
+       bonding.
+
+       Filtering:
+
+       Enabling filtering causes the ARP monitor to only use incoming ARP
+       packets for link availability purposes.  Arriving packets that are
+       not ARPs are delivered normally, but do not count when determining
+       if a slave is available.
+
+       Filtering operates by only considering the reception of ARP
+       packets (any ARP packet, regardless of source or destination) when
+       determining if a slave has received traffic for link availability
+       purposes.
+
+       Filtering is useful in network configurations in which significant
+       levels of third party broadcast traffic would fool the standard
+       ARP monitor into considering the links as still up.  Use of
+       filtering can resolve this, as only ARP traffic is considered for
+       link availability purposes.
 
        This option was added in bonding version 3.1.0.
 
index f3089d4235153b6fa03aaf5c8d09c81043bba996..0cbe6ec22d6ff1d6a3c739f05ae61f4dc24781ec 100644 (file)
@@ -554,12 +554,6 @@ solution for a couple of reasons:
   not specified in the struct can_frame and therefore it is only valid in
   CANFD_MTU sized CAN FD frames.
 
-  As long as the payload length is <=8 the received CAN frames from CAN FD
-  capable CAN devices can be received and read by legacy sockets too. When
-  user-generated CAN FD frames have a payload length <=8 these can be send
-  by legacy CAN network interfaces too. Sending CAN FD frames with payload
-  length > 8 to a legacy CAN network interface returns an -EMSGSIZE error.
-
   Implementation hint for new CAN applications:
 
   To build a CAN FD aware application use struct canfd_frame as basic CAN
index a06b48d2f5cc68c9bd6c37ac0bdb9ce54a69f5b2..81f940f4e88480d48c35fd7707d679d646ef0af8 100644 (file)
@@ -546,6 +546,130 @@ ffffffffa0069c8f + <x>:
 For BPF JIT developers, bpf_jit_disasm, bpf_asm and bpf_dbg provides a useful
 toolchain for developing and testing the kernel's JIT compiler.
 
+BPF kernel internals
+--------------------
+Internally, for the kernel interpreter, a different BPF instruction set
+format with similar underlying principles from BPF described in previous
+paragraphs is being used. However, the instruction set format is modelled
+closer to the underlying architecture to mimic native instruction sets, so
+that a better performance can be achieved (more details later).
+
+It is designed to be JITed with one to one mapping, which can also open up
+the possibility for GCC/LLVM compilers to generate optimized BPF code through
+a BPF backend that performs almost as fast as natively compiled code.
+
+The new instruction set was originally designed with the possible goal in
+mind to write programs in "restricted C" and compile into BPF with a optional
+GCC/LLVM backend, so that it can just-in-time map to modern 64-bit CPUs with
+minimal performance overhead over two steps, that is, C -> BPF -> native code.
+
+Currently, the new format is being used for running user BPF programs, which
+includes seccomp BPF, classic socket filters, cls_bpf traffic classifier,
+team driver's classifier for its load-balancing mode, netfilter's xt_bpf
+extension, PTP dissector/classifier, and much more. They are all internally
+converted by the kernel into the new instruction set representation and run
+in the extended interpreter. For in-kernel handlers, this all works
+transparently by using sk_unattached_filter_create() for setting up the
+filter, resp. sk_unattached_filter_destroy() for destroying it. The macro
+SK_RUN_FILTER(filter, ctx) transparently invokes the right BPF function to
+run the filter. 'filter' is a pointer to struct sk_filter that we got from
+sk_unattached_filter_create(), and 'ctx' the given context (e.g. skb pointer).
+All constraints and restrictions from sk_chk_filter() apply before a
+conversion to the new layout is being done behind the scenes!
+
+Currently, for JITing, the user BPF format is being used and current BPF JIT
+compilers reused whenever possible. In other words, we do not (yet!) perform
+a JIT compilation in the new layout, however, future work will successively
+migrate traditional JIT compilers into the new instruction format as well, so
+that they will profit from the very same benefits. Thus, when speaking about
+JIT in the following, a JIT compiler (TBD) for the new instruction format is
+meant in this context.
+
+Some core changes of the new internal format:
+
+- Number of registers increase from 2 to 10:
+
+  The old format had two registers A and X, and a hidden frame pointer. The
+  new layout extends this to be 10 internal registers and a read-only frame
+  pointer. Since 64-bit CPUs are passing arguments to functions via registers
+  the number of args from BPF program to in-kernel function is restricted
+  to 5 and one register is used to accept return value from an in-kernel
+  function. Natively, x86_64 passes first 6 arguments in registers, aarch64/
+  sparcv9/mips64 have 7 - 8 registers for arguments; x86_64 has 6 callee saved
+  registers, and aarch64/sparcv9/mips64 have 11 or more callee saved registers.
+
+  Therefore, BPF calling convention is defined as:
+
+    * R0       - return value from in-kernel function
+    * R1 - R5  - arguments from BPF program to in-kernel function
+    * R6 - R9  - callee saved registers that in-kernel function will preserve
+    * R10      - read-only frame pointer to access stack
+
+  Thus, all BPF registers map one to one to HW registers on x86_64, aarch64,
+  etc, and BPF calling convention maps directly to ABIs used by the kernel on
+  64-bit architectures.
+
+  On 32-bit architectures JIT may map programs that use only 32-bit arithmetic
+  and may let more complex programs to be interpreted.
+
+  R0 - R5 are scratch registers and BPF program needs spill/fill them if
+  necessary across calls. Note that there is only one BPF program (== one BPF
+  main routine) and it cannot call other BPF functions, it can only call
+  predefined in-kernel functions, though.
+
+- Register width increases from 32-bit to 64-bit:
+
+  Still, the semantics of the original 32-bit ALU operations are preserved
+  via 32-bit subregisters. All BPF registers are 64-bit with 32-bit lower
+  subregisters that zero-extend into 64-bit if they are being written to.
+  That behavior maps directly to x86_64 and arm64 subregister definition, but
+  makes other JITs more difficult.
+
+  32-bit architectures run 64-bit internal BPF programs via interpreter.
+  Their JITs may convert BPF programs that only use 32-bit subregisters into
+  native instruction set and let the rest being interpreted.
+
+  Operation is 64-bit, because on 64-bit architectures, pointers are also
+  64-bit wide, and we want to pass 64-bit values in/out of kernel functions,
+  so 32-bit BPF registers would otherwise require to define register-pair
+  ABI, thus, there won't be able to use a direct BPF register to HW register
+  mapping and JIT would need to do combine/split/move operations for every
+  register in and out of the function, which is complex, bug prone and slow.
+  Another reason is the use of atomic 64-bit counters.
+
+- Conditional jt/jf targets replaced with jt/fall-through:
+
+  While the original design has constructs such as "if (cond) jump_true;
+  else jump_false;", they are being replaced into alternative constructs like
+  "if (cond) jump_true; /* else fall-through */".
+
+- Introduces bpf_call insn and register passing convention for zero overhead
+  calls from/to other kernel functions:
+
+  After a kernel function call, R1 - R5 are reset to unreadable and R0 has a
+  return type of the function. Since R6 - R9 are callee saved, their state is
+  preserved across the call.
+
+Also in the new design, BPF is limited to 4096 insns, which means that any
+program will terminate quickly and will only call a fixed number of kernel
+functions. Original BPF and the new format are two operand instructions,
+which helps to do one-to-one mapping between BPF insn and x86 insn during JIT.
+
+The input context pointer for invoking the interpreter function is generic,
+its content is defined by a specific use case. For seccomp register R1 points
+to seccomp_data, for converted BPF filters R1 points to a skb.
+
+A program, that is translated internally consists of the following elements:
+
+  op:16, jt:8, jf:8, k:32    ==>    op:8, a_reg:4, x_reg:4, off:16, imm:32
+
+Just like the original BPF, the new format runs within a controlled environment,
+is deterministic and the kernel can easily prove that. The safety of the program
+can be determined in two steps: first step does depth-first-search to disallow
+loops and other CFG validation; second step starts from the first insn and
+descends all possible paths. It simulates execution of every insn and observes
+the state change of registers and stack.
+
 Misc
 ----
 
@@ -561,3 +685,4 @@ the underlying architecture.
 
 Jay Schulist <jschlst@samba.org>
 Daniel Borkmann <dborkman@redhat.com>
+Alexei Starovoitov <ast@plumgrid.com>
index ad474ea07d07f1d03674c832cb7436ea1ec6059c..ba1daea7f2e4c67490478c0eae850bd35a08796c 100644 (file)
@@ -1,38 +1,8 @@
 The Gianfar Ethernet Driver
-Sysfs File description
 
 Author: Andy Fleming <afleming@freescale.com>
 Updated: 2005-07-28
 
-SYSFS
-
-Several of the features of the gianfar driver are controlled
-through sysfs files.  These are:
-
-bd_stash:
-To stash RX Buffer Descriptors in the L2, echo 'on' or '1' to
-bd_stash, echo 'off' or '0' to disable
-
-rx_stash_len:
-To stash the first n bytes of the packet in L2, echo the number
-of bytes to buf_stash_len.  echo 0 to disable.
-
-WARNING: You could really screw these up if you set them too low or high!
-fifo_threshold:
-To change the number of bytes the controller needs in the
-fifo before it starts transmission, echo the number of bytes to 
-fifo_thresh.  Range should be 0-511.
-
-fifo_starve:
-When the FIFO has less than this many bytes during a transmit, it
-enters starve mode, and increases the priority of TX memory
-transactions.  To change, echo the number of bytes to
-fifo_starve.  Range should be 0-511.
-
-fifo_starve_off:
-Once in starve mode, the FIFO remains there until it has this
-many bytes.  To change, echo the number of bytes to
-fifo_starve_off.  Range should be 0-511.
 
 CHECKSUM OFFLOADING
 
index 4ebbd659256fbfe3cdf450bfed814066ae2df575..43d3549366a09d6cfbb7e4b284bb01d04fd314a0 100644 (file)
@@ -36,54 +36,6 @@ Default Value: 0
 This parameter adds support for SR-IOV.  It causes the driver to spawn up to
 max_vfs worth of virtual function.
 
-QueuePairs
-----------
-Valid Range:  0-1
-Default Value:  1 (TX and RX will be paired onto one interrupt vector)
-
-If set to 0, when MSI-X is enabled, the TX and RX will attempt to occupy
-separate vectors.
-
-This option can be overridden to 1 if there are not sufficient interrupts
-available.  This can occur if any combination of RSS, VMDQ, and max_vfs
-results in more than 4 queues being used.
-
-Node
-----
-Valid Range:   0-n
-Default Value: -1 (off)
-
-  0 - n: where n is the number of the NUMA node that should be used to
-         allocate memory for this adapter port.
-  -1: uses the driver default of allocating memory on whichever processor is
-      running insmod/modprobe.
-
-  The Node parameter will allow you to pick which NUMA node you want to have
-  the adapter allocate memory from.  All driver structures, in-memory queues,
-  and receive buffers will be allocated on the node specified.  This parameter
-  is only useful when interrupt affinity is specified, otherwise some portion
-  of the time the interrupt could run on a different core than the memory is
-  allocated on, causing slower memory access and impacting throughput, CPU, or
-  both.
-
-EEE
----
-Valid Range:  0-1
-Default Value: 1 (enabled)
-
-  A link between two EEE-compliant devices will result in periodic bursts of
-  data followed by long periods where in the link is in an idle state. This Low
-  Power Idle (LPI) state is supported in both 1Gbps and 100Mbps link speeds.
-  NOTE: EEE support requires autonegotiation.
-
-DMAC
-----
-Valid Range: 0-1
-Default Value: 1 (enabled)
-  Enables or disables DMA Coalescing feature.
-
-
-
 Additional Configurations
 =========================
 
index b26122973525f81e691f2ef05e7069647d6b7e19..c6af4bac5aa8f914a83305831e10f285c1699fb2 100644 (file)
@@ -226,9 +226,9 @@ Ring setup:
        void *rx_ring, *tx_ring;
 
        /* Configure ring parameters */
-       if (setsockopt(fd, NETLINK_RX_RING, &req, sizeof(req)) < 0)
+       if (setsockopt(fd, SOL_NETLINK, NETLINK_RX_RING, &req, sizeof(req)) < 0)
                exit(1);
-       if (setsockopt(fd, NETLINK_TX_RING, &req, sizeof(req)) < 0)
+       if (setsockopt(fd, SOL_NETLINK, NETLINK_TX_RING, &req, sizeof(req)) < 0)
                exit(1)
 
        /* Calculate size of each individual ring */
index 1404674c0a0282af7d077cf55a5da076875bd2ed..6fea79efb4cbfd31cc1d0155aef320b94b89da9e 100644 (file)
@@ -453,7 +453,7 @@ TP_STATUS_COPY        : This flag indicates that the frame (and associated
                         enabled previously with setsockopt() and 
                         the PACKET_COPY_THRESH option. 
 
-                        The number of frames than can be buffered to 
+                        The number of frames that can be buffered to
                         be read with recvfrom is limited like a normal socket.
                         See the SO_RCVBUF option in the socket (7) man page.
 
index ebf2707194029b5f7a44a5f5b4c1c8166e6ac816..3544c98401fd121a1f217160575176960a078760 100644 (file)
@@ -48,7 +48,7 @@ The MDIO bus
    time, so it is safe for them to block, waiting for an interrupt to signal
    the operation is complete
  
- 2) A reset function is necessary.  This is used to return the bus to an
+ 2) A reset function is optional.  This is used to return the bus to an
    initialized state.
 
  3) A probe function is needed.  This function should set up anything the bus
@@ -253,16 +253,25 @@ Writing a PHY driver
 
  Each driver consists of a number of function pointers:
 
+   soft_reset: perform a PHY software reset
    config_init: configures PHY into a sane state after a reset.
      For instance, a Davicom PHY requires descrambling disabled.
    probe: Allocate phy->priv, optionally refuse to bind.
    PHY may not have been reset or had fixups run yet.
    suspend/resume: power management
    config_aneg: Changes the speed/duplex/negotiation settings
+   aneg_done: Determines the auto-negotiation result
    read_status: Reads the current speed/duplex/negotiation settings
    ack_interrupt: Clear a pending interrupt
+   did_interrupt: Checks if the PHY generated an interrupt
    config_intr: Enable or disable interrupts
    remove: Does any driver take-down
+   ts_info: Queries about the HW timestamping status
+   hwtstamp: Set the PHY HW timestamping configuration
+   rxtstamp: Requests a receive timestamp at the PHY level for a 'skb'
+   txtsamp: Requests a transmit timestamp at the PHY level for a 'skb'
+   set_wol: Enable Wake-on-LAN at the PHY level
+   get_wol: Get the Wake-on-LAN status at the PHY level
 
  Of these, only config_aneg and read_status are required to be
  assigned by the driver code.  The rest are optional.  Also, it is
index 5a61a240a6523d64641c0807808a78f8b2eb2e6f..0e30c7845b2b316cb4bb7cdf32807aaf18a55610 100644 (file)
@@ -102,13 +102,18 @@ Examples:
                          The 'minimum' MAC is what you set with dstmac.
 
  pgset "flag [name]"     Set a flag to determine behaviour.  Current flags
-                         are: IPSRC_RND #IP Source is random (between min/max),
-                              IPDST_RND, UDPSRC_RND,
-                              UDPDST_RND, MACSRC_RND, MACDST_RND 
+                         are: IPSRC_RND # IP source is random (between min/max)
+                              IPDST_RND # IP destination is random
+                              UDPSRC_RND, UDPDST_RND,
+                              MACSRC_RND, MACDST_RND
+                              TXSIZE_RND, IPV6,
                               MPLS_RND, VID_RND, SVID_RND
+                              FLOW_SEQ,
                               QUEUE_MAP_RND # queue map random
                               QUEUE_MAP_CPU # queue map mirrors smp_processor_id()
-                              IPSEC # Make IPsec encapsulation for packet
+                              UDPCSUM,
+                              IPSEC # IPsec encapsulation (needs CONFIG_XFRM)
+                              NODE_ALLOC # node specific memory allocation
 
  pgset spi SPI_VALUE     Set specific SA used to transform packet.
 
@@ -233,13 +238,22 @@ udp_dst_max
 
 flag
   IPSRC_RND
-  TXSIZE_RND
   IPDST_RND
   UDPSRC_RND
   UDPDST_RND
   MACSRC_RND
   MACDST_RND
+  TXSIZE_RND
+  IPV6
+  MPLS_RND
+  VID_RND
+  SVID_RND
+  FLOW_SEQ
+  QUEUE_MAP_RND
+  QUEUE_MAP_CPU
+  UDPCSUM
   IPSEC
+  NODE_ALLOC
 
 dst_min
 dst_max
index b89bc82eed4656430ab2d4d4a6454d08ac44624f..16a924c486bf3adb856efc2a2bec72b90311f2ff 100644 (file)
@@ -27,6 +27,8 @@ Contents of this document:
 
  (*) AF_RXRPC kernel interface.
 
+ (*) Configurable parameters.
+
 
 ========
 OVERVIEW
@@ -864,3 +866,82 @@ The kernel interface functions are as follows:
 
      This is used to allocate a null RxRPC key that can be used to indicate
      anonymous security for a particular domain.
+
+
+=======================
+CONFIGURABLE PARAMETERS
+=======================
+
+The RxRPC protocol driver has a number of configurable parameters that can be
+adjusted through sysctls in /proc/net/rxrpc/:
+
+ (*) req_ack_delay
+
+     The amount of time in milliseconds after receiving a packet with the
+     request-ack flag set before we honour the flag and actually send the
+     requested ack.
+
+     Usually the other side won't stop sending packets until the advertised
+     reception window is full (to a maximum of 255 packets), so delaying the
+     ACK permits several packets to be ACK'd in one go.
+
+ (*) soft_ack_delay
+
+     The amount of time in milliseconds after receiving a new packet before we
+     generate a soft-ACK to tell the sender that it doesn't need to resend.
+
+ (*) idle_ack_delay
+
+     The amount of time in milliseconds after all the packets currently in the
+     received queue have been consumed before we generate a hard-ACK to tell
+     the sender it can free its buffers, assuming no other reason occurs that
+     we would send an ACK.
+
+ (*) resend_timeout
+
+     The amount of time in milliseconds after transmitting a packet before we
+     transmit it again, assuming no ACK is received from the receiver telling
+     us they got it.
+
+ (*) max_call_lifetime
+
+     The maximum amount of time in seconds that a call may be in progress
+     before we preemptively kill it.
+
+ (*) dead_call_expiry
+
+     The amount of time in seconds before we remove a dead call from the call
+     list.  Dead calls are kept around for a little while for the purpose of
+     repeating ACK and ABORT packets.
+
+ (*) connection_expiry
+
+     The amount of time in seconds after a connection was last used before we
+     remove it from the connection list.  Whilst a connection is in existence,
+     it serves as a placeholder for negotiated security; when it is deleted,
+     the security must be renegotiated.
+
+ (*) transport_expiry
+
+     The amount of time in seconds after a transport was last used before we
+     remove it from the transport list.  Whilst a transport is in existence, it
+     serves to anchor the peer data and keeps the connection ID counter.
+
+ (*) rxrpc_rx_window_size
+
+     The size of the receive window in packets.  This is the maximum number of
+     unconsumed received packets we're willing to hold in memory for any
+     particular call.
+
+ (*) rxrpc_rx_mtu
+
+     The maximum packet MTU size that we're willing to receive in bytes.  This
+     indicates to the peer whether we're willing to accept jumbo packets.
+
+ (*) rxrpc_rx_jumbo_max
+
+     The maximum number of packets that we're willing to accept in a jumbo
+     packet.  Non-terminal packets in a jumbo packet must contain a four byte
+     header plus exactly 1412 bytes of data.  The terminal packet must contain
+     a four byte header plus any amount of data.  In any event, a jumbo packet
+     may not exceed rxrpc_rx_mtu in size.
index 7d11bb5dc30a7fbb7f4f13317c588e6ae4f00304..bdc4c0db51e1078fb002907124fe7008ef4c0cd4 100644 (file)
@@ -30,7 +30,7 @@ A congestion control mechanism can be registered through functions in
 tcp_cong.c. The functions used by the congestion control mechanism are
 registered via passing a tcp_congestion_ops struct to
 tcp_register_congestion_control. As a minimum name, ssthresh,
-cong_avoid, min_cwnd must be valid.
+cong_avoid must be valid.
 
 Private data for a congestion control mechanism is stored in tp->ca_priv.
 tcp_ca(tp) returns a pointer to this space.  This is preallocated space - it
index 661d3c316a17721d787a8a601f3e9c8356e957be..bc35541249032c4d64c8888741eddc64f87e4f2e 100644 (file)
@@ -21,26 +21,38 @@ has such a feature).
 
 SO_TIMESTAMPING:
 
-Instructs the socket layer which kind of information is wanted. The
-parameter is an integer with some of the following bits set. Setting
-other bits is an error and doesn't change the current state.
-
-SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamp in hardware
-SOF_TIMESTAMPING_TX_SOFTWARE:  if SOF_TIMESTAMPING_TX_HARDWARE is off or
-                               fails, then do it in software
-SOF_TIMESTAMPING_RX_HARDWARE:  return the original, unmodified time stamp
-                               as generated by the hardware
-SOF_TIMESTAMPING_RX_SOFTWARE:  if SOF_TIMESTAMPING_RX_HARDWARE is off or
-                               fails, then do it in software
-SOF_TIMESTAMPING_RAW_HARDWARE: return original raw hardware time stamp
-SOF_TIMESTAMPING_SYS_HARDWARE: return hardware time stamp transformed to
-                               the system time base
-SOF_TIMESTAMPING_SOFTWARE:     return system time stamp generated in
-                               software
-
-SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
-SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
-following control message:
+Instructs the socket layer which kind of information should be collected
+and/or reported.  The parameter is an integer with some of the following
+bits set. Setting other bits is an error and doesn't change the current
+state.
+
+Four of the bits are requests to the stack to try to generate
+timestamps.  Any combination of them is valid.
+
+SOF_TIMESTAMPING_TX_HARDWARE:  try to obtain send time stamps in hardware
+SOF_TIMESTAMPING_TX_SOFTWARE:  try to obtain send time stamps in software
+SOF_TIMESTAMPING_RX_HARDWARE:  try to obtain receive time stamps in hardware
+SOF_TIMESTAMPING_RX_SOFTWARE:  try to obtain receive time stamps in software
+
+The other three bits control which timestamps will be reported in a
+generated control message.  If none of these bits are set or if none of
+the set bits correspond to data that is available, then the control
+message will not be generated:
+
+SOF_TIMESTAMPING_SOFTWARE:     report systime if available
+SOF_TIMESTAMPING_SYS_HARDWARE: report hwtimetrans if available
+SOF_TIMESTAMPING_RAW_HARDWARE: report hwtimeraw if available
+
+It is worth noting that timestamps may be collected for reasons other
+than being requested by a particular socket with
+SOF_TIMESTAMPING_[TR]X_(HARD|SOFT)WARE.  For example, most drivers that
+can generate hardware receive timestamps ignore
+SOF_TIMESTAMPING_RX_HARDWARE.  It is still a good idea to set that flag
+in case future drivers pay attention.
+
+If timestamps are reported, they will appear in a control message with
+cmsg_level==SOL_SOCKET, cmsg_type==SO_TIMESTAMPING, and a payload like
+this:
 
 struct scm_timestamping {
        struct timespec systime;
@@ -190,6 +202,9 @@ Time stamps for outgoing packets are to be generated as follows:
   and not free the skb. A driver not supporting hardware time stamping doesn't
   do that. A driver must never touch sk_buff::tstamp! It is used to store
   software generated time stamps by the network subsystem.
+- Driver should call skb_tx_timestamp() as close to passing sk_buff to hardware
+  as possible. skb_tx_timestamp() provides a software time stamp if requested
+  and hardware timestamping is not possible (SKBTX_IN_PROGRESS not set).
 - As soon as the driver has sent the packet and/or obtained a
   hardware time stamp for it, it passes the time stamp back by
   calling skb_hwtstamp_tx() with the original skb, the raw
@@ -200,6 +215,3 @@ Time stamps for outgoing packets are to be generated as follows:
   this would occur at a later time in the processing pipeline than other
   software time stamping and therefore could lead to unexpected deltas
   between time stamps.
-- If the driver did not set the SKBTX_IN_PROGRESS flag (see above), then
-  dev_hard_start_xmit() checks whether software time stamping
-  is wanted as fallback and potentially generates the time stamp.
index 0103e4b15b0eadb099b091618d19b5d247dcc906..ebff6ee52441edbca95a0ebc8b20cd49ac218d3d 100644 (file)
@@ -75,14 +75,26 @@ Before the controller can make use of the PHY, it has to get a reference to
 it. This framework provides the following APIs to get a reference to the PHY.
 
 struct phy *phy_get(struct device *dev, const char *string);
+struct phy *phy_optional_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
-
-phy_get and devm_phy_get can be used to get the PHY. In the case of dt boot,
-the string arguments should contain the phy name as given in the dt data and
-in the case of non-dt boot, it should contain the label of the PHY.
-The only difference between the two APIs is that devm_phy_get associates the
-device with the PHY using devres on successful PHY get. On driver detach,
-release function is invoked on the the devres data and devres data is freed.
+struct phy *devm_phy_optional_get(struct device *dev, const char *string);
+
+phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
+be used to get the PHY. In the case of dt boot, the string arguments
+should contain the phy name as given in the dt data and in the case of
+non-dt boot, it should contain the label of the PHY.  The two
+devm_phy_get associates the device with the PHY using devres on
+successful PHY get. On driver detach, release function is invoked on
+the the devres data and devres data is freed. phy_optional_get and
+devm_phy_optional_get should be used when the phy is optional. These
+two functions will never return -ENODEV, but instead returns NULL when
+the phy cannot be found.
+
+It should be noted that NULL is a valid phy reference. All phy
+consumer calls on the NULL phy become NOPs. That is the release calls,
+the phy_init() and phy_exit() calls, and phy_power_on() and
+phy_power_off() calls are all NOP when applied to a NULL phy. The NULL
+phy is useful in devices for handling optional phy devices.
 
 5. Releasing a reference to the PHY
 
index a4d682f54231d01eafdbb23ebab39d571a409c52..ad04cc8097ed97ffbf1ae6189e92a20ef7ca9de9 100644 (file)
@@ -4,6 +4,8 @@ apm-acpi.txt
        - basic info about the APM and ACPI support.
 basic-pm-debugging.txt
        - Debugging suspend and resume
+charger-manager.txt
+       - Battery charger management.
 devices.txt
        - How drivers interact with system-wide power management
 drivers-testing.txt
@@ -22,6 +24,8 @@ pm_qos_interface.txt
        - info on Linux PM Quality of Service interface
 power_supply_class.txt
        - Tells userspace about battery, UPS, AC or DC power supply properties
+runtime_pm.txt
+       - Power management framework for I/O devices.
 s2ram.txt
        - How to get suspend to ram working (and debug it when it isn't)
 states.txt
@@ -38,7 +42,5 @@ tricks.txt
        - How to trick software suspend (to disk) into working when it isn't
 userland-swsusp.txt
        - Experimental implementation of software suspend in userspace
-video_extension.txt
-       - ACPI video extensions
 video.txt
        - Video issues during resume from suspend
index a74d0a84d329a2909186256d9ad5fdb5f5327a2e..f1ac2dae999e008ca7175b2eee0c482f144b9f12 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <math.h>
 #include <signal.h>
 #include <stdio.h>
@@ -117,13 +118,22 @@ static void usage(char *progname)
                " -f val     adjust the ptp clock frequency by 'val' ppb\n"
                " -g         get the ptp clock time\n"
                " -h         prints this message\n"
+               " -i val     index for event/trigger\n"
                " -k val     measure the time offset between system and phc clock\n"
                "            for 'val' times (Maximum 25)\n"
+               " -l         list the current pin configuration\n"
+               " -L pin,val configure pin index 'pin' with function 'val'\n"
+               "            the channel index is taken from the '-i' option\n"
+               "            'val' specifies the auxiliary function:\n"
+               "            0 - none\n"
+               "            1 - external time stamp\n"
+               "            2 - periodic output\n"
                " -p val     enable output with a period of 'val' nanoseconds\n"
                " -P val     enable or disable (val=1|0) the system clock PPS\n"
                " -s         set the ptp clock time from the system time\n"
                " -S         set the system time from the ptp clock time\n"
-               " -t val     shift the ptp clock time by 'val' seconds\n",
+               " -t val     shift the ptp clock time by 'val' seconds\n"
+               " -T val     set the ptp clock time to 'val' seconds\n",
                progname);
 }
 
@@ -133,6 +143,7 @@ int main(int argc, char *argv[])
        struct ptp_extts_event event;
        struct ptp_extts_request extts_request;
        struct ptp_perout_request perout_request;
+       struct ptp_pin_desc desc;
        struct timespec ts;
        struct timex tx;
 
@@ -154,12 +165,16 @@ int main(int argc, char *argv[])
        int capabilities = 0;
        int extts = 0;
        int gettime = 0;
+       int index = 0;
+       int list_pins = 0;
        int oneshot = 0;
        int pct_offset = 0;
        int n_samples = 0;
        int periodic = 0;
        int perout = -1;
+       int pin_index = -1, pin_func;
        int pps = -1;
+       int seconds = 0;
        int settime = 0;
 
        int64_t t1, t2, tp;
@@ -167,7 +182,7 @@ int main(int argc, char *argv[])
 
        progname = strrchr(argv[0], '/');
        progname = progname ? 1+progname : argv[0];
-       while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghk:p:P:sSt:v"))) {
+       while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
                switch (c) {
                case 'a':
                        oneshot = atoi(optarg);
@@ -190,10 +205,23 @@ int main(int argc, char *argv[])
                case 'g':
                        gettime = 1;
                        break;
+               case 'i':
+                       index = atoi(optarg);
+                       break;
                case 'k':
                        pct_offset = 1;
                        n_samples = atoi(optarg);
                        break;
+               case 'l':
+                       list_pins = 1;
+                       break;
+               case 'L':
+                       cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
+                       if (cnt != 2) {
+                               usage(progname);
+                               return -1;
+                       }
+                       break;
                case 'p':
                        perout = atoi(optarg);
                        break;
@@ -209,6 +237,10 @@ int main(int argc, char *argv[])
                case 't':
                        adjtime = atoi(optarg);
                        break;
+               case 'T':
+                       settime = 3;
+                       seconds = atoi(optarg);
+                       break;
                case 'h':
                        usage(progname);
                        return 0;
@@ -240,12 +272,14 @@ int main(int argc, char *argv[])
                               "  %d programmable alarms\n"
                               "  %d external time stamp channels\n"
                               "  %d programmable periodic signals\n"
-                              "  %d pulse per second\n",
+                              "  %d pulse per second\n"
+                              "  %d programmable pins\n",
                               caps.max_adj,
                               caps.n_alarm,
                               caps.n_ext_ts,
                               caps.n_per_out,
-                              caps.pps);
+                              caps.pps,
+                              caps.n_pins);
                }
        }
 
@@ -299,9 +333,19 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (settime == 3) {
+               ts.tv_sec = seconds;
+               ts.tv_nsec = 0;
+               if (clock_settime(clkid, &ts)) {
+                       perror("clock_settime");
+               } else {
+                       puts("set time okay");
+               }
+       }
+
        if (extts) {
                memset(&extts_request, 0, sizeof(extts_request));
-               extts_request.index = 0;
+               extts_request.index = index;
                extts_request.flags = PTP_ENABLE_FEATURE;
                if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
                        perror("PTP_EXTTS_REQUEST");
@@ -326,6 +370,24 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (list_pins) {
+               int n_pins = 0;
+               if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+                       perror("PTP_CLOCK_GETCAPS");
+               } else {
+                       n_pins = caps.n_pins;
+               }
+               for (i = 0; i < n_pins; i++) {
+                       desc.index = i;
+                       if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
+                               perror("PTP_PIN_GETFUNC");
+                               break;
+                       }
+                       printf("name %s index %u func %u chan %u\n",
+                              desc.name, desc.index, desc.func, desc.chan);
+               }
+       }
+
        if (oneshot) {
                install_handler(SIGALRM, handle_alarm);
                /* Create a timer. */
@@ -375,7 +437,7 @@ int main(int argc, char *argv[])
                        return -1;
                }
                memset(&perout_request, 0, sizeof(perout_request));
-               perout_request.index = 0;
+               perout_request.index = index;
                perout_request.start.sec = ts.tv_sec + 2;
                perout_request.start.nsec = 0;
                perout_request.period.sec = 0;
@@ -387,6 +449,18 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (pin_index >= 0) {
+               memset(&desc, 0, sizeof(desc));
+               desc.index = pin_index;
+               desc.func = pin_func;
+               desc.chan = index;
+               if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
+                       perror("PTP_PIN_SETFUNC");
+               } else {
+                       puts("set pin function okay");
+               }
+       }
+
        if (pps != -1) {
                int enable = pps ? 1 : 0;
                if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
@@ -423,14 +497,14 @@ int main(int argc, char *argv[])
                        interval = t2 - t1;
                        offset = (t2 + t1) / 2 - tp;
 
-                       printf("system time: %ld.%ld\n",
+                       printf("system time: %" PRId64 ".%u\n",
                                (pct+2*i)->sec, (pct+2*i)->nsec);
-                       printf("phc    time: %ld.%ld\n",
+                       printf("phc    time: %" PRId64 ".%u\n",
                                (pct+2*i+1)->sec, (pct+2*i+1)->nsec);
-                       printf("system time: %ld.%ld\n",
+                       printf("system time: %" PRId64 ".%u\n",
                                (pct+2*i+2)->sec, (pct+2*i+2)->nsec);
-                       printf("system/phc clock time offset is %ld ns\n"
-                               "system     clock time delay  is %ld ns\n",
+                       printf("system/phc clock time offset is %" PRId64 " ns\n"
+                              "system     clock time delay  is %" PRId64 " ns\n",
                                offset, interval);
                }
 
index 3a2b96302eccc5dfb07ab4d755ba3d209efe0bc2..10c874ebdfe5293a0da287ac2037a46904f23bc4 100644 (file)
@@ -16,11 +16,13 @@ Debugging390.txt
        - hints for debugging on s390 systems.
 driver-model.txt
        - information on s390 devices and the driver model.
+kvm.txt
+       - ioctl calls to /dev/kvm on s390.
 monreader.txt
        - information on accessing the z/VM monitor stream from Linux.
+qeth.txt
+       - HiperSockets Bridge Port Support.
 s390dbf.txt
        - information on using the s390 debug feature.
-TAPE
-       - information on the driver for channel-attached tapes.
-zfcpdump
+zfcpdump.txt
        - information on the s390 SCSI dump tool.
index 46702e4f89c937d3d5a900b2da0f8af57163bc7f..eccf7ad2e7f96b8976dd9e7a06e726f5c5d4b4a1 100644 (file)
@@ -2,6 +2,8 @@
        - this file.
 sched-arch.txt
        - CPU Scheduler implementation hints for architecture specific code.
+sched-bwc.txt
+       - CFS bandwidth control overview.
 sched-design-CFS.txt
        - goals, design and implementation of the Completely Fair Scheduler.
 sched-domains.txt
index 2044be565d93b934a232d133d5e63cc4c430270a..c4b978a72f78d4e8adda44ba88e3fad0455884f5 100644 (file)
@@ -36,6 +36,8 @@ NinjaSCSI.txt
        - info on WorkBiT NinjaSCSI-32/32Bi driver
 aacraid.txt
        - Driver supporting Adaptec RAID controllers
+advansys.txt
+       - List of Advansys Host Adapters
 aha152x.txt
        - info on driver for Adaptec AHA152x based adapters
 aic79xx.txt
@@ -44,6 +46,12 @@ aic7xxx.txt
        - info on driver for Adaptec controllers
 arcmsr_spec.txt
        - ARECA FIRMWARE SPEC (for IOP331 adapter)
+bfa.txt
+       - Brocade FC/FCOE adapter driver.
+bnx2fc.txt
+       - FCoE hardware offload for Broadcom network interfaces.
+cxgb3i.txt
+       - Chelsio iSCSI Linux Driver
 dc395x.txt
        - README file for the dc395x SCSI driver
 dpti.txt
@@ -52,18 +60,24 @@ dtc3x80.txt
        - info on driver for DTC 2x80 based adapters
 g_NCR5380.txt
        - info on driver for NCR5380 and NCR53c400 based adapters
+hpsa.txt
+       - HP Smart Array Controller SCSI driver.
 hptiop.txt
        - HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
 in2000.txt
        - info on in2000 driver
 libsas.txt
        - Serial Attached SCSI management layer.
+link_power_management_policy.txt
+       - Link power management options.
 lpfc.txt
        - LPFC driver release notes
 megaraid.txt
        - Common Management Module, shared code handling ioctls for LSI drivers
 ncr53c8xx.txt
        - info on driver for NCR53c8xx based adapters
+osd.txt
+       Object-Based Storage Device, command set introduction.
 osst.txt
        - info on driver for OnStream SC-x0 SCSI tape
 ppa.txt
@@ -74,6 +88,8 @@ scsi-changer.txt
        - README for the SCSI media changer driver
 scsi-generic.txt
        - info on the sg driver for generic (non-disk/CD/tape) SCSI devices.
+scsi-parameters.txt
+       - List of SCSI-parameters to pass to the kernel at module load-time.
 scsi.txt
        - short blurb on using SCSI support as a module.
 scsi_mid_low_api.txt
index 1f1b22fbd73935d8677fa959ecb8e8d1b7b2dd3c..f9c6b5ed03e7f0809b7ebe2558474ce394c523e5 100644 (file)
@@ -4,10 +4,12 @@ README.cycladesZ
        - info on Cyclades-Z firmware loading.
 digiepca.txt
        - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
-hayes-esp.txt
-       - info on using the Hayes ESP serial driver.
+driver
+       - intro to the low level serial driver.
 moxa-smartio
        - file with info on installing/using Moxa multiport serial driver.
+n_gsm.txt
+       - GSM 0710 tty multiplexer howto.
 riscom8.txt
        - notes on using the RISCom/8 multi-port serial driver.
 rocket.txt
diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX
new file mode 100644 (file)
index 0000000..a128fa8
--- /dev/null
@@ -0,0 +1,22 @@
+00-INDEX
+       - this file.
+Makefile
+       - Makefile for the example sourcefiles.
+butterfly
+       - AVR Butterfly SPI driver overview and pin configuration.
+ep93xx_spi
+       - Basic EP93xx SPI driver configuration.
+pxa2xx
+       - PXA2xx SPI master controller build by spi_message fifo wq
+spidev
+       - Intro to the userspace API for spi devices
+spidev_fdx.c
+       - spidev example file
+spi-lm70llp
+       - Connecting an LM70-LLP sensor to the kernel via the SPI subsys.
+spi-sc18is602
+       - NXP SC18IS602/603 I2C-bus to SPI bridge
+spi-summary
+       - (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here.
+spidev_test.c
+       - SPI testing utility.
index f72e0d1e0da852ac3e89e97f8bd0c22055d66608..7982bcc4d151adfa6f0782182a84a482b8d976a0 100644 (file)
@@ -543,7 +543,22 @@ SPI MASTER METHODS
        queuing transfers that arrive in the meantime. When the driver is
        finished with this message, it must call
        spi_finalize_current_message() so the subsystem can issue the next
-       transfer. This may sleep.
+       message. This may sleep.
+
+    master->transfer_one(struct spi_master *master, struct spi_device *spi,
+                        struct spi_transfer *transfer)
+       The subsystem calls the driver to transfer a single transfer while
+       queuing transfers that arrive in the meantime. When the driver is
+       finished with this transfer, it must call
+       spi_finalize_current_transfer() so the subsystem can issue the next
+       transfer. This may sleep. Note: transfer_one and transfer_one_message
+       are mutually exclusive; when both are set, the generic subsystem does
+       not call your transfer_one callback.
+
+       Return values:
+       negative errno: error
+       0: transfer is finished
+       1: transfer is still in progress
 
     DEPRECATED METHODS
 
index ef2ccbf77fa2d4e8b8152d844d3a24de8fb54045..6d042dc1cce0db6d2862200e456f6d7b3324af4e 100644 (file)
@@ -8,6 +8,8 @@ hpet_example.c
        - sample hpet timer test program
 hrtimers.txt
        - subsystem for high-resolution kernel timers
+Makefile
+       - Build and link hpet_example
 NO_HZ.txt
        - Summary of the different methods for the scheduler clock-interrupts management.
 timers-howto.txt
index 641ec922017993ec1aaa75f19b08dcb76c2f49cf..fee9f2bf9c64a825c068046c5b7100d62c5757e9 100644 (file)
@@ -20,5 +20,7 @@ ppc-pv.txt
        - the paravirtualization interface on PowerPC.
 review-checklist.txt
        - review checklist for KVM patches.
+s390-diag.txt
+       - Diagnose hypercall description (for IBM S/390)
 timekeeping.txt
        - timekeeping virtualization for x86-based architectures.
index a39d06680e1c1a738437dfafdb36f1fda29b2f66..081c49777abb81e54bc6bfee8b2ae553b3954b3e 100644 (file)
@@ -16,8 +16,6 @@ hwpoison.txt
        - explains what hwpoison is
 ksm.txt
        - how to use the Kernel Samepage Merging feature.
-locking
-       - info on how locking and synchronization is done in the Linux vm code.
 numa
        - information about NUMA specific code in the Linux vm.
 numa_memory_policy.txt
@@ -32,6 +30,8 @@ slub.txt
        - a short users guide for SLUB.
 soft-dirty.txt
        - short explanation for soft-dirty PTEs
+split_page_table_lock
+       - Separate per-table lock to improve scalability of the old page_table_lock.
 transhuge.txt
        - Transparent Hugepage Support, alternative way of using hugepages.
 unevictable-lru.txt
index d63fa024ac05901252a3ea9af825c85b866845e3..8330cf9325f0ad6da97b4bdc1c8e02414bfa9cbc 100644 (file)
@@ -4,7 +4,9 @@ ds2482
        - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
 ds2490
        - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
-mxc_w1
+mxc-w1
        - W1 master controller driver found on Freescale MX2/MX3 SoCs
+omap-hdq
+       - HDQ/1-wire module of TI OMAP 2430/3430.
 w1-gpio
        - GPIO 1-wire bus master driver.
index 75613c9ac4dbe2eae00d12d15b043bfc47720a6c..6e18c70c347488756987040d73e6f1e790c11ed6 100644 (file)
@@ -4,3 +4,5 @@ w1_therm
        - The Maxim/Dallas Semiconductor ds18*20 temperature sensor.
 w1_ds2423
        - The Maxim/Dallas Semiconductor ds2423 counter device.
+w1_ds28e04
+       - The Maxim/Dallas Semiconductor ds28e04 eeprom.
index f37b46d348614be9fc5a0b54a8c303617e979d56..692264456f0f6cd2bce609207251472c3fcc9005 100644 (file)
@@ -1,6 +1,20 @@
 00-INDEX
        - this file
-mtrr.txt
-       - how to use x86 Memory Type Range Registers to increase performance
+boot.txt
+       - List of boot protocol versions
+early-microcode.txt
+       - How to load microcode from an initrd-CPIO archive early to fix CPU issues.
+earlyprintk.txt
+       - Using earlyprintk with a USB2 debug port key.
+entry_64.txt
+       - Describe (some of the) kernel entry points for x86.
 exception-tables.txt
        - why and how Linux kernel uses exception tables on x86
+mtrr.txt
+       - how to use x86 Memory Type Range Registers to increase performance
+pat.txt
+       - Page Attribute Table intro and API
+usb-legacy-support.txt
+       - how to fix/avoid quirks when using emulated PS/2 mouse/keyboard.
+zero-page.txt
+       - layout of the first page of memory.
index 28fa325b74617f513e3b2cd478f1b03d5a6edd62..6f6d956ac1c9724bd47fd6a5a77d22f09fe1cd9b 100644 (file)
@@ -7,7 +7,7 @@ help.  Contact the Chinese maintainer if this translation is outdated
 or if there is a problem with the translation.
 
 Maintainer: Will Deacon <will.deacon@arm.com>
-Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
 ---------------------------------------------------------------------
 Documentation/arm64/booting.txt 的中文翻译
 
@@ -16,9 +16,9 @@ Documentation/arm64/booting.txt 的中文翻译
 译存在问题,请联系中文版维护者。
 
 英文版维护者: Will Deacon <will.deacon@arm.com>
-中文版维护者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
-中文版翻译者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
-中文版校译者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
+中文版维护者: 傅炜  Fu Wei <wefu@redhat.com>
+中文版翻译者: 傅炜  Fu Wei <wefu@redhat.com>
+中文版校译者: 傅炜  Fu Wei <wefu@redhat.com>
 
 以下为正文
 ---------------------------------------------------------------------
@@ -64,8 +64,8 @@ RAM,或可能使用对这个设备已知的 RAM 信息,还可能使用任何
 
 必要性: 强制
 
-设å¤\87æ \91æ\95°æ\8d®å\9d\97ï¼\88dtbï¼\89大å°\8få¿\85é¡»ä¸\8d大äº\8e 2 MBï¼\8cä¸\94ä½\8däº\8eä»\8eå\86\85æ ¸æ\98 å\83\8fèµ·å§\8bç®\97起第ä¸\80个
-512MB 内的 2MB 边界上。这使得内核可以通过初始页表中的单个节描述符来
+设å¤\87æ \91æ\95°æ\8d®å\9d\97ï¼\88dtbï¼\89å¿\85é¡» 8 å­\97è\8a\82对é½\90ï¼\8c并ä½\8däº\8eä»\8eå\86\85æ ¸æ\98 å\83\8fèµ·å§\8bç®\97起第ä¸\80个 512MB
+内,且不得跨越 2MB 对齐边界。这使得内核可以通过初始页表中的单个节描述符来
 映射此数据块。
 
 
@@ -84,13 +84,23 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
 
 必要性: 强制
 
-已解压的内核映像包含一个 32 字节的头,内容如下:
+已解压的内核映像包含一个 64 字节的头,内容如下:
 
-  u32 magic    = 0x14000008;   /* 跳转到 stext, 小端 */
-  u32 res0     = 0;            /* 保留 */
+  u32 code0;                   /* 可执行代码 */
+  u32 code1;                   /* 可执行代码 */
   u64 text_offset;             /* 映像装载偏移 */
+  u64 res0     = 0;            /* 保留 */
   u64 res1     = 0;            /* 保留 */
   u64 res2     = 0;            /* 保留 */
+  u64 res3     = 0;            /* 保留 */
+  u64 res4     = 0;            /* 保留 */
+  u32 magic    = 0x644d5241;   /* 魔数, 小端, "ARM\x64" */
+  u32 res5 = 0;                /* 保留 */
+
+
+映像头注释:
+
+- code0/code1 负责跳转到 stext.
 
 映像必须位于系统 RAM 起始处的特定偏移(当前是 0x80000)。系统 RAM
 的起始地址必须是以 2MB 对齐的。
@@ -118,9 +128,9 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
   外部高速缓存(如果存在)必须配置并禁用。
 
 - 架构计时器
-  CNTFRQ 必须设定为计时器的频率
-  如果在 EL1 模式下进入内核,则 CNTHCTL_EL2 中的 EL1PCTEN (bit 0)
-  必须置位。
+  CNTFRQ 必须设定为计时器的频率,且 CNTVOFF 必须设定为对所有 CPU
+  都一致的值。如果在 EL1 模式下进入内核,则 CNTHCTL_EL2 中的
+  EL1PCTEN (bit 0) 必须置位。
 
 - 一致性
   通过内核启动的所有 CPU 在内核入口地址上必须处于相同的一致性域中。
@@ -131,23 +141,40 @@ AArch64 内核当前没有提供自解压代码,因此如果使用了压缩内
   在进入内核映像的异常级中,所有构架中可写的系统寄存器必须通过软件
   在一个更高的异常级别下初始化,以防止在 未知 状态下运行。
 
+以上对于 CPU 模式、高速缓存、MMU、架构计时器、一致性、系统寄存器的
+必要条件描述适用于所有 CPU。所有 CPU 必须在同一异常级别跳入内核。
+
 引导装载程序必须在每个 CPU 处于以下状态时跳入内核入口:
 
 - 主 CPU 必须直接跳入内核映像的第一条指令。通过此 CPU 传递的设备树
-  数据块必须在每个 CPU 节点中包含以下内容:
-
-    1、‘enable-method’属性。目前,此字段支持的值仅为字符串“spin-table”。
-
-    2、‘cpu-release-addr’标识一个 64-bit、初始化为零的内存位置。
+  数据块必须在每个 CPU 节点中包含一个 ‘enable-method’ 属性,所
+  支持的 enable-method 请见下文。
 
   引导装载程序必须生成这些设备树属性,并在跳入内核入口之前将其插入
   数据块。
 
-- 任何辅助 CPU 必须在内存保留区(通过设备树中的 /memreserve/ 域传递
+- enable-method 为 “spin-table” 的 CPU 必须在它们的 CPU
+  节点中包含一个 ‘cpu-release-addr’ 属性。这个属性标识了一个
+  64 位自然对齐且初始化为零的内存位置。
+
+  这些 CPU 必须在内存保留区(通过设备树中的 /memreserve/ 域传递
   给内核)中自旋于内核之外,轮询它们的 cpu-release-addr 位置(必须
   包含在保留区中)。可通过插入 wfe 指令来降低忙循环开销,而主 CPU 将
   发出 sev 指令。当对 cpu-release-addr 所指位置的读取操作返回非零值
-  时,CPU 必须直接跳入此值所指向的地址。
+  时,CPU 必须跳入此值所指向的地址。此值为一个单独的 64 位小端值,
+  因此 CPU 须在跳转前将所读取的值转换为其本身的端模式。
+
+- enable-method 为 “psci” 的 CPU 保持在内核外(比如,在
+  memory 节点中描述为内核空间的内存区外,或在通过设备树 /memreserve/
+  域中描述为内核保留区的空间中)。内核将会发起在 ARM 文档(编号
+  ARM DEN 0022A:用于 ARM 上的电源状态协调接口系统软件)中描述的
+  CPU_ON 调用来将 CPU 带入内核。
+
+  *译者注:到文档翻译时,此文档已更新为 ARM DEN 0022B。
+
+  设备树必须包含一个 ‘psci’ 节点,请参考以下文档:
+  Documentation/devicetree/bindings/arm/psci.txt
+
 
 - 辅助 CPU 通用寄存器设置
   x0 = 0 (保留,将来可能使用)
index a5f6283829f9c90bb9d3de64d414589192d01788..a782704c1cb59ab868de82d573291ac8780f6297 100644 (file)
@@ -7,7 +7,7 @@ help.  Contact the Chinese maintainer if this translation is outdated
 or if there is a problem with the translation.
 
 Maintainer: Catalin Marinas <catalin.marinas@arm.com>
-Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
 ---------------------------------------------------------------------
 Documentation/arm64/memory.txt 的中文翻译
 
@@ -16,9 +16,9 @@ Documentation/arm64/memory.txt 的中文翻译
 译存在问题,请联系中文版维护者。
 
 英文版维护者: Catalin Marinas <catalin.marinas@arm.com>
-中文版维护者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
-中文版翻译者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
-中文版校译者: 傅炜  Fu Wei <tekkamanninja@gmail.com>
+中文版维护者: 傅炜  Fu Wei <wefu@redhat.com>
+中文版翻译者: 傅炜  Fu Wei <wefu@redhat.com>
+中文版校译者: 傅炜  Fu Wei <wefu@redhat.com>
 
 以下为正文
 ---------------------------------------------------------------------
@@ -41,7 +41,7 @@ AArch64 Linux 使用页大小为 4KB 的 3 级转换表配置,对于用户和
 TTBR1 中,且从不写入 TTBR0。
 
 
-AArch64 Linux 内存布局:
+AArch64 Linux å\9c¨é¡µå¤§å°\8f为 4KB æ\97¶ç\9a\84å\86\85å­\98å¸\83å±\80ï¼\9a
 
 起始地址                   结束地址                    大小          用途
 -----------------------------------------------------------------------
@@ -55,15 +55,42 @@ ffffffbc00000000    ffffffbdffffffff           8GB          vmemmap
 
 ffffffbe00000000       ffffffbffbbfffff          ~8GB          [防护页,未来用于 vmmemap]
 
+ffffffbffbc00000       ffffffbffbdfffff           2MB          earlyprintk 设备
+
 ffffffbffbe00000       ffffffbffbe0ffff          64KB          PCI I/O 空间
 
-ffffffbbffff0000       ffffffbcffffffff          ~2MB          [防护页]
+ffffffbffbe10000       ffffffbcffffffff          ~2MB          [防护页]
 
 ffffffbffc000000       ffffffbfffffffff          64MB          模块
 
 ffffffc000000000       ffffffffffffffff         256GB          内核逻辑内存映射
 
 
+AArch64 Linux 在页大小为 64KB 时的内存布局:
+
+起始地址                   结束地址                    大小          用途
+-----------------------------------------------------------------------
+0000000000000000       000003ffffffffff           4TB          用户空间
+
+fffffc0000000000       fffffdfbfffeffff          ~2TB          vmalloc
+
+fffffdfbffff0000       fffffdfbffffffff          64KB          [防护页]
+
+fffffdfc00000000       fffffdfdffffffff           8GB          vmemmap
+
+fffffdfe00000000       fffffdfffbbfffff          ~8GB          [防护页,未来用于 vmmemap]
+
+fffffdfffbc00000       fffffdfffbdfffff           2MB          earlyprintk 设备
+
+fffffdfffbe00000       fffffdfffbe0ffff          64KB          PCI I/O 空间
+
+fffffdfffbe10000       fffffdfffbffffff          ~2MB          [防护页]
+
+fffffdfffc000000       fffffdffffffffff          64MB          模块
+
+fffffe0000000000       ffffffffffffffff           2TB          内核逻辑内存映射
+
+
 4KB 页大小的转换表查找:
 
 +--------+--------+--------+--------+--------+--------+--------+--------+
@@ -91,3 +118,10 @@ ffffffc000000000    ffffffffffffffff         256GB          内核逻辑内存映射
  |                 |    +--------------------------> [41:29] L2 索引 (仅使用 38:29 )
  |                 +-------------------------------> [47:42] L1 索引 (未使用)
  +-------------------------------------------------> [63] TTBR0/1
+
+当使用 KVM 时, 管理程序(hypervisor)在 EL2 中通过相对内核虚拟地址的
+一个固定偏移来映射内核页(内核虚拟地址的高 24 位设为零):
+
+起始地址                   结束地址                    大小          用途
+-----------------------------------------------------------------------
+0000004000000000       0000007fffffffff         256GB          在 HYP 中映射的内核对象
diff --git a/Documentation/zh_CN/arm64/tagged-pointers.txt b/Documentation/zh_CN/arm64/tagged-pointers.txt
new file mode 100644 (file)
index 0000000..2664d1b
--- /dev/null
@@ -0,0 +1,52 @@
+Chinese translated version of Documentation/arm64/tagged-pointers.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly.  However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help.  Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Maintainer: Will Deacon <will.deacon@arm.com>
+Chinese maintainer: Fu Wei <wefu@redhat.com>
+---------------------------------------------------------------------
+Documentation/arm64/tagged-pointers.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: Will Deacon <will.deacon@arm.com>
+中文版维护者: 傅炜  Fu Wei <wefu@redhat.com>
+中文版翻译者: 傅炜  Fu Wei <wefu@redhat.com>
+中文版校译者: 傅炜  Fu Wei <wefu@redhat.com>
+
+以下为正文
+---------------------------------------------------------------------
+               Linux 在 AArch64 中带标记的虚拟地址
+               =================================
+
+作者: Will Deacon <will.deacon@arm.com>
+日期: 2013 年 06 月 12 日
+
+本文档简述了在 AArch64 地址转换系统中提供的带标记的虚拟地址及其在
+AArch64 Linux 中的潜在用途。
+
+内核提供的地址转换表配置使通过 TTBR0 完成的虚拟地址转换(即用户空间
+映射),其虚拟地址的最高 8 位(63:56)会被转换硬件所忽略。这种机制
+让这些位可供应用程序自由使用,其注意事项如下:
+
+       (1) 内核要求所有传递到 EL1 的用户空间地址带有 0x00 标记。
+           这意味着任何携带用户空间虚拟地址的系统调用(syscall)
+           参数 *必须* 在陷入内核前使它们的最高字节被清零。
+
+       (2) 非零标记在传递信号时不被保存。这意味着在应用程序中利用了
+           标记的信号处理函数无法依赖 siginfo_t 的用户空间虚拟
+           地址所携带的包含其内部域信息的标记。此规则的一个例外是
+           当信号是在调试观察点的异常处理程序中产生的,此时标记的
+           信息将被保存。
+
+       (3) 当使用带标记的指针时需特别留心,因为仅对两个虚拟地址
+           的高字节,C 编译器很可能无法判断它们是不同的。
+
+此构架会阻止对带标记的 PC 指针的利用,因此在异常返回时,其高字节
+将被设置成一个为 “55” 的扩展符。
index ec12265ac67bdacd67ab5a6a062c50bf6c1356b5..162b0fe3b0019aa4a3af487e1356f691f1e96c19 100644 (file)
@@ -73,7 +73,8 @@ Descriptions of section entries:
        L: Mailing list that is relevant to this area
        W: Web-page with status/info
        Q: Patchwork web based patch tracking system site
-       T: SCM tree type and location.  Type is one of: git, hg, quilt, stgit, topgit.
+       T: SCM tree type and location.
+          Type is one of: git, hg, quilt, stgit, topgit
        S: Status, one of the following:
           Supported:   Someone is actually paid to look after this.
           Maintained:  Someone actually looks after it.
@@ -473,7 +474,7 @@ F:  net/rxrpc/af_rxrpc.c
 
 AGPGART DRIVER
 M:     David Airlie <airlied@linux.ie>
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T:     git git://people.freedesktop.org/~airlied/linux (part of drm maint)
 S:     Maintained
 F:     drivers/char/agp/
 F:     include/linux/agp*
@@ -535,10 +536,17 @@ S:        Odd Fixes
 L:     linux-alpha@vger.kernel.org
 F:     arch/alpha/
 
+ALTERA TRIPLE SPEED ETHERNET DRIVER
+M:     Vince Bridgers <vbridgers2013@gmail.com
+L:     netdev@vger.kernel.org
+L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/net/ethernet/altera/
+
 ALTERA UART/JTAG UART SERIAL DRIVERS
 M:     Tobias Klauser <tklauser@distanz.ch>
 L:     linux-serial@vger.kernel.org
-L:     nios2-dev@sopc.et.ntust.edu.tw (moderated for non-subscribers)
+L:     nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 S:     Maintained
 F:     drivers/tty/serial/altera_uart.c
 F:     drivers/tty/serial/altera_jtaguart.c
@@ -910,11 +918,11 @@ F:        arch/arm/include/asm/hardware/dec21285.h
 F:     arch/arm/mach-footbridge/
 
 ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
-M:     Shawn Guo <shawn.guo@linaro.org>
+M:     Shawn Guo <shawn.guo@freescale.com>
 M:     Sascha Hauer <kernel@pengutronix.de>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-T:     git git://git.linaro.org/people/shawnguo/linux-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git
 F:     arch/arm/mach-imx/
 F:     arch/arm/boot/dts/imx*
 F:     arch/arm/configs/imx*_defconfig
@@ -1612,11 +1620,11 @@ S:      Maintained
 F:     drivers/net/wireless/atmel*
 
 ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
-M:      Bradley Grove <linuxdrivers@attotech.com>
-L:      linux-scsi@vger.kernel.org
-W:      http://www.attotech.com
-S:      Supported
-F:      drivers/scsi/esas2r
+M:     Bradley Grove <linuxdrivers@attotech.com>
+L:     linux-scsi@vger.kernel.org
+W:     http://www.attotech.com
+S:     Supported
+F:     drivers/scsi/esas2r
 
 AUDIT SUBSYSTEM
 M:     Eric Paris <eparis@redhat.com>
@@ -1737,6 +1745,7 @@ F:        include/uapi/linux/bfs_fs.h
 BLACKFIN ARCHITECTURE
 M:     Steven Miao <realmz6@gmail.com>
 L:     adi-buildroot-devel@lists.sourceforge.net
+T:     git git://git.code.sf.net/p/adi-linux/code
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     arch/blackfin/
@@ -1830,8 +1839,8 @@ F:        net/bluetooth/
 F:     include/net/bluetooth/
 
 BONDING DRIVER
-M:     Jay Vosburgh <fubar@us.ibm.com>
-M:     Veaceslav Falico <vfalico@redhat.com>
+M:     Jay Vosburgh <j.vosburgh@gmail.com>
+M:     Veaceslav Falico <vfalico@gmail.com>
 M:     Andy Gospodarek <andy@greyhouse.net>
 L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
@@ -1845,6 +1854,12 @@ L:       netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/broadcom/b44.*
 
+BROADCOM GENET ETHERNET DRIVER
+M:     Florian Fainelli <f.fainelli@gmail.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+F:     drivers/net/ethernet/broadcom/genet/
+
 BROADCOM BNX2 GIGABIT ETHERNET DRIVER
 M:     Michael Chan <mchan@broadcom.com>
 L:     netdev@vger.kernel.org
@@ -1860,6 +1875,7 @@ F:        drivers/net/ethernet/broadcom/bnx2x/
 
 BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
 M:     Christian Daudt <bcm@fixthebug.org>
+M:     Matt Porter <mporter@linaro.org>
 L:     bcm-kernel-feedback-list@broadcom.com
 T:     git git://git.github.com/broadcom/bcm11351
 S:     Maintained
@@ -2158,7 +2174,7 @@ F:        Documentation/zh_CN/
 
 CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
 M:     Peter Chen <Peter.Chen@freescale.com>
-T:     git://github.com/hzpeterchen/linux-usb.git
+T:     git git://github.com/hzpeterchen/linux-usb.git
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/chipidea/
@@ -2178,9 +2194,9 @@ S:        Supported
 F:     drivers/net/ethernet/cisco/enic/
 
 CISCO VIC LOW LATENCY NIC DRIVER
-M:      Upinder Malhi <umalhi@cisco.com>
-S:      Supported
-F:      drivers/infiniband/hw/usnic
+M:     Upinder Malhi <umalhi@cisco.com>
+S:     Supported
+F:     drivers/infiniband/hw/usnic
 
 CIRRUS LOGIC EP93XX ETHERNET DRIVER
 M:     Hartley Sweeten <hsweeten@visionengravers.com>
@@ -2367,7 +2383,7 @@ F:        include/linux/cpufreq.h
 
 CPU FREQUENCY DRIVERS - ARM BIG LITTLE
 M:     Viresh Kumar <viresh.kumar@linaro.org>
-M:     Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
+M:     Sudeep Holla <sudeep.holla@arm.com>
 L:     cpufreq@vger.kernel.org
 L:     linux-pm@vger.kernel.org
 W:     http://www.arm.com/products/processors/technologies/biglittleprocessing.php
@@ -2377,20 +2393,20 @@ F:      drivers/cpufreq/arm_big_little.c
 F:     drivers/cpufreq/arm_big_little_dt.c
 
 CPUIDLE DRIVER - ARM BIG LITTLE
-M:      Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-M:      Daniel Lezcano <daniel.lezcano@linaro.org>
-L:      linux-pm@vger.kernel.org
-L:      linux-arm-kernel@lists.infradead.org
-T:      git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
-S:      Maintained
-F:      drivers/cpuidle/cpuidle-big_little.c
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M:     Daniel Lezcano <daniel.lezcano@linaro.org>
+L:     linux-pm@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+S:     Maintained
+F:     drivers/cpuidle/cpuidle-big_little.c
 
 CPUIDLE DRIVERS
 M:     Rafael J. Wysocki <rjw@rjwysocki.net>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 L:     linux-pm@vger.kernel.org
 S:     Maintained
-T:     git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
 F:     drivers/cpuidle/*
 F:     include/linux/cpuidle.h
 
@@ -2408,8 +2424,10 @@ F:       tools/power/cpupower/
 
 CPUSETS
 M:     Li Zefan <lizefan@huawei.com>
+L:     cgroups@vger.kernel.org
 W:     http://www.bullopensource.org/cpuset/
 W:     http://oss.sgi.com/projects/cpusets/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git
 S:     Maintained
 F:     Documentation/cgroups/cpusets.txt
 F:     include/linux/cpuset.h
@@ -2455,9 +2473,9 @@ S:        Maintained
 F:     sound/pci/cs5535audio/
 
 CW1200 WLAN driver
-M:     Solomon Peachy <pizza@shaftnet.org>
-S:     Maintained
-F:     drivers/net/wireless/cw1200/
+M:     Solomon Peachy <pizza@shaftnet.org>
+S:     Maintained
+F:     drivers/net/wireless/cw1200/
 
 CX18 VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
@@ -2608,9 +2626,9 @@ DC395x SCSI driver
 M:     Oliver Neukum <oliver@neukum.org>
 M:     Ali Akcaagac <aliakc@web.de>
 M:     Jamie Lenehan <lenehan@twibble.org>
-W:     http://twibble.org/dist/dc395x/
 L:     dc395x@twibble.org
-L:     http://lists.twibble.org/mailman/listinfo/dc395x/
+W:     http://twibble.org/dist/dc395x/
+W:     http://lists.twibble.org/mailman/listinfo/dc395x/
 S:     Maintained
 F:     Documentation/scsi/dc395x.txt
 F:     drivers/scsi/dc395x.*
@@ -2845,19 +2863,29 @@ F:      lib/kobj*
 DRM DRIVERS
 M:     David Airlie <airlied@linux.ie>
 L:     dri-devel@lists.freedesktop.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+T:     git git://people.freedesktop.org/~airlied/linux
 S:     Maintained
 F:     drivers/gpu/drm/
 F:     include/drm/
 F:     include/uapi/drm/
 
+RADEON DRM DRIVERS
+M:     Alex Deucher <alexander.deucher@amd.com>
+M:     Christian König <christian.koenig@amd.com>
+L:     dri-devel@lists.freedesktop.org
+T:     git git://people.freedesktop.org/~agd5f/linux
+S:     Supported
+F:     drivers/gpu/drm/radeon/
+F:     include/drm/radeon*
+F:     include/uapi/drm/radeon*
+
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Daniel Vetter <daniel.vetter@ffwll.ch>
 M:     Jani Nikula <jani.nikula@linux.intel.com>
 L:     intel-gfx@lists.freedesktop.org
 L:     dri-devel@lists.freedesktop.org
 Q:     http://patchwork.freedesktop.org/project/intel-gfx/
-T:     git git://people.freedesktop.org/~danvet/drm-intel
+T:     git git://anongit.freedesktop.org/drm-intel
 S:     Supported
 F:     drivers/gpu/drm/i915/
 F:     include/drm/i915*
@@ -3082,6 +3110,8 @@ F:        fs/ecryptfs/
 
 EDAC-CORE
 M:     Doug Thompson <dougthompson@xmission.com>
+M:     Borislav Petkov <bp@alien8.de>
+M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Supported
@@ -3324,6 +3354,17 @@ S:       Maintained
 F:     include/linux/netfilter_bridge/
 F:     net/bridge/
 
+ETHERNET PHY LIBRARY
+M:     Florian Fainelli <f.fainelli@gmail.com>
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     include/linux/phy.h
+F:     include/linux/phy_fixed.h
+F:     drivers/net/phy/
+F:     Documentation/networking/phy.txt
+F:     drivers/of/of_mdio.c
+F:     drivers/of/of_net.c
+
 EXT2 FILE SYSTEM
 M:     Jan Kara <jack@suse.cz>
 L:     linux-ext4@vger.kernel.org
@@ -4517,6 +4558,7 @@ M:        Greg Rose <gregory.v.rose@intel.com>
 M:     Alex Duyck <alexander.h.duyck@intel.com>
 M:     John Ronciak <john.ronciak@intel.com>
 M:     Mitch Williams <mitch.a.williams@intel.com>
+M:     Linux NICS <linux.nics@intel.com>
 L:     e1000-devel@lists.sourceforge.net
 W:     http://www.intel.com/support/feedback.htm
 W:     http://e1000.sourceforge.net/
@@ -4534,6 +4576,7 @@ F:        Documentation/networking/ixgbevf.txt
 F:     Documentation/networking/i40e.txt
 F:     Documentation/networking/i40evf.txt
 F:     drivers/net/ethernet/intel/
+F:     drivers/net/ethernet/intel/*/
 
 INTEL-MID GPIO DRIVER
 M:     David Cohen <david.a.cohen@linux.intel.com>
@@ -4890,7 +4933,7 @@ F:        drivers/staging/ktap/
 KCONFIG
 M:     "Yann E. MORIN" <yann.morin.1998@free.fr>
 L:     linux-kbuild@vger.kernel.org
-T:     git://gitorious.org/linux-kconfig/linux-kconfig
+T:     git git://gitorious.org/linux-kconfig/linux-kconfig
 S:     Maintained
 F:     Documentation/kbuild/kconfig-language.txt
 F:     scripts/kconfig/
@@ -5447,11 +5490,11 @@ S:      Maintained
 F:     drivers/media/tuners/m88ts2022*
 
 MA901 MASTERKIT USB FM RADIO DRIVER
-M:      Alexey Klimov <klimov.linux@gmail.com>
-L:      linux-media@vger.kernel.org
-T:      git git://linuxtv.org/media_tree.git
-S:      Maintained
-F:      drivers/media/radio/radio-ma901.c
+M:     Alexey Klimov <klimov.linux@gmail.com>
+L:     linux-media@vger.kernel.org
+T:     git git://linuxtv.org/media_tree.git
+S:     Maintained
+F:     drivers/media/radio/radio-ma901.c
 
 MAC80211
 M:     Johannes Berg <johannes@sipsolutions.net>
@@ -5487,6 +5530,11 @@ W:       http://www.kernel.org/doc/man-pages
 L:     linux-man@vger.kernel.org
 S:     Maintained
 
+MARVELL ARMADA DRM SUPPORT
+M:     Russell King <rmk+kernel@arm.linux.org.uk>
+S:     Maintained
+F:     drivers/gpu/drm/armada/
+
 MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
 M:     Mirko Lindner <mlindner@marvell.com>
 M:     Stephen Hemminger <stephen@networkplumber.org>
@@ -5607,7 +5655,7 @@ F:        drivers/scsi/megaraid/
 
 MELLANOX ETHERNET DRIVER (mlx4_en)
 M:     Amir Vadai <amirv@mellanox.com>
-L:     netdev@vger.kernel.org
+L:     netdev@vger.kernel.org
 S:     Supported
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
@@ -5648,7 +5696,7 @@ F:        include/linux/mtd/
 F:     include/uapi/mtd/
 
 MEN A21 WATCHDOG DRIVER
-M:     Johannes Thumshirn <johannes.thumshirn@men.de>
+M:     Johannes Thumshirn <johannes.thumshirn@men.de>
 L:     linux-watchdog@vger.kernel.org
 S:     Supported
 F:     drivers/watchdog/mena21_wdt.c
@@ -5704,20 +5752,20 @@ L:      linux-rdma@vger.kernel.org
 W:     http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-T:     git://openfabrics.org/~eli/connect-ib.git
+T:     git git://openfabrics.org/~eli/connect-ib.git
 S:     Supported
 F:     drivers/net/ethernet/mellanox/mlx5/core/
 F:     include/linux/mlx5/
 
 Mellanox MLX5 IB driver
-M:      Eli Cohen <eli@mellanox.com>
-L:      linux-rdma@vger.kernel.org
-W:      http://www.mellanox.com
-Q:      http://patchwork.kernel.org/project/linux-rdma/list/
-T:      git://openfabrics.org/~eli/connect-ib.git
-S:      Supported
-F:      include/linux/mlx5/
-F:      drivers/infiniband/hw/mlx5/
+M:     Eli Cohen <eli@mellanox.com>
+L:     linux-rdma@vger.kernel.org
+W:     http://www.mellanox.com
+Q:     http://patchwork.kernel.org/project/linux-rdma/list/
+T:     git git://openfabrics.org/~eli/connect-ib.git
+S:     Supported
+F:     include/linux/mlx5/
+F:     drivers/infiniband/hw/mlx5/
 
 MODULE SUPPORT
 M:     Rusty Russell <rusty@rustcorp.com.au>
@@ -5969,6 +6017,9 @@ F:        include/linux/netdevice.h
 F:     include/uapi/linux/in.h
 F:     include/uapi/linux/net.h
 F:     include/uapi/linux/netdevice.h
+F:     tools/net/
+F:     tools/testing/selftests/net/
+F:     lib/random32.c
 
 NETWORKING [IPv4/IPv6]
 M:     "David S. Miller" <davem@davemloft.net>
@@ -5992,6 +6043,7 @@ L:        netdev@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec.git
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next.git
 S:     Maintained
+F:     net/core/flow.c
 F:     net/xfrm/
 F:     net/key/
 F:     net/ipv4/xfrm*
@@ -6143,6 +6195,12 @@ S:       Supported
 F:     drivers/block/nvme*
 F:     include/linux/nvme.h
 
+NXP TDA998X DRM DRIVER
+M:     Russell King <rmk+kernel@arm.linux.org.uk>
+S:     Supported
+F:     drivers/gpu/drm/i2c/tda998x_drv.c
+F:     include/drm/i2c/tda998x.h
+
 OMAP SUPPORT
 M:     Tony Lindgren <tony@atomide.com>
 L:     linux-omap@vger.kernel.org
@@ -7021,13 +7079,8 @@ F:       Documentation/networking/LICENSE.qla3xxx
 F:     drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
-M:     Himanshu Madhani <himanshu.madhani@qlogic.com>
-M:     Rajesh Borundia <rajesh.borundia@qlogic.com>
 M:     Shahed Shaikh <shahed.shaikh@qlogic.com>
-M:     Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
-M:     Sony Chacko <sony.chacko@qlogic.com>
-M:     Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
-M:     linux-driver@qlogic.com
+M:     Dept-HSGLinuxNICDev@qlogic.com
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/qlogic/qlcnic/
@@ -7197,7 +7250,7 @@ S:        Maintained
 F:     drivers/net/ethernet/rdc/r6040.c
 
 RDS - RELIABLE DATAGRAM SOCKETS
-M:     Venkat Venkatsubra <venkat.x.venkatsubra@oracle.com>
+M:     Chien Yen <chien.yen@oracle.com>
 L:     rds-devel@oss.oracle.com (moderated for non-subscribers)
 S:     Supported
 F:     net/rds/
@@ -7498,6 +7551,15 @@ S:       Supported
 L:     linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 F:     drivers/clk/samsung/
 
+SAMSUNG SXGBE DRIVERS
+M:     Byungho An <bh74.an@samsung.com>
+M:     Girish K S <ks.giri@samsung.com>
+M:     Siva Reddy Kallam <siva.kallam@samsung.com>
+M:     Vipul Pandya <vipul.pandya@samsung.com>
+S:     Supported
+L:     netdev@vger.kernel.org
+F:     drivers/net/ethernet/samsung/sxgbe/
+
 SERIAL DRIVERS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-serial@vger.kernel.org
@@ -8430,8 +8492,8 @@ TARGET SUBSYSTEM
 M:     Nicholas A. Bellinger <nab@linux-iscsi.org>
 L:     linux-scsi@vger.kernel.org
 L:     target-devel@vger.kernel.org
-L:     http://groups.google.com/group/linux-iscsi-target-dev
 W:     http://www.linux-iscsi.org
+W:     http://groups.google.com/group/linux-iscsi-target-dev
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
 S:     Supported
 F:     drivers/target/
@@ -8672,17 +8734,17 @@ S:      Maintained
 F:     drivers/media/radio/radio-raremono.c
 
 THERMAL
-M:      Zhang Rui <rui.zhang@intel.com>
-M:      Eduardo Valentin <eduardo.valentin@ti.com>
-L:      linux-pm@vger.kernel.org
-T:      git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
-T:      git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
-Q:      https://patchwork.kernel.org/project/linux-pm/list/
-S:      Supported
-F:      drivers/thermal/
-F:      include/linux/thermal.h
-F:      include/linux/cpu_cooling.h
-F:      Documentation/devicetree/bindings/thermal/
+M:     Zhang Rui <rui.zhang@intel.com>
+M:     Eduardo Valentin <eduardo.valentin@ti.com>
+L:     linux-pm@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
+Q:     https://patchwork.kernel.org/project/linux-pm/list/
+S:     Supported
+F:     drivers/thermal/
+F:     include/linux/thermal.h
+F:     include/linux/cpu_cooling.h
+F:     Documentation/devicetree/bindings/thermal/
 
 THINGM BLINK(1) USB RGB LED DRIVER
 M:     Vivien Didelot <vivien.didelot@savoirfairelinux.com>
@@ -9716,7 +9778,6 @@ F:        drivers/xen/*swiotlb*
 XFS FILESYSTEM
 P:     Silicon Graphics Inc
 M:     Dave Chinner <david@fromorbit.com>
-M:     Ben Myers <bpm@sgi.com>
 M:     xfs@oss.sgi.com
 L:     xfs@oss.sgi.com
 W:     http://oss.sgi.com/projects/xfs
@@ -9785,7 +9846,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
 L:     mjpeg-users@lists.sourceforge.net
 L:     linux-media@vger.kernel.org
 W:     http://mjpeg.sourceforge.net/driver-zoran/
-T:     Mercurial http://linuxtv.org/hg/v4l-dvb
+T:     hg http://linuxtv.org/hg/v4l-dvb
 S:     Odd Fixes
 F:     drivers/media/pci/zoran/
 
index 933e1def6bafbea459960d8f6e64ac8c7b2a5e8e..c10b734339dbe10bb257a330c4eb9dad9eb1265e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 14
 SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc8
 NAME = Shuffling Zombie Juror
 
 # *DOCUMENTATION*
@@ -605,10 +605,11 @@ endif
 ifdef CONFIG_CC_STACKPROTECTOR_REGULAR
   stackp-flag := -fstack-protector
   ifeq ($(call cc-option, $(stackp-flag)),)
-    $(warning Cannot use CONFIG_CC_STACKPROTECTOR: \
-             -fstack-protector not supported by compiler))
+    $(warning Cannot use CONFIG_CC_STACKPROTECTOR_REGULAR: \
+             -fstack-protector not supported by compiler)
   endif
-else ifdef CONFIG_CC_STACKPROTECTOR_STRONG
+else
+ifdef CONFIG_CC_STACKPROTECTOR_STRONG
   stackp-flag := -fstack-protector-strong
   ifeq ($(call cc-option, $(stackp-flag)),)
     $(warning Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: \
@@ -618,6 +619,7 @@ else
   # Force off for distro compilers that enable stack protector by default.
   stackp-flag := $(call cc-option, -fno-stack-protector)
 endif
+endif
 KBUILD_CFLAGS += $(stackp-flag)
 
 # This warning generated too much noise in a regular build.
index 6b58c1de757744feac1d0ae54ec1fdd0693fc500..400c663b21c2bf075e977a8ccf3016fb7e03b5a6 100644 (file)
@@ -282,7 +282,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
 #else
        /* if V-P const for loop, PTAG can be written once outside loop */
        if (full_page_op)
-               write_aux_reg(ARC_REG_DC_PTAG, paddr);
+               write_aux_reg(aux_tag, paddr);
 #endif
 
        while (num_lines-- > 0) {
@@ -296,7 +296,7 @@ static inline void __cache_line_loop(unsigned long paddr, unsigned long vaddr,
                write_aux_reg(aux_cmd, vaddr);
                vaddr += L1_CACHE_BYTES;
 #else
-               write_aux_reg(aux, paddr);
+               write_aux_reg(aux_cmd, paddr);
                paddr += L1_CACHE_BYTES;
 #endif
        }
index e254198177914ca13050f37519a6ca43e0da596d..15949459611f194376dafcdebaf569f8ef141dc5 100644 (file)
@@ -1578,6 +1578,7 @@ config BL_SWITCHER_DUMMY_IF
 
 choice
        prompt "Memory split"
+       depends on MMU
        default VMSPLIT_3G
        help
          Select the desired split between kernel and user memory.
@@ -1595,6 +1596,7 @@ endchoice
 
 config PAGE_OFFSET
        hex
+       default PHYS_OFFSET if !MMU
        default 0x40000000 if VMSPLIT_1G
        default 0x80000000 if VMSPLIT_2G
        default 0xC0000000
@@ -1903,6 +1905,7 @@ config XEN
        depends on ARM && AEABI && OF
        depends on CPU_V7 && !CPU_V6
        depends on !GENERIC_ATOMIC64
+       depends on MMU
        select ARM_PSCI
        select SWIOTLB_XEN
        select ARCH_DMA_ADDR_T_64BIT
index 47279aa96a6a48fd1945ae9faa7584d49f24a355..0714e0334e33c9790b221d03859574b2f4e774ad 100644 (file)
@@ -1,4 +1,5 @@
 ashldi3.S
+bswapsdi2.S
 font.c
 lib1funcs.S
 hyp-stub.S
index b9d6a8b485e0bdeba13c1848391fca3ca263341b..032030361bef2448ce84075212615d58c469cb8b 100644 (file)
@@ -38,6 +38,7 @@ dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb
 dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb
 dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb
 # sama5d3
+dtb-$(CONFIG_ARCH_AT91)        += at91-sama5d3_xplained.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d31ek.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d33ek.dtb
 dtb-$(CONFIG_ARCH_AT91)        += sama5d34ek.dtb
@@ -208,7 +209,8 @@ dtb-$(CONFIG_ARCH_OMAP2PLUS) += omap2420-h4.dtb \
        omap3-n900.dtb \
        omap3-n9.dtb \
        omap3-n950.dtb \
-       omap3-tobi.dtb \
+       omap3-overo-tobi.dtb \
+       omap3-overo-storm-tobi.dtb \
        omap3-gta04.dtb \
        omap3-igep0020.dtb \
        omap3-igep0030.dtb \
index 4718ec4a4dbfef5e2a7273726cb6a8f0750623e3..486880b7483134c88f8638a6e7fb4cc98518e7e3 100644 (file)
                ti,model = "AM335x-EVMSK";
                ti,audio-codec = <&tlv320aic3106>;
                ti,mcasp-controller = <&mcasp1>;
-               ti,codec-clock-rate = <24576000>;
+               ti,codec-clock-rate = <24000000>;
                ti,audio-routing =
                        "Headphone Jack",       "HPLOUT",
                        "Headphone Jack",       "HPROUT";
                >;
        };
 
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */
+               >;
+       };
+
        mcasp1_pins: mcasp1_pins {
                pinctrl-single,pins = <
                        0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
        status = "okay";
        vmmc-supply = <&vmmc_reg>;
        bus-width = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+       cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
 };
 
 &sham {
index 66609684d41b59ef701530fd2076553ffc4e9b6b..9480cf891f8cd0ce475d87cf2eed904a6a740eb7 100644 (file)
@@ -23,6 +23,7 @@
                gpio0 = &gpio0;
                gpio1 = &gpio1;
                gpio2 = &gpio2;
+               eth3 = &eth3;
        };
 
        cpus {
                                interrupts = <91>;
                        };
 
-                       ethernet@34000 {
+                       eth3: ethernet@34000 {
                                compatible = "marvell,armada-370-neta";
                                reg = <0x34000 0x4000>;
                                interrupts = <14>;
diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
new file mode 100644 (file)
index 0000000..ce13755
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * at91-sama5d3_xplained.dts - Device Tree file for the SAMA5D3 Xplained board
+ *
+ *  Copyright (C) 2014 Atmel,
+ *               2014 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+#include "sama5d36.dtsi"
+
+/ {
+       model = "SAMA5D3 Xplained";
+       compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5";
+
+       chosen {
+               bootargs = "console=ttyS0,115200";
+       };
+
+       memory {
+               reg = <0x20000000 0x10000000>;
+       };
+
+       ahb {
+               apb {
+                       mmc0: mmc@f0000000 {
+                               pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>;
+                               status = "okay";
+                               slot@0 {
+                                       reg = <0>;
+                                       bus-width = <8>;
+                                       cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>;
+                               };
+                       };
+
+                       spi0: spi@f0004000 {
+                               cs-gpios = <&pioD 13 0>;
+                               status = "okay";
+                       };
+
+                       can0: can@f000c000 {
+                               status = "okay";
+                       };
+
+                       i2c0: i2c@f0014000 {
+                               status = "okay";
+                       };
+
+                       i2c1: i2c@f0018000 {
+                               status = "okay";
+                       };
+
+                       macb0: ethernet@f0028000 {
+                               phy-mode = "rgmii";
+                               status = "okay";
+                       };
+
+                       usart0: serial@f001c000 {
+                               status = "okay";
+                       };
+
+                       usart1: serial@f0020000 {
+                               pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>;
+                               status = "okay";
+                       };
+
+                       uart0: serial@f0024000 {
+                               status = "okay";
+                       };
+
+                       mmc1: mmc@f8000000 {
+                               pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>;
+                               status = "okay";
+                               slot@0 {
+                                       reg = <0>;
+                                       bus-width = <4>;
+                                       cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>;
+                               };
+                       };
+
+                       spi1: spi@f8008000 {
+                               cs-gpios = <&pioC 25 0>, <0>, <0>, <&pioD 16 0>;
+                               status = "okay";
+                       };
+
+                       adc0: adc@f8018000 {
+                               pinctrl-0 = <
+                                       &pinctrl_adc0_adtrg
+                                       &pinctrl_adc0_ad0
+                                       &pinctrl_adc0_ad1
+                                       &pinctrl_adc0_ad2
+                                       &pinctrl_adc0_ad3
+                                       &pinctrl_adc0_ad4
+                                       &pinctrl_adc0_ad5
+                                       &pinctrl_adc0_ad6
+                                       &pinctrl_adc0_ad7
+                                       &pinctrl_adc0_ad8
+                                       &pinctrl_adc0_ad9
+                                       >;
+                               status = "okay";
+                       };
+
+                       i2c2: i2c@f801c000 {
+                               dmas = <0>, <0>;        /* Do not use DMA for i2c2 */
+                               status = "okay";
+                       };
+
+                       macb1: ethernet@f802c000 {
+                               phy-mode = "rmii";
+                               status = "okay";
+                       };
+
+                       dbgu: serial@ffffee00 {
+                               status = "okay";
+                       };
+
+                       pinctrl@fffff200 {
+                               board {
+                                       pinctrl_mmc0_cd: mmc0_cd {
+                                               atmel,pins =
+                                                       <AT91_PIOE 0 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+                                       };
+
+                                       pinctrl_mmc1_cd: mmc1_cd {
+                                               atmel,pins =
+                                                       <AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+                                       };
+
+                                       pinctrl_usba_vbus: usba_vbus {
+                                               atmel,pins =
+                                                       <AT91_PIOE 9 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;   /* PE9, conflicts with A9 */
+                                       };
+                               };
+                       };
+
+                       pmc: pmc@fffffc00 {
+                               main: mainck {
+                                       clock-frequency = <12000000>;
+                               };
+                       };
+               };
+
+               nand0: nand@60000000 {
+                       nand-bus-width = <8>;
+                       nand-ecc-mode = "hw";
+                       atmel,has-pmecc;
+                       atmel,pmecc-cap = <4>;
+                       atmel,pmecc-sector-size = <512>;
+                       nand-on-flash-bbt;
+                       status = "okay";
+
+                       at91bootstrap@0 {
+                               label = "at91bootstrap";
+                               reg = <0x0 0x40000>;
+                       };
+
+                       bootloader@40000 {
+                               label = "bootloader";
+                               reg = <0x40000 0x80000>;
+                       };
+
+                       bootloaderenv@c0000 {
+                               label = "bootloader env";
+                               reg = <0xc0000 0xc0000>;
+                       };
+
+                       dtb@180000 {
+                               label = "device tree";
+                               reg = <0x180000 0x80000>;
+                       };
+
+                       kernel@200000 {
+                               label = "kernel";
+                               reg = <0x200000 0x600000>;
+                       };
+
+                       rootfs@800000 {
+                               label = "rootfs";
+                               reg = <0x800000 0x0f800000>;
+                       };
+               };
+
+               usb0: gadget@00500000 {
+                       atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>;   /* PE9, conflicts with A9 */
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_usba_vbus>;
+                       status = "okay";
+               };
+
+               usb1: ohci@00600000 {
+                       num-ports = <3>;
+                       atmel,vbus-gpio = <0
+                                          &pioE 3 GPIO_ACTIVE_LOW
+                                          &pioE 4 GPIO_ACTIVE_LOW
+                                         >;
+                       status = "okay";
+               };
+
+               usb2: ehci@00700000 {
+                       status = "okay";
+               };
+       };
+
+       gpio_keys {
+               compatible = "gpio-keys";
+
+               bp3 {
+                       label = "PB_USER";
+                       gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
+                       linux,code = <0x104>;
+                       gpio-key,wakeup;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               d2 {
+                       label = "d2";
+                       gpios = <&pioE 23 GPIO_ACTIVE_LOW>;     /* PE23, conflicts with A23, CTS2 */
+                       linux,default-trigger = "heartbeat";
+               };
+
+               d3 {
+                       label = "d3";
+                       gpios = <&pioE 24 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
index 0042f73068b0c913f729cb6e0fd5b3b5b01609d5..fece8665fb63ad89232a821c4da307475bbc4f88 100644 (file)
                        };
 
                        i2c0: i2c@fff88000 {
-                               compatible = "atmel,at91sam9263-i2c";
+                               compatible = "atmel,at91sam9260-i2c";
                                reg = <0xfff88000 0x100>;
                                interrupts = <13 IRQ_TYPE_LEVEL_HIGH 6>;
                                #address-cells = <1>;
index e9487f6f01660409ee193649d3c1d56c98376cb5..924a6a6ffd0f0a03d6fcde286fff1383e696eb70 100644 (file)
                        nand-on-flash-bbt;
                        status = "okay";
                };
+
+               usb0: ohci@00500000 {
+                       status = "okay";
+               };
        };
 
        leds {
index e491b82f8d67099ce25b4d1f08cdc6777bf55d7f..792fde1b7f752a93ffa42f2e5f8c7083dc1bb55c 100644 (file)
        };
 
        pinctrl@35004800 {
-               compatible = "brcm,capri-pinctrl";
+               compatible = "brcm,bcm11351-pinctrl";
                reg = <0x35004800 0x430>;
        };
 
index 2b76524f4aa74ee475d7e027f24683097ef4770f..187fd46b7b5ef018c2985e7db5298784338f0507 100644 (file)
                                #clock-cells = <1>;
                        };
 
-                       pmu_intc: pmu-interrupt-ctrl@d0050 {
-                               compatible = "marvell,dove-pmu-intc";
-                               interrupt-controller;
-                               #interrupt-cells = <1>;
-                               reg = <0xd0050 0x8>;
-                               interrupts = <33>;
-                               marvell,#interrupts = <7>;
-                       };
-
                        pinctrl: pin-ctrl@d0200 {
                                compatible = "marvell,dove-pinctrl";
                                reg = <0xd0200 0x10>;
                        rtc: real-time-clock@d8500 {
                                compatible = "marvell,orion-rtc";
                                reg = <0xd8500 0x20>;
-                               interrupt-parent = <&pmu_intc>;
-                               interrupts = <5>;
                        };
 
                        gpio2: gpio-ctrl@e8400 {
index fd8fc7cd53f3158bf7e030659a09a0c3ae476edc..5bfae54fb7806f4391a93ab89bdb1dd621358c03 100644 (file)
                };
        };
 
-       codec: spdif-transmitter {
-               compatible = "linux,spdif-dit";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_hummingboard_spdif>;
-       };
-
        sound-spdif {
                compatible = "fsl,imx-audio-spdif";
                model = "imx-spdif";
                };
 
                pinctrl_hummingboard_spdif: hummingboard-spdif {
-                       fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+                       fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
                };
 
                pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus {
 };
 
 &spdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hummingboard_spdif>;
        status = "okay";
 };
 
index 64daa3b311f6f057e8ecf05ec6f7ea84b9c36ed8..c2a24888a2768969263e1b8536e98ec869b4ff4f 100644 (file)
                };
        };
 
-       codec: spdif-transmitter {
-               compatible = "linux,spdif-dit";
-               pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_cubox_i_spdif>;
-       };
-
        sound-spdif {
                compatible = "fsl,imx-audio-spdif";
                model = "imx-spdif";
@@ -89,7 +83,7 @@
                };
 
                pinctrl_cubox_i_spdif: cubox-i-spdif {
-                       fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+                       fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x13091>;
                };
 
                pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
 };
 
 &spdif {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_cubox_i_spdif>;
        status = "okay";
 };
 
index 2363593e1050b7b84b4705878fc10cb653b33cca..ef58d1c24313541a068436c5e590378120c6bb3b 100644 (file)
@@ -612,7 +612,7 @@ clocks {
                compatible = "ti,keystone,psc-clock";
                clocks = <&chipclk13>;
                clock-output-names = "vcp-3";
-               reg = <0x0235000a8 0xb00>, <0x02350060 0x400>;
+               reg = <0x023500a8 0xb00>, <0x02350060 0x400>;
                reg-names = "control", "domain";
                domain-id = <24>;
        };
index b9b55c95a566c3ea6f6f21e55b787b9c31c2194f..d3b253bbc8856a9ba0a2f1810c1860f875931462 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "OMAP3 GTA04";
-       compatible = "ti,omap3-gta04", "ti,omap3";
+       compatible = "ti,omap3-gta04", "ti,omap36xx", "ti,omap3";
 
        cpus {
                cpu@0 {
@@ -32,7 +32,7 @@
                aux-button {
                        label = "aux";
                        linux,code = <169>;
-                       gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+                       gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
                        gpio-key,wakeup;
                };
        };
@@ -92,6 +92,8 @@
        bmp085@77 {
                compatible = "bosch,bmp085";
                reg = <0x77>;
+               interrupt-parent = <&gpio4>;
+               interrupts = <17 IRQ_TYPE_EDGE_RISING>;
        };
 
        /* leds */
        pinctrl-names = "default";
        pinctrl-0 = <&mmc1_pins>;
        vmmc-supply = <&vmmc1>;
-       vmmc_aux-supply = <&vsim>;
        bus-width = <4>;
+       ti,non-removable;
 };
 
 &mmc2 {
index 25a2b5f652fd1949ceac364ec8a154436aba05e4..f2779ac75872a4a44e2d03402fab7b6fe1a4b66b 100644 (file)
@@ -14,7 +14,7 @@
 
 / {
        model = "IGEPv2 (TI OMAP AM/DM37x)";
-       compatible = "isee,omap3-igep0020", "ti,omap3";
+       compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
 
        leds {
                pinctrl-names = "default";
index 145c58cfc8ac1d3c322f2a2ad44abac2734bbb30..2793749eb1ba460dcf8736fc964aef7b87b05d1a 100644 (file)
@@ -13,7 +13,7 @@
 
 / {
        model = "IGEP COM MODULE (TI OMAP AM/DM37x)";
-       compatible = "isee,omap3-igep0030", "ti,omap3";
+       compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
 
        leds {
                pinctrl-names = "default";
index 39828ce464ee527b900ff6a2013660fe1c231822..9938b5dc1909c00f01e587f15a4a1c1d2a6bc665 100644 (file)
@@ -14,5 +14,5 @@
 
 / {
        model = "Nokia N9";
-       compatible = "nokia,omap3-n9", "ti,omap3";
+       compatible = "nokia,omap3-n9", "ti,omap36xx", "ti,omap3";
 };
index 6fc85f96353024ad61d04d74d7ca51f8afb1c7ce..0bf40c90faba626c88b539965a1f928aa09bf313 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 Pavel Machek <pavel@ucw.cz>
- * Copyright 2013 Aaro Koskinen <aaro.koskinen@iki.fi>
+ * Copyright (C) 2013-2014 Aaro Koskinen <aaro.koskinen@iki.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 (or later) as
@@ -13,7 +13,7 @@
 
 / {
        model = "Nokia N900";
-       compatible = "nokia,omap3-n900", "ti,omap3";
+       compatible = "nokia,omap3-n900", "ti,omap3430", "ti,omap3";
 
        cpus {
                cpu@0 {
index b076a526b99973a3489bf831e0cec5c1dcff93bb..261c5589bfa3170e76cc8f469ac1d6ca07a02765 100644 (file)
@@ -14,5 +14,5 @@
 
 / {
        model = "Nokia N950";
-       compatible = "nokia,omap3-n950", "ti,omap3";
+       compatible = "nokia,omap3-n950", "ti,omap36xx", "ti,omap3";
 };
diff --git a/arch/arm/boot/dts/omap3-overo-storm-tobi.dts b/arch/arm/boot/dts/omap3-overo-storm-tobi.dts
new file mode 100644 (file)
index 0000000..966b5c9
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap36xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+       model = "OMAP36xx/AM37xx/DM37xx Gumstix Overo on Tobi";
+       compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap36xx", "ti,omap3";
+};
+
diff --git a/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi b/arch/arm/boot/dts/omap3-overo-tobi-common.dtsi
new file mode 100644 (file)
index 0000000..4edc013
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+#include "omap3-overo.dtsi"
+
+/ {
+       leds {
+               compatible = "gpio-leds";
+               heartbeat {
+                       label = "overo:red:gpio21";
+                       gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
+                       linux,default-trigger = "heartbeat";
+               };
+       };
+
+       vddvario: regulator-vddvario {
+                 compatible = "regulator-fixed";
+                 regulator-name = "vddvario";
+                 regulator-always-on;
+       };
+
+       vdd33a: regulator-vdd33a {
+               compatible = "regulator-fixed";
+               regulator-name = "vdd33a";
+               regulator-always-on;
+       };
+};
+
+&gpmc {
+       ranges = <5 0 0x2c000000 0x1000000>;    /* CS5 */
+
+       ethernet@5,0 {
+               compatible = "smsc,lan9221", "smsc,lan9115";
+               reg = <5 0 0xff>;
+               bank-width = <2>;
+
+               gpmc,mux-add-data;
+               gpmc,cs-on-ns = <0>;
+               gpmc,cs-rd-off-ns = <42>;
+               gpmc,cs-wr-off-ns = <36>;
+               gpmc,adv-on-ns = <6>;
+               gpmc,adv-rd-off-ns = <12>;
+               gpmc,adv-wr-off-ns = <12>;
+               gpmc,oe-on-ns = <0>;
+               gpmc,oe-off-ns = <42>;
+               gpmc,we-on-ns = <0>;
+               gpmc,we-off-ns = <36>;
+               gpmc,rd-cycle-ns = <60>;
+               gpmc,wr-cycle-ns = <54>;
+               gpmc,access-ns = <36>;
+               gpmc,page-burst-access-ns = <0>;
+               gpmc,bus-turnaround-ns = <0>;
+               gpmc,cycle2cycle-delay-ns = <0>;
+               gpmc,wr-data-mux-bus-ns = <18>;
+               gpmc,wr-access-ns = <42>;
+               gpmc,cycle2cycle-samecsen;
+               gpmc,cycle2cycle-diffcsen;
+
+               interrupt-parent = <&gpio6>;
+               interrupts = <16 IRQ_TYPE_LEVEL_LOW>;   /* GPIO 176 */
+               reg-io-width = <4>;
+       };
+};
+
+&i2c3 {
+       clock-frequency = <100000>;
+};
+
+&mmc3 {
+       status = "disabled";
+};
diff --git a/arch/arm/boot/dts/omap3-overo-tobi.dts b/arch/arm/boot/dts/omap3-overo-tobi.dts
new file mode 100644 (file)
index 0000000..de5653e
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Tobi expansion board is manufactured by Gumstix Inc.
+ */
+
+/dts-v1/;
+
+#include "omap34xx.dtsi"
+#include "omap3-overo-tobi-common.dtsi"
+
+/ {
+       model = "OMAP35xx Gumstix Overo on Tobi";
+       compatible = "gumstix,omap3-overo-tobi", "gumstix,omap3-overo", "ti,omap3430", "ti,omap3";
+};
+
index a461d2fd1fb0e81862805ccec939e1c1b3a41244..597099907f8ef77423210bcf6cb2be26f8799eb5 100644 (file)
@@ -9,9 +9,6 @@
 /*
  * The Gumstix Overo must be combined with an expansion board.
  */
-/dts-v1/;
-
-#include "omap34xx.dtsi"
 
 / {
        pwmleds {
diff --git a/arch/arm/boot/dts/omap3-tobi.dts b/arch/arm/boot/dts/omap3-tobi.dts
deleted file mode 100644 (file)
index 7e4ad2a..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 Florian Vaussard, EPFL Mobots group
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * Tobi expansion board is manufactured by Gumstix Inc.
- */
-
-#include "omap3-overo.dtsi"
-
-/ {
-       model = "TI OMAP3 Gumstix Overo on Tobi";
-       compatible = "ti,omap3-tobi", "ti,omap3-overo", "ti,omap3";
-
-       leds {
-               compatible = "gpio-leds";
-               heartbeat {
-                       label = "overo:red:gpio21";
-                       gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
-                       linux,default-trigger = "heartbeat";
-               };
-       };
-
-       vddvario: regulator-vddvario {
-                 compatible = "regulator-fixed";
-                 regulator-name = "vddvario";
-                 regulator-always-on;
-       };
-
-       vdd33a: regulator-vdd33a {
-               compatible = "regulator-fixed";
-               regulator-name = "vdd33a";
-               regulator-always-on;
-       };
-};
-
-&gpmc {
-       ranges = <5 0 0x2c000000 0x1000000>;    /* CS5 */
-
-       ethernet@5,0 {
-               compatible = "smsc,lan9221", "smsc,lan9115";
-               reg = <5 0 0xff>;
-               bank-width = <2>;
-
-               gpmc,mux-add-data;
-               gpmc,cs-on-ns = <0>;
-               gpmc,cs-rd-off-ns = <42>;
-               gpmc,cs-wr-off-ns = <36>;
-               gpmc,adv-on-ns = <6>;
-               gpmc,adv-rd-off-ns = <12>;
-               gpmc,adv-wr-off-ns = <12>;
-               gpmc,oe-on-ns = <0>;
-               gpmc,oe-off-ns = <42>;
-               gpmc,we-on-ns = <0>;
-               gpmc,we-off-ns = <36>;
-               gpmc,rd-cycle-ns = <60>;
-               gpmc,wr-cycle-ns = <54>;
-               gpmc,access-ns = <36>;
-               gpmc,page-burst-access-ns = <0>;
-               gpmc,bus-turnaround-ns = <0>;
-               gpmc,cycle2cycle-delay-ns = <0>;
-               gpmc,wr-data-mux-bus-ns = <18>;
-               gpmc,wr-access-ns = <42>;
-               gpmc,cycle2cycle-samecsen;
-               gpmc,cycle2cycle-diffcsen;
-
-               interrupt-parent = <&gpio6>;
-               interrupts = <16 IRQ_TYPE_LEVEL_LOW>;   /* GPIO 176 */
-               reg-io-width = <4>;
-       };
-};
-
-&i2c3 {
-       clock-frequency = <100000>;
-};
-
-&mmc3 {
-       status = "disabled";
-};
index 52447c17537a17c6035bf33694909e7252b78733..3d5faf85f51be4c283451b263e22450650019d7c 100644 (file)
                        compatible = "atmel,at91rm9200-ohci", "usb-ohci";
                        reg = <0x00600000 0x100000>;
                        interrupts = <32 IRQ_TYPE_LEVEL_HIGH 2>;
-                       clocks = <&usb>, <&uhphs_clk>, <&udphs_clk>,
+                       clocks = <&usb>, <&uhphs_clk>, <&uhphs_clk>,
                                 <&uhpck>;
                        clock-names = "usb_clk", "ohci_clk", "hclk", "uhpck";
                        status = "disabled";
index 6c31c26e6cc09511b9e4cd11b12dc946ecea8aeb..db58cad6acd32633b88bf88a0589885bfa58ed9b 100644 (file)
@@ -8,8 +8,8 @@
  */
 #include "sama5d3.dtsi"
 #include "sama5d3_can.dtsi"
-#include "sama5d3_emac.dtsi"
 #include "sama5d3_gmac.dtsi"
+#include "sama5d3_emac.dtsi"
 #include "sama5d3_lcd.dtsi"
 #include "sama5d3_mci2.dtsi"
 #include "sama5d3_tcb1.dtsi"
index 0c1e8d871ed1a45662198501fb133aa29bf46af0..6cb9b68e2188a59fecb89e750023551a17c0334f 100644 (file)
                msp2: msp@80117000 {
                        pinctrl-names = "default";
                        pinctrl-0 = <&msp2_default_mode>;
-                       status = "okay";
                };
 
                msp3: msp@80125000 {
index 040bb0eba1526f9747ad9955f874c39f3a757d85..d4d2763f47948b65f7f0890696699a4b2b98f245 100644 (file)
                ranges;
 
                emac: ethernet@01c0b000 {
-                       compatible = "allwinner,sun4i-emac";
+                       compatible = "allwinner,sun4i-a10-emac";
                        reg = <0x01c0b000 0x1000>;
                        interrupts = <55>;
                        clocks = <&ahb_gates 17>;
                };
 
                mdio@01c0b080 {
-                       compatible = "allwinner,sun4i-mdio";
+                       compatible = "allwinner,sun4i-a10-mdio";
                        reg = <0x01c0b080 0x14>;
                        status = "disabled";
                        #address-cells = <1>;
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index ea16054857a497e4794167402d4a0a456f2f378f..79fd412005b02860c5dcb8712418273584fa3b8f 100644 (file)
                ranges;
 
                emac: ethernet@01c0b000 {
-                       compatible = "allwinner,sun4i-emac";
+                       compatible = "allwinner,sun4i-a10-emac";
                        reg = <0x01c0b000 0x1000>;
                        interrupts = <55>;
                        clocks = <&ahb_gates 17>;
                };
 
                mdio@01c0b080 {
-                       compatible = "allwinner,sun4i-mdio";
+                       compatible = "allwinner,sun4i-a10-mdio";
                        reg = <0x01c0b080 0x14>;
                        status = "disabled";
                        #address-cells = <1>;
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 320335abfccd763118408f3f836c0fba39ca6f69..c463fd730c9155d8c9a491cf176a7320831e29fd 100644 (file)
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <29>;
                };
index 119f066f0d98aa16221855e04e8a3f83e4afe33e..6f25cf559ad0c99f5b376ba2a05e2e629878f35b 100644 (file)
                ranges;
 
                emac: ethernet@01c0b000 {
-                       compatible = "allwinner,sun4i-emac";
+                       compatible = "allwinner,sun4i-a10-emac";
                        reg = <0x01c0b000 0x1000>;
                        interrupts = <0 55 4>;
                        clocks = <&ahb_gates 17>;
                };
 
                mdio@01c0b080 {
-                       compatible = "allwinner,sun4i-mdio";
+                       compatible = "allwinner,sun4i-a10-mdio";
                        reg = <0x01c0b080 0x14>;
                        status = "disabled";
                        #address-cells = <1>;
                rtc: rtc@01c20d00 {
                        compatible = "allwinner,sun7i-a20-rtc";
                        reg = <0x01c20d00 0x20>;
-                       interrupts = <0 24 1>;
+                       interrupts = <0 24 4>;
                };
 
                sid: eeprom@01c23800 {
                };
 
                rtp: rtp@01c25000 {
-                       compatible = "allwinner,sun4i-ts";
+                       compatible = "allwinner,sun4i-a10-ts";
                        reg = <0x01c25000 0x100>;
                        interrupts = <0 29 4>;
                };
                hstimer@01c60000 {
                        compatible = "allwinner,sun7i-a20-hstimer";
                        reg = <0x01c60000 0x1000>;
-                       interrupts = <0 81 1>,
-                                    <0 82 1>,
-                                    <0 83 1>,
-                                    <0 84 1>;
+                       interrupts = <0 81 4>,
+                                    <0 82 4>,
+                                    <0 83 4>,
+                                    <0 84 4>;
                        clocks = <&ahb_gates 28>;
                };
 
index 389e987ec2819e31725329102f84d6f3cecbb5cd..44ec401ec36682289d8e4afa3b9b87791cd82c73 100644 (file)
@@ -57,6 +57,8 @@
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
+                       nvidia,head = <0>;
+
                        rgb {
                                status = "disabled";
                        };
@@ -72,6 +74,8 @@
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
+                       nvidia,head = <1>;
+
                        rgb {
                                status = "disabled";
                        };
index 480ecda3416b841b8941105d24646f1240f5ab37..48d2a7f4d0c05e2808a5cb2150298c41c1aa3367 100644 (file)
@@ -94,6 +94,8 @@
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
+                       nvidia,head = <0>;
+
                        rgb {
                                status = "disabled";
                        };
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
+                       nvidia,head = <1>;
+
                        rgb {
                                status = "disabled";
                        };
index 9104224124eeaac83bcedbd0e2fb7bcb3887d631..1e156d9d0506085c4ea615ac8c7e06193573edcb 100644 (file)
@@ -28,7 +28,7 @@
        compatible = "nvidia,cardhu", "nvidia,tegra30";
 
        aliases {
-               rtc0 = "/i2c@7000d000/tps6586x@34";
+               rtc0 = "/i2c@7000d000/tps65911@2d";
                rtc1 = "/rtc@7000e000";
        };
 
index ed8e7700b46dac0ba9d5ba34754fb5f8ae3dd976..19a84e933f4eae0799fc194b386bfdc51b85b880 100644 (file)
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
+                       nvidia,head = <0>;
+
                        rgb {
                                status = "disabled";
                        };
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
+                       nvidia,head = <1>;
+
                        rgb {
                                status = "disabled";
                        };
diff --git a/arch/arm/boot/dts/testcases/tests-interrupts.dtsi b/arch/arm/boot/dts/testcases/tests-interrupts.dtsi
deleted file mode 100644 (file)
index c843720..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-
-/ {
-       testcase-data {
-               interrupts {
-                       #address-cells = <1>;
-                       #size-cells = <1>;
-                       test_intc0: intc0 {
-                               interrupt-controller;
-                               #interrupt-cells = <1>;
-                       };
-
-                       test_intc1: intc1 {
-                               interrupt-controller;
-                               #interrupt-cells = <3>;
-                       };
-
-                       test_intc2: intc2 {
-                               interrupt-controller;
-                               #interrupt-cells = <2>;
-                       };
-
-                       test_intmap0: intmap0 {
-                               #interrupt-cells = <1>;
-                               #address-cells = <0>;
-                               interrupt-map = <1 &test_intc0 9>,
-                                               <2 &test_intc1 10 11 12>,
-                                               <3 &test_intc2 13 14>,
-                                               <4 &test_intc2 15 16>;
-                       };
-
-                       test_intmap1: intmap1 {
-                               #interrupt-cells = <2>;
-                               interrupt-map = <0x5000 1 2 &test_intc0 15>;
-                       };
-
-                       interrupts0 {
-                               interrupt-parent = <&test_intc0>;
-                               interrupts = <1>, <2>, <3>, <4>;
-                       };
-
-                       interrupts1 {
-                               interrupt-parent = <&test_intmap0>;
-                               interrupts = <1>, <2>, <3>, <4>;
-                       };
-
-                       interrupts-extended0 {
-                               reg = <0x5000 0x100>;
-                               interrupts-extended = <&test_intc0 1>,
-                                                     <&test_intc1 2 3 4>,
-                                                     <&test_intc2 5 6>,
-                                                     <&test_intmap0 1>,
-                                                     <&test_intmap0 2>,
-                                                     <&test_intmap0 3>,
-                                                     <&test_intmap1 1 2>;
-                       };
-               };
-       };
-};
diff --git a/arch/arm/boot/dts/testcases/tests-phandle.dtsi b/arch/arm/boot/dts/testcases/tests-phandle.dtsi
deleted file mode 100644 (file)
index 0007d3c..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-
-/ {
-       testcase-data {
-               phandle-tests {
-                       provider0: provider0 {
-                               #phandle-cells = <0>;
-                       };
-
-                       provider1: provider1 {
-                               #phandle-cells = <1>;
-                       };
-
-                       provider2: provider2 {
-                               #phandle-cells = <2>;
-                       };
-
-                       provider3: provider3 {
-                               #phandle-cells = <3>;
-                       };
-
-                       consumer-a {
-                               phandle-list =  <&provider1 1>,
-                                               <&provider2 2 0>,
-                                               <0>,
-                                               <&provider3 4 4 3>,
-                                               <&provider2 5 100>,
-                                               <&provider0>,
-                                               <&provider1 7>;
-                               phandle-list-names = "first", "second", "third";
-
-                               phandle-list-bad-phandle = <12345678 0 0>;
-                               phandle-list-bad-args = <&provider2 1 0>,
-                                                       <&provider3 0>;
-                               empty-property;
-                               unterminated-string = [40 41 42 43];
-                       };
-               };
-       };
-};
diff --git a/arch/arm/boot/dts/testcases/tests.dtsi b/arch/arm/boot/dts/testcases/tests.dtsi
deleted file mode 100644 (file)
index 3f123ec..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/include/ "tests-phandle.dtsi"
-/include/ "tests-interrupts.dtsi"
index f43907c40c93a8cb9b101d72043fc48621e0f795..65f6577113235749c3635dc30d321fa3c775b1c0 100644 (file)
@@ -1,4 +1,4 @@
-/include/ "versatile-ab.dts"
+#include <versatile-ab.dts>
 
 / {
        model = "ARM Versatile PB";
@@ -47,4 +47,4 @@
        };
 };
 
-/include/ "testcases/tests.dtsi"
+#include <testcases.dtsi>
index 845bc745706b53ff616dacf908679c9435113e8d..ee6982976d661d0086ff9886851ec9948e4ee909 100644 (file)
@@ -29,6 +29,7 @@ CONFIG_ARCH_OMAP3=y
 CONFIG_ARCH_OMAP4=y
 CONFIG_SOC_OMAP5=y
 CONFIG_SOC_AM33XX=y
+CONFIG_SOC_DRA7XX=y
 CONFIG_SOC_AM43XX=y
 CONFIG_ARCH_ROCKCHIP=y
 CONFIG_ARCH_SOCFPGA=y
index 00fe9e9710fd77e4a11c4c9c8c6c03534d5e6690..27d69b558c5de2caf1be2b9ac79388ae997f562a 100644 (file)
@@ -204,7 +204,10 @@ CONFIG_MMC_BLOCK_MINORS=16
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_PLTFM=y
 CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=y
 CONFIG_LEDS_TRIGGER_ONESHOT=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
index e9a49fe0284e41c2f6d6d9448fb73e9a2ad99ead..8b8b61685a3436158923b30cc80106364e02d509 100644 (file)
@@ -212,6 +212,7 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 static inline void __flush_icache_all(void)
 {
        __flush_icache_preferred();
+       dsb();
 }
 
 /*
index 8756e4bcdba0609ff789a4f1efaa551faa39ed98..4afb376d9c7c13d07ea81502e17ba53f0554c122 100644 (file)
  */
 #define UL(x) _AC(x, UL)
 
+/* PAGE_OFFSET - the virtual address of the start of the kernel image */
+#define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
+
 #ifdef CONFIG_MMU
 
 /*
- * PAGE_OFFSET - the virtual address of the start of the kernel image
  * TASK_SIZE - the maximum size of a user space task.
  * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area
  */
-#define PAGE_OFFSET            UL(CONFIG_PAGE_OFFSET)
 #define TASK_SIZE              (UL(CONFIG_PAGE_OFFSET) - UL(SZ_16M))
 #define TASK_UNMAPPED_BASE     ALIGN(TASK_SIZE / 3, SZ_16M)
 
 #define END_MEM                (UL(CONFIG_DRAM_BASE) + CONFIG_DRAM_SIZE)
 #endif
 
-#ifndef PAGE_OFFSET
-#define PAGE_OFFSET            PLAT_PHYS_OFFSET
-#endif
-
 /*
  * The module can be at any place in ram in nommu mode.
  */
index 03243f7eeddfc57beebb8100132dae059f96af77..85c60adc8b60bd04a68c3012b0c22ec7c1bf9bba 100644 (file)
 /*
  * 2nd stage PTE definitions for LPAE.
  */
-#define L_PTE_S2_MT_UNCACHED    (_AT(pteval_t, 0x5) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_MT_WRITETHROUGH (_AT(pteval_t, 0xa) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_MT_WRITEBACK   (_AT(pteval_t, 0xf) << 2) /* MemAttr[3:0] */
-#define L_PTE_S2_RDONLY                 (_AT(pteval_t, 1) << 6)   /* HAP[1]   */
-#define L_PTE_S2_RDWR           (_AT(pteval_t, 3) << 6)   /* HAP[2:1] */
+#define L_PTE_S2_MT_UNCACHED           (_AT(pteval_t, 0x0) << 2) /* strongly ordered */
+#define L_PTE_S2_MT_WRITETHROUGH       (_AT(pteval_t, 0xa) << 2) /* normal inner write-through */
+#define L_PTE_S2_MT_WRITEBACK          (_AT(pteval_t, 0xf) << 2) /* normal inner write-back */
+#define L_PTE_S2_MT_DEV_SHARED         (_AT(pteval_t, 0x1) << 2) /* device */
+#define L_PTE_S2_MT_MASK               (_AT(pteval_t, 0xf) << 2)
 
-#define L_PMD_S2_RDWR           (_AT(pmdval_t, 3) << 6)   /* HAP[2:1] */
+#define L_PTE_S2_RDONLY                        (_AT(pteval_t, 1) << 6)   /* HAP[1]   */
+#define L_PTE_S2_RDWR                  (_AT(pteval_t, 3) << 6)   /* HAP[2:1] */
+
+#define L_PMD_S2_RDWR                  (_AT(pmdval_t, 3) << 6)   /* HAP[2:1] */
 
 /*
  * Hyp-mode PL2 PTE definitions for LPAE.
index ef3c6072aa45345ae4594f22aebbe9a9ebc538f1..ac4bfae26702b0be3333c1184f1ac552f6c0eddd 100644 (file)
 
 static inline void dsb_sev(void)
 {
-#if __LINUX_ARM_ARCH__ >= 7
-       __asm__ __volatile__ (
-               "dsb ishst\n"
-               SEV
-       );
-#else
-       __asm__ __volatile__ (
-               "mcr p15, 0, %0, c7, c10, 4\n"
-               SEV
-               : : "r" (0)
-       );
-#endif
+
+       dsb(ishst);
+       __asm__(SEV);
 }
 
 /*
index 47cd974e57ea3ca0de7e9feccd9e527c2ba39f1f..c96ecacb2021222936844a4807f39ef474965879 100644 (file)
@@ -177,6 +177,18 @@ __lookup_processor_type_data:
        .long   __proc_info_end
        .size   __lookup_processor_type_data, . - __lookup_processor_type_data
 
+__error_lpae:
+#ifdef CONFIG_DEBUG_LL
+       adr     r0, str_lpae
+       bl      printascii
+       b       __error
+str_lpae: .asciz "\nError: Kernel with LPAE support, but CPU does not support LPAE.\n"
+#else
+       b       __error
+#endif
+       .align
+ENDPROC(__error_lpae)
+
 __error_p:
 #ifdef CONFIG_DEBUG_LL
        adr     r0, str_p1
index 914616e0bdcd0c0108376a9e5834e9cb73219b51..f5f381d915560818dcf0d2200731a90b0c7ae404 100644 (file)
@@ -102,7 +102,7 @@ ENTRY(stext)
        and     r3, r3, #0xf                    @ extract VMSA support
        cmp     r3, #5                          @ long-descriptor translation table format?
  THUMB( it     lo )                            @ force fixup-able long branch encoding
-       blo     __error_p                       @ only classic page table format
+       blo     __error_lpae                    @ only classic page table format
 #endif
 
 #ifndef CONFIG_XIP_KERNEL
index b0df9761de6dc1109f727e0300ff91448f8fd55b..1e8b030dbefd8b2b19da27d9ca8ecabfaf610bba 100644 (file)
@@ -731,7 +731,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
        kernel_data.end     = virt_to_phys(_end - 1);
 
        for_each_memblock(memory, region) {
-               res = memblock_virt_alloc_low(sizeof(*res), 0);
+               res = memblock_virt_alloc(sizeof(*res), 0);
                res->name  = "System RAM";
                res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
                res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
index 1d8248ea5669fa81209b2a7a8a055b7855a8c1f3..bd18bb8b2770ced6a65e5b3ad50dd79963d49c3b 100644 (file)
@@ -878,7 +878,8 @@ static int hyp_init_cpu_pm_notifier(struct notifier_block *self,
                                    unsigned long cmd,
                                    void *v)
 {
-       if (cmd == CPU_PM_EXIT) {
+       if (cmd == CPU_PM_EXIT &&
+           __hyp_get_vectors() == hyp_default_vectors) {
                cpu_init_hyp_mode(NULL);
                return NOTIFY_OK;
        }
index ddc15539bad2c5996dcd5167e694b16dbdd9488b..0d68d4073068e8ad665840b8f51319e9b2bdbd89 100644 (file)
@@ -220,6 +220,10 @@ after_vfp_restore:
  * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c).  Return values are
  * passed in r0 and r1.
  *
+ * A function pointer with a value of 0xffffffff has a special meaning,
+ * and is used to implement __hyp_get_vectors in the same way as in
+ * arch/arm/kernel/hyp_stub.S.
+ *
  * The calling convention follows the standard AAPCS:
  *   r0 - r3: caller save
  *   r12:     caller save
@@ -363,6 +367,11 @@ hyp_hvc:
 host_switch_to_hyp:
        pop     {r0, r1, r2}
 
+       /* Check for __hyp_get_vectors */
+       cmp     r0, #-1
+       mrceq   p15, 4, r0, c12, c0, 0  @ get HVBAR
+       beq     1f
+
        push    {lr}
        mrs     lr, SPSR
        push    {lr}
@@ -378,7 +387,7 @@ THUMB(      orr     lr, #1)
        pop     {lr}
        msr     SPSR_csxf, lr
        pop     {lr}
-       eret
+1:     eret
 
 guest_trap:
        load_vcpu                       @ Load VCPU pointer to r0
index 8f4649b301b2b8edba6f03e190719a967b883657..1abae5f6a4181013a83e286d8ec9b1518179ce39 100644 (file)
@@ -8,7 +8,7 @@ config ARCH_HI3xxx
        select CLKSRC_OF
        select GENERIC_CLOCKEVENTS
        select HAVE_ARM_SCU
-       select HAVE_ARM_TWD
+       select HAVE_ARM_TWD if SMP
        select HAVE_SMP
        select PINCTRL
        select PINCTRL_SINGLE
index befcaf5d05740c4ad1a417d8be62ddae9a38f59a..ec419649320ffe8fd6cae929d4664ae8071c9fff 100644 (file)
@@ -101,11 +101,9 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 obj-$(CONFIG_SOC_IMX6Q) += clk-imx6q.o mach-imx6q.o
 obj-$(CONFIG_SOC_IMX6SL) += clk-imx6sl.o mach-imx6sl.o
 
-ifeq ($(CONFIG_PM),y)
 obj-$(CONFIG_SOC_IMX6Q) += pm-imx6q.o headsmp.o
 # i.MX6SL reuses i.MX6Q code
 obj-$(CONFIG_SOC_IMX6SL) += pm-imx6q.o headsmp.o
-endif
 
 # i.MX5 based machines
 obj-$(CONFIG_MACH_MX51_BABBAGE) += mach-mx51_babbage.o
index af2e582d2b7427e1ffa72b65fb3b90bcdb257c3a..4d677f4425399c03c07827c7fca39719ca00620c 100644 (file)
@@ -482,6 +482,9 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
        if (IS_ENABLED(CONFIG_PCI_IMX6))
                clk_set_parent(clk[lvds1_sel], clk[sata_ref]);
 
+       /* Set initial power mode */
+       imx6q_set_lpm(WAIT_CLOCKED);
+
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
        base = of_iomap(np, 0);
        WARN_ON(!base);
index 3781a1853998c30520961cde9c27dd02e8068267..4c86f303520573d544528c983cade541135e71a2 100644 (file)
@@ -266,6 +266,9 @@ static void __init imx6sl_clocks_init(struct device_node *ccm_node)
        /* Audio-related clocks configuration */
        clk_set_parent(clks[IMX6SL_CLK_SPDIF0_SEL], clks[IMX6SL_CLK_PLL3_PFD3]);
 
+       /* Set initial power mode */
+       imx6q_set_lpm(WAIT_CLOCKED);
+
        np = of_find_compatible_node(NULL, NULL, "fsl,imx6sl-gpt");
        base = of_iomap(np, 0);
        WARN_ON(!base);
index 59c3b9b26bb40bbabe40f471d6a420efee43a1c2..baf439dc22d8268d65bd269f508c968aae822046 100644 (file)
@@ -144,13 +144,11 @@ void imx6q_set_chicken_bit(void);
 void imx_cpu_die(unsigned int cpu);
 int imx_cpu_kill(unsigned int cpu);
 
-#ifdef CONFIG_PM
 void imx6q_pm_init(void);
 void imx6q_pm_set_ccm_base(void __iomem *base);
+#ifdef CONFIG_PM
 void imx5_pm_init(void);
 #else
-static inline void imx6q_pm_init(void) {}
-static inline void imx6q_pm_set_ccm_base(void __iomem *base) {}
 static inline void imx5_pm_init(void) {}
 #endif
 
index 9d47adc078aa76cac2262063dfc94d3d54a6966b..7a9b98589db7260ea0c56deca6872b3667158c2a 100644 (file)
@@ -236,8 +236,6 @@ void __init imx6q_pm_init(void)
                regmap_update_bits(gpr, IOMUXC_GPR1, IMX6Q_GPR1_GINT,
                                   IMX6Q_GPR1_GINT);
 
-       /* Set initial power mode */
-       imx6q_set_lpm(WAIT_CLOCKED);
 
        suspend_set_ops(&imx6q_pm_ops);
 }
index ba470d64493bc18abf610f765259409df92d08bf..3795ae28a6134637cf06226d2b50629ff5ad586c 100644 (file)
@@ -2,7 +2,6 @@ config ARCH_MOXART
        bool "MOXA ART SoC" if ARCH_MULTI_V4T
        select CPU_FA526
        select ARM_DMA_MEM_BUFFERABLE
-       select DMA_OF
        select USE_OF
        select CLKSRC_OF
        select CLKSRC_MMIO
index 91449c5cb70f46affaf85602ec8f98b6f393d10f..85089d821982193b2e2d79f5f5fbf050eefad464 100644 (file)
@@ -156,6 +156,7 @@ static struct omap_usb_config nokia770_usb_config __initdata = {
        .register_dev   = 1,
        .hmc_mode       = 16,
        .pins[0]        = 6,
+       .extcon         = "tahvo-usb",
 };
 
 #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
index 653b489479e0ee2d4166d6d033d315a1e56430e4..0af7ca02314d99aa72baefb69959ccfba3380758 100644 (file)
@@ -50,11 +50,12 @@ config SOC_OMAP5
        bool "TI OMAP5"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select ARM_GIC
        select CPU_V7
        select HAVE_ARM_SCU if SMP
-       select HAVE_ARM_TWD if LOCAL_TIMERS
+       select HAVE_ARM_TWD if SMP
        select HAVE_SMP
        select HAVE_ARM_ARCH_TIMER
        select ARM_ERRATA_798181 if SMP
@@ -63,6 +64,7 @@ config SOC_AM33XX
        bool "TI AM33XX"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select CPU_V7
        select MULTI_IRQ_HANDLER
@@ -72,6 +74,7 @@ config SOC_AM43XX
        depends on ARCH_MULTI_V7
        select CPU_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select MULTI_IRQ_HANDLER
        select ARM_GIC
        select MACH_OMAP_GENERIC
@@ -80,6 +83,7 @@ config SOC_DRA7XX
        bool "TI DRA7XX"
        depends on ARCH_MULTI_V7
        select ARCH_OMAP2PLUS
+       select ARCH_HAS_OPP
        select ARM_CPU_SUSPEND if PM
        select ARM_GIC
        select CPU_V7
@@ -268,9 +272,6 @@ config MACH_OMAP_3430SDP
        default y
        select OMAP_PACKAGE_CBB
 
-config MACH_NOKIA_N800
-       bool
-
 config MACH_NOKIA_N810
        bool
 
@@ -281,7 +282,6 @@ config MACH_NOKIA_N8X0
        bool "Nokia N800/N810"
        depends on SOC_OMAP2420
        default y
-       select MACH_NOKIA_N800
        select MACH_NOKIA_N810
        select MACH_NOKIA_N810_WIMAX
        select OMAP_PACKAGE_ZAC
index 3b05aea56d1f5636d5ff2e154513cf22349b3eec..11ed9152e665274793ee83f50881efc2d9fbdded 100644 (file)
@@ -433,7 +433,9 @@ static const struct clk_ops dpll4_m5x2_ck_ops = {
        .enable         = &omap2_dflt_clk_enable,
        .disable        = &omap2_dflt_clk_disable,
        .is_enabled     = &omap2_dflt_clk_is_enabled,
+       .set_rate       = &omap3_clkoutx2_set_rate,
        .recalc_rate    = &omap3_clkoutx2_recalc,
+       .round_rate     = &omap3_clkoutx2_round_rate,
 };
 
 static const struct clk_ops dpll4_m5x2_ck_3630_ops = {
index 4c158c838d4062e1eaee78ff770e4b9dc257146f..01fc710c81818e9d48e2b26ca8742b77b392ff1c 100644 (file)
@@ -23,6 +23,8 @@
 #include "prm.h"
 #include "clockdomain.h"
 
+#define MAX_CPUS       2
+
 /* Machine specific information */
 struct idle_statedata {
        u32 cpu_state;
@@ -48,11 +50,11 @@ static struct idle_statedata omap4_idle_data[] = {
        },
 };
 
-static struct powerdomain *mpu_pd, *cpu_pd[NR_CPUS];
-static struct clockdomain *cpu_clkdm[NR_CPUS];
+static struct powerdomain *mpu_pd, *cpu_pd[MAX_CPUS];
+static struct clockdomain *cpu_clkdm[MAX_CPUS];
 
 static atomic_t abort_barrier;
-static bool cpu_done[NR_CPUS];
+static bool cpu_done[MAX_CPUS];
 static struct idle_statedata *state_ptr = &omap4_idle_data[0];
 
 /* Private functions */
index 3185ced807c952804d50199fd3ff7bc8ea68fb8f..3c418ea54bbe1a483ddc37759f0580ca7c949dd5 100644 (file)
@@ -623,6 +623,32 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
 
 /* Clock control for DPLL outputs */
 
+/* Find the parent DPLL for the given clkoutx2 clock */
+static struct clk_hw_omap *omap3_find_clkoutx2_dpll(struct clk_hw *hw)
+{
+       struct clk_hw_omap *pclk = NULL;
+       struct clk *parent;
+
+       /* Walk up the parents of clk, looking for a DPLL */
+       do {
+               do {
+                       parent = __clk_get_parent(hw->clk);
+                       hw = __clk_get_hw(parent);
+               } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
+               if (!hw)
+                       break;
+               pclk = to_clk_hw_omap(hw);
+       } while (pclk && !pclk->dpll_data);
+
+       /* clk does not have a DPLL as a parent?  error in the clock data */
+       if (!pclk) {
+               WARN_ON(1);
+               return NULL;
+       }
+
+       return pclk;
+}
+
 /**
  * omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
  * @clk: DPLL output struct clk
@@ -637,27 +663,14 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        unsigned long rate;
        u32 v;
        struct clk_hw_omap *pclk = NULL;
-       struct clk *parent;
 
        if (!parent_rate)
                return 0;
 
-       /* Walk up the parents of clk, looking for a DPLL */
-       do {
-               do {
-                       parent = __clk_get_parent(hw->clk);
-                       hw = __clk_get_hw(parent);
-               } while (hw && (__clk_get_flags(hw->clk) & CLK_IS_BASIC));
-               if (!hw)
-                       break;
-               pclk = to_clk_hw_omap(hw);
-       } while (pclk && !pclk->dpll_data);
+       pclk = omap3_find_clkoutx2_dpll(hw);
 
-       /* clk does not have a DPLL as a parent?  error in the clock data */
-       if (!pclk) {
-               WARN_ON(1);
+       if (!pclk)
                return 0;
-       }
 
        dd = pclk->dpll_data;
 
@@ -672,6 +685,55 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        return rate;
 }
 
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate)
+{
+       return 0;
+}
+
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate)
+{
+       const struct dpll_data *dd;
+       u32 v;
+       struct clk_hw_omap *pclk = NULL;
+
+       if (!*prate)
+               return 0;
+
+       pclk = omap3_find_clkoutx2_dpll(hw);
+
+       if (!pclk)
+               return 0;
+
+       dd = pclk->dpll_data;
+
+       /* TYPE J does not have a clkoutx2 */
+       if (dd->flags & DPLL_J_TYPE) {
+               *prate = __clk_round_rate(__clk_get_parent(pclk->hw.clk), rate);
+               return *prate;
+       }
+
+       WARN_ON(!dd->enable_mask);
+
+       v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
+       v >>= __ffs(dd->enable_mask);
+
+       /* If in bypass, the rate is fixed to the bypass rate*/
+       if (v != OMAP3XXX_EN_DPLL_LOCKED)
+               return *prate;
+
+       if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+               unsigned long best_parent;
+
+               best_parent = (rate / 2);
+               *prate = __clk_round_rate(__clk_get_parent(hw->clk),
+                               best_parent);
+       }
+
+       return *prate * 2;
+}
+
 /* OMAP3/4 non-CORE DPLL clkops */
 const struct clk_hw_omap_ops clkhwops_omap3_dpll = {
        .allow_idle     = omap3_dpll_allow_idle,
index d24926e6340fa714cf0aeacca14a6578e5b481a4..ab43755364f5a7c06ecfc367c0f055d65876dc54 100644 (file)
@@ -1339,7 +1339,7 @@ static void __maybe_unused gpmc_read_timings_dt(struct device_node *np,
                of_property_read_bool(np, "gpmc,time-para-granularity");
 }
 
-#ifdef CONFIG_MTD_NAND
+#if IS_ENABLED(CONFIG_MTD_NAND)
 
 static const char * const nand_xfer_types[] = {
        [NAND_OMAP_PREFETCH_POLLED]             = "prefetch-polled",
@@ -1429,7 +1429,7 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
 }
 #endif
 
-#ifdef CONFIG_MTD_ONENAND
+#if IS_ENABLED(CONFIG_MTD_ONENAND)
 static int gpmc_probe_onenand_child(struct platform_device *pdev,
                                 struct device_node *child)
 {
index d408b15b4fbfd97ecd3d82aaa46cc86788e63a8c..af432b191255030a7c8fda2be849be0a75620482 100644 (file)
@@ -179,15 +179,6 @@ static struct map_desc omap34xx_io_desc[] __initdata = {
                .length         = L4_EMU_34XX_SIZE,
                .type           = MT_DEVICE
        },
-#if defined(CONFIG_DEBUG_LL) &&                                                        \
-       (defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3))
-       {
-               .virtual        = ZOOM_UART_VIRT,
-               .pfn            = __phys_to_pfn(ZOOM_UART_BASE),
-               .length         = SZ_1M,
-               .type           = MT_DEVICE
-       },
-#endif
 };
 #endif
 
index 42d81885c700c498babd2dd2e5d322e3af2c3f19..1f33f5db10d5a2dde0d90bd29f1eb6fce9b65995 100644 (file)
@@ -1946,30 +1946,32 @@ static int _ocp_softreset(struct omap_hwmod *oh)
        if (ret)
                goto dis_opt_clks;
 
-       _write_sysconfig(v, oh);
-       ret = _clear_softreset(oh, &v);
-       if (ret)
-               goto dis_opt_clks;
-
        _write_sysconfig(v, oh);
 
        if (oh->class->sysc->srst_udelay)
                udelay(oh->class->sysc->srst_udelay);
 
        c = _wait_softreset_complete(oh);
-       if (c == MAX_MODULE_SOFTRESET_WAIT)
+       if (c == MAX_MODULE_SOFTRESET_WAIT) {
                pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
                           oh->name, MAX_MODULE_SOFTRESET_WAIT);
-       else
+               ret = -ETIMEDOUT;
+               goto dis_opt_clks;
+       } else {
                pr_debug("omap_hwmod: %s: softreset in %d usec\n", oh->name, c);
+       }
+
+       ret = _clear_softreset(oh, &v);
+       if (ret)
+               goto dis_opt_clks;
+
+       _write_sysconfig(v, oh);
 
        /*
         * XXX add _HWMOD_STATE_WEDGED for modules that don't come back from
         * _wait_target_ready() or _reset()
         */
 
-       ret = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
-
 dis_opt_clks:
        if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
                _disable_optional_clocks(oh);
index 18f333c440db3b72ff49577ef71d24b64dbcc916..810c205d668bfa5040ed2ad0458b412eb83b538e 100644 (file)
@@ -1365,11 +1365,10 @@ static struct omap_hwmod_class_sysconfig dra7xx_spinlock_sysc = {
        .rev_offs       = 0x0000,
        .sysc_offs      = 0x0010,
        .syss_offs      = 0x0014,
-       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
-                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
-                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
-       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
-                          SIDLE_SMART_WKUP),
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
        .sysc_fields    = &omap_hwmod_sysc_type1,
 };
 
index 3d5b24dcd9a41e2b7f4c16052bc2d931de74a0e4..c33e07e2f0d4e3d01b9e58e6347d4ca42ed81a18 100644 (file)
@@ -22,6 +22,8 @@
 #include "common-board-devices.h"
 #include "dss-common.h"
 #include "control.h"
+#include "omap-secure.h"
+#include "soc.h"
 
 struct pdata_init {
        const char *compatible;
@@ -169,6 +171,22 @@ static void __init am3517_evm_legacy_init(void)
        omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
        omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
 }
+
+static void __init nokia_n900_legacy_init(void)
+{
+       hsmmc2_internal_input_clk();
+
+       if (omap_type() == OMAP2_DEVICE_TYPE_SEC) {
+               if (IS_ENABLED(CONFIG_ARM_ERRATA_430973)) {
+                       pr_info("RX-51: Enabling ARM errata 430973 workaround\n");
+                       /* set IBE to 1 */
+                       rx51_secure_update_aux_cr(BIT(6), 0);
+               } else {
+                       pr_warning("RX-51: Not enabling ARM errata 430973 workaround\n");
+                       pr_warning("Thumb binaries may crash randomly without this workaround\n");
+               }
+       }
+}
 #endif /* CONFIG_ARCH_OMAP3 */
 
 #ifdef CONFIG_ARCH_OMAP4
@@ -239,6 +257,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #endif
 #ifdef CONFIG_ARCH_OMAP3
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata),
+       OF_DEV_AUXDATA("ti,omap3-padconf", 0x480025a0, "480025a0.pinmux", &pcs_pdata),
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002a00, "48002a00.pinmux", &pcs_pdata),
        /* Only on am3517 */
        OF_DEV_AUXDATA("ti,davinci_mdio", 0x5c030000, "davinci_mdio.0", NULL),
@@ -259,7 +278,7 @@ struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 static struct pdata_init pdata_quirks[] __initdata = {
 #ifdef CONFIG_ARCH_OMAP3
        { "compulab,omap3-sbc-t3730", omap3_sbc_t3730_legacy_init, },
-       { "nokia,omap3-n900", hsmmc2_internal_input_clk, },
+       { "nokia,omap3-n900", nokia_n900_legacy_init, },
        { "nokia,omap3-n9", hsmmc2_internal_input_clk, },
        { "nokia,omap3-n950", hsmmc2_internal_input_clk, },
        { "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
index 6334b96b4097b6977ae29047040bf6990aed06a7..280f3c58abe505c9047e6027071ec8bafd720c57 100644 (file)
@@ -183,11 +183,11 @@ void omap4_prminst_global_warm_sw_reset(void)
                                        OMAP4_PRM_RSTCTRL_OFFSET);
        v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
        omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
-                                OMAP4430_PRM_DEVICE_INST,
+                                dev_inst,
                                 OMAP4_PRM_RSTCTRL_OFFSET);
 
        /* OCP barrier */
        v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
-                                   OMAP4430_PRM_DEVICE_INST,
+                                   dev_inst,
                                    OMAP4_PRM_RSTCTRL_OFFSET);
 }
index c9f309ae88c5b57d0ecf60ac8025d704df37bdc2..8b90c4f2d430829e42213cb0b23eebeab23600f6 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <mach/gumstix.h>
 #include <mach/mfp-pxa25x.h>
+#include <mach/irqs.h>
 #include <linux/platform_data/video-pxafb.h>
 
 #include "generic.h"
index 954641e6c8b1cec4f1b0f29ea8fae26f0cbfcdf3..1b0825911e62c168dd8c4cf144e4334f88def99c 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef ASM_ARCH_BALLOON3_H
 #define ASM_ARCH_BALLOON3_H
 
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */
+
 enum balloon3_features {
        BALLOON3_FEATURE_OHCI,
        BALLOON3_FEATURE_MMC,
index f3c3493b468dff61399381567e89dbb6d6c5eeda..c030d955bbd7adfddc4f606cf4c69fb25a26030b 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __ASM_ARCH_CORGI_H
 #define __ASM_ARCH_CORGI_H  1
 
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */
 
 /*
  * Corgi (Non Standard) GPIO Definitions
index 2628e7b721168c99cb8dc1214934bcdffbfa8e1c..00cfbbbf73f78d5a7dd4f6bb288046b6caad0251 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef CSB726_H
 #define CSB726_H
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 #define CSB726_GPIO_IRQ_LAN    52
 #define CSB726_GPIO_IRQ_SM501  53
 #define CSB726_GPIO_MMC_DETECT 100
index dba14b6503ad17008660d23f81306db42c72119c..f7df27bbb42e0099c8d9567793deb95bcd6ce316 100644 (file)
@@ -6,6 +6,7 @@
  * published by the Free Software Foundation.
  */
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
 
 /* BTRESET - Reset line to Bluetooth module, active low signal. */
 #define GPIO_GUMSTIX_BTRESET          7
index 22a96f87232b5d5bdf894b55624900e832d054f4..7e63f4680271f3bb8ab9f9fdc4983e9371618a72 100644 (file)
@@ -23,6 +23,7 @@
  * IDP hardware.
  */
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
 
 #define IDP_FLASH_PHYS         (PXA_CS0_PHYS)
 #define IDP_ALT_FLASH_PHYS     (PXA_CS1_PHYS)
index 2c4471336570f0c38563f8b19d61b2a1b3bd5ed3..b184f296023bbf22e3986b882f293d47426c11ac 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _INCLUDE_PALMLD_H_
 #define _INCLUDE_PALMLD_H_
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /** HERE ARE GPIOs **/
 
 /* GPIOs */
index 0bd4f036c72fbb1deda29f4a2097785a9aee8a5c..e342c59214053c2fcb05ed5ee8adb186c6ffa4a8 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef _INCLUDE_PALMT5_H_
 #define _INCLUDE_PALMT5_H_
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /** HERE ARE GPIOs **/
 
 /* GPIOs */
index c383a21680b6992e711f8397e0dee98498cb0c94..81c727b3cfd23c60bc31e88087e3299eca1e5b3b 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef _INCLUDE_PALMTC_H_
 #define _INCLUDE_PALMTC_H_
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /** HERE ARE GPIOs **/
 
 /* GPIOs */
index f2e5303802537d79bac10b397b7b1d17e23bdf3d..92bc1f05300dde13e9ee79b4f01d967221de7ee4 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef _INCLUDE_PALMTX_H_
 #define _INCLUDE_PALMTX_H_
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /** HERE ARE GPIOs **/
 
 /* GPIOs */
index 6bf28de228bdeb8952f14458a5ebde1a93653530..86ebd7b6c9602859b0713903cca0c70f97595bf4 100644 (file)
@@ -23,6 +23,8 @@
  * Definitions of CPU card resources only
  */
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /* phyCORE-PXA270 (PCM027) Interrupts */
 #define PCM027_IRQ(x)          (IRQ_BOARD_START + (x))
 #define PCM027_BTDET_IRQ       PCM027_IRQ(0)
index 0260aaa2fc178670e597014eff70f358a16c5ad1..7e544c14967ed45177a2cc8a3d393f5bfe5b90b8 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <mach/pcm027.h>
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
 
 /*
  * definitions relevant only when the PCM-990
index f32ff75dcca83abd42fb8dfc30ac7a8ebdbf9e59..b56b19351a0389d2cd8ac7d76f027b2bcf1b39ba 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __ASM_ARCH_POODLE_H
 #define __ASM_ARCH_POODLE_H  1
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /*
  * GPIOs
  */
index 0bfe6507c95dd2c4e89e8c23384a179ba1b0030d..25c9f62e46aa3fcbaae5210663b64fdaf6c18bb4 100644 (file)
@@ -15,8 +15,8 @@
 #define __ASM_ARCH_SPITZ_H  1
 #endif
 
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO, PXA_GPIO_TO_IRQ */
 #include <linux/fb.h>
-#include <linux/gpio.h>
 
 /* Spitz/Akita GPIOs */
 
index 2bb0e862598c41eeca0c20b36469b49f7cdc9692..0497d95cef25541c65da7c2e4b572784d191410e 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _ASM_ARCH_TOSA_H_
 #define _ASM_ARCH_TOSA_H_ 1
 
+#include "irqs.h" /* PXA_NR_BUILTIN_GPIO */
+
 /*  TOSA Chip selects  */
 #define TOSA_LCDC_PHYS         PXA_CS4_PHYS
 /* Internel Scoop */
index d2ca01053f697d888bb3d529e5f8a998efcbb27b..ae3ca013afabe82185104aecd3252f31a6a3434b 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef _TRIPEPS4_H_
 #define _TRIPEPS4_H_
 
+#include "irqs.h" /* PXA_GPIO_TO_IRQ */
+
 /* physical memory regions */
 #define TRIZEPS4_FLASH_PHYS    (PXA_CS0_PHYS)  /* Flash region */
 #define TRIZEPS4_DISK_PHYS     (PXA_CS1_PHYS)  /* Disk On Chip region */
index f70583fee59f8b61e59a1022f07b36c26fd3210c..29997bde277d1be730aa85d98a2ae17bc0bc2da5 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/reboot.h>
+#include <linux/regulator/fixed.h>
 #include <linux/regulator/max1586.h>
 #include <linux/slab.h>
 #include <linux/i2c/pxa-i2c.h>
@@ -714,6 +715,10 @@ static struct gpio global_gpios[] = {
        { GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" },
 };
 
+static struct regulator_consumer_supply fixed_5v0_consumers[] = {
+       REGULATOR_SUPPLY("power", "pwm-backlight"),
+};
+
 static void __init mioa701_machine_init(void)
 {
        int rc;
@@ -753,6 +758,10 @@ static void __init mioa701_machine_init(void)
        pxa_set_i2c_info(&i2c_pdata);
        pxa27x_set_i2c_power_info(NULL);
        pxa_set_camera_info(&mioa701_pxacamera_platform_data);
+
+       regulator_register_always_on(0, "fixed-5.0V", fixed_5v0_consumers,
+                                    ARRAY_SIZE(fixed_5v0_consumers),
+                                    5000000);
 }
 
 static void mioa701_machine_exit(void)
index f33679d2d3ee0a218d280972c5f409f0b561d41b..50e1d850ee2e01d6f29ee5004af4339f40c712b0 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef __ASM_ARCH_COLLIE_H
 #define __ASM_ARCH_COLLIE_H
 
+#include "hardware.h" /* Gives GPIO_MAX */
+
 extern void locomolcd_power(int on);
 
 #define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
index 338640631e08234ebcab2a5616dec8240e68aed8..05fa505df5850d0de63d013e9ebdecfdea1461e4 100644 (file)
@@ -8,7 +8,7 @@ config ARCH_SHMOBILE_MULTI
        select CPU_V7
        select GENERIC_CLOCKEVENTS
        select HAVE_ARM_SCU if SMP
-       select HAVE_ARM_TWD if LOCAL_TIMERS
+       select HAVE_ARM_TWD if SMP
        select HAVE_SMP
        select ARM_GIC
        select MIGHT_HAVE_CACHE_L2X0
index 4ae0286b468db6209311d14d13cd9cc673fb200b..f55b05a29b55f3ed655b36b1edf1f93f85d09c9d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/cpu_pm.h>
 #include <linux/suspend.h>
 #include <linux/err.h>
+#include <linux/slab.h>
 #include <linux/clk/tegra.h>
 
 #include <asm/smp_plat.h>
index 303a285d80fd7b7d7cc4280779c343b4a3123f4a..6191603379e13cad2da1552954c3e2fb903cc241 100644 (file)
@@ -73,10 +73,20 @@ u32 tegra_uart_config[3] = {
 static void __init tegra_init_cache(void)
 {
 #ifdef CONFIG_CACHE_L2X0
+       static const struct of_device_id pl310_ids[] __initconst = {
+               { .compatible = "arm,pl310-cache",  },
+               {}
+       };
+
+       struct device_node *np;
        int ret;
        void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
        u32 aux_ctrl, cache_type;
 
+       np = of_find_matching_node(NULL, pl310_ids);
+       if (!np)
+               return;
+
        cache_type = readl(p + L2X0_CACHE_TYPE);
        aux_ctrl = (cache_type & 0x700) << (17-8);
        aux_ctrl |= 0x7C400001;
index 1db2a5ca9ab8c8280dd11db69e1cc98538a76ba2..8c09a8393fb63056a171e12351e3a52d35d5de4d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/of.h>
+#include <linux/memblock.h>
 #include <linux/irqchip.h>
 #include <linux/irqchip/arm-gic.h>
 
 
 void __iomem *zynq_scu_base;
 
+/**
+ * zynq_memory_init - Initialize special memory
+ *
+ * We need to stop things allocating the low memory as DMA can't work in
+ * the 1st 512K of memory.
+ */
+static void __init zynq_memory_init(void)
+{
+       if (!__pa(PAGE_OFFSET))
+               memblock_reserve(__pa(PAGE_OFFSET), __pa(swapper_pg_dir));
+}
+
 static struct platform_device zynq_cpuidle_device = {
        .name = "cpuidle-zynq",
 };
@@ -117,5 +130,6 @@ DT_MACHINE_START(XILINX_EP107, "Xilinx Zynq Platform")
        .init_machine   = zynq_init_machine,
        .init_time      = zynq_timer_init,
        .dt_compat      = zynq_dt_match,
+       .reserve        = zynq_memory_init,
        .restart        = zynq_system_reset,
 MACHINE_END
index 1a77450e728ad17cf6b8fec2beb3111a2a8bfb94..11b3914660d2a9f518f15b09028d3dad78ad07e0 100644 (file)
@@ -1358,7 +1358,7 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
        *handle = DMA_ERROR_CODE;
        size = PAGE_ALIGN(size);
 
-       if (gfp & GFP_ATOMIC)
+       if (!(gfp & __GFP_WAIT))
                return __iommu_alloc_atomic(dev, size, handle);
 
        /*
index 2b3a56414271e5e31323566676097b774fca9406..ef69152f9b52e473796829545bf5cf5d1e83926a 100644 (file)
@@ -264,6 +264,9 @@ static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
                        note_page(st, addr, 3, pmd_val(*pmd));
                else
                        walk_pte(st, pmd, addr);
+
+               if (SECTION_SIZE < PMD_SIZE && pmd_large(pmd[1]))
+                       note_page(st, addr + SECTION_SIZE, 3, pmd_val(pmd[1]));
        }
 }
 
index d5a982d15a88e2a37a524267f31633f497aa0d4b..7ea641b7aa7d2b6ffd240b9fe0e7f7897a5a2d1a 100644 (file)
@@ -38,6 +38,7 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
 
 struct mem_type {
        pteval_t prot_pte;
+       pteval_t prot_pte_s2;
        pmdval_t prot_l1;
        pmdval_t prot_sect;
        unsigned int domain;
index 4f08c133cc255e2e2c2b93a0f28b79caaf3fc795..a623cb3ad012b196aacd11fc7f122fb84c0e3765 100644 (file)
@@ -232,12 +232,16 @@ __setup("noalign", noalign_setup);
 #endif /* ifdef CONFIG_CPU_CP15 / else */
 
 #define PROT_PTE_DEVICE                L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_XN
+#define PROT_PTE_S2_DEVICE     PROT_PTE_DEVICE
 #define PROT_SECT_DEVICE       PMD_TYPE_SECT|PMD_SECT_AP_WRITE
 
 static struct mem_type mem_types[] = {
        [MT_DEVICE] = {           /* Strongly ordered / ARMv6 shared device */
                .prot_pte       = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
                                  L_PTE_SHARED,
+               .prot_pte_s2    = s2_policy(PROT_PTE_S2_DEVICE) |
+                                 s2_policy(L_PTE_S2_MT_DEV_SHARED) |
+                                 L_PTE_SHARED,
                .prot_l1        = PMD_TYPE_TABLE,
                .prot_sect      = PROT_SECT_DEVICE | PMD_SECT_S,
                .domain         = DOMAIN_IO,
@@ -508,7 +512,8 @@ static void __init build_mem_type_table(void)
        cp = &cache_policies[cachepolicy];
        vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
        s2_pgprot = cp->pte_s2;
-       hyp_device_pgprot = s2_device_pgprot = mem_types[MT_DEVICE].prot_pte;
+       hyp_device_pgprot = mem_types[MT_DEVICE].prot_pte;
+       s2_device_pgprot = mem_types[MT_DEVICE].prot_pte_s2;
 
        /*
         * ARMv6 and above have extended page tables.
index 45dc29f85d56ca79ae7fa6076f3cee103465e15b..32b3558321c40db0d31e6898ad3ea329e049bca4 100644 (file)
@@ -208,7 +208,6 @@ __v6_setup:
        mcr     p15, 0, r0, c7, c14, 0          @ clean+invalidate D cache
        mcr     p15, 0, r0, c7, c5, 0           @ invalidate I cache
        mcr     p15, 0, r0, c7, c15, 0          @ clean+invalidate cache
-       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer
 #ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ invalidate I + D TLBs
        mcr     p15, 0, r0, c2, c0, 2           @ TTB control register
@@ -218,6 +217,8 @@ __v6_setup:
        ALT_UP(orr      r8, r8, #TTB_FLAGS_UP)
        mcr     p15, 0, r8, c2, c0, 1           @ load TTB1
 #endif /* CONFIG_MMU */
+       mcr     p15, 0, r0, c7, c10, 4          @ drain write buffer and
+                                               @ complete invalidations
        adr     r5, v6_crval
        ldmia   r5, {r5, r6}
  ARM_BE8(orr   r6, r6, #1 << 25)               @ big-endian page tables
index bd1781979a391825043d078192666e5a846cdae5..74f6033e76dd1702e89631334a813f5ea9ec1046 100644 (file)
@@ -351,7 +351,6 @@ __v7_setup:
 
 4:     mov     r10, #0
        mcr     p15, 0, r10, c7, c5, 0          @ I+BTB cache invalidate
-       dsb
 #ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7, 0          @ invalidate I + D TLBs
        v7_ttb_setup r10, r4, r8, r5            @ TTBCR, TTBRx setup
@@ -360,6 +359,7 @@ __v7_setup:
        mcr     p15, 0, r5, c10, c2, 0          @ write PRRR
        mcr     p15, 0, r6, c10, c2, 1          @ write NMRR
 #endif
+       dsb                                     @ Complete invalidations
 #ifndef CONFIG_ARM_THUMBEE
        mrc     p15, 0, r0, c0, c1, 0           @ read ID_PFR0 for ThumbEE
        and     r0, r0, #(0xf << 12)            @ ThumbEE enabled field
index 271b5e9715682ab40869a1ea8a02c9696eaebf07..6f879c319a9dbe9fc406946565da49a0e99f5eb8 100644 (file)
@@ -825,8 +825,8 @@ b_epilogue:
                        break;
                case BPF_S_ANC_RXHASH:
                        ctx->seen |= SEEN_SKB;
-                       BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
-                       off = offsetof(struct sk_buff, rxhash);
+                       BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+                       off = offsetof(struct sk_buff, hash);
                        emit(ARM_LDR_I(r_A, r_skb, off), ctx);
                        break;
                case BPF_S_ANC_VLAN_TAG:
@@ -925,6 +925,7 @@ void bpf_jit_compile(struct sk_filter *fp)
                bpf_jit_dump(fp->len, alloc_size, 2, ctx.target);
 
        fp->bpf_func = (void *)ctx.target;
+       fp->jited = 1;
 out:
        kfree(ctx.offsets);
        return;
@@ -932,7 +933,7 @@ out:
 
 void bpf_jit_free(struct sk_filter *fp)
 {
-       if (fp->bpf_func != sk_run_filter)
+       if (fp->jited)
                module_free(NULL, fp->bpf_func);
        kfree(fp);
 }
index 13fb0b3efc5f7206bb8e187ea07ff6c3337ff2be..453a179469a34fd9ffa72ec723a6bada988d4e73 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __ASM_PERCPU_H
 #define __ASM_PERCPU_H
 
+#ifdef CONFIG_SMP
+
 static inline void set_my_cpu_offset(unsigned long off)
 {
        asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
@@ -36,6 +38,12 @@ static inline unsigned long __my_cpu_offset(void)
 }
 #define __my_cpu_offset __my_cpu_offset()
 
+#else  /* !CONFIG_SMP */
+
+#define set_my_cpu_offset(x)   do { } while (0)
+
+#endif /* CONFIG_SMP */
+
 #include <asm-generic/percpu.h>
 
 #endif /* __ASM_PERCPU_H */
index b524dcd17243d712b4d461cf77d4dd56ed04c8bb..aa3917c8b62318aef9424735d560be305f3465d3 100644 (file)
@@ -136,11 +136,11 @@ extern struct page *empty_zero_page;
 /*
  * The following only work if pte_present(). Undefined behaviour otherwise.
  */
-#define pte_present(pte)       (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))
-#define pte_dirty(pte)         (pte_val(pte) & PTE_DIRTY)
-#define pte_young(pte)         (pte_val(pte) & PTE_AF)
-#define pte_special(pte)       (pte_val(pte) & PTE_SPECIAL)
-#define pte_write(pte)         (pte_val(pte) & PTE_WRITE)
+#define pte_present(pte)       (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
+#define pte_dirty(pte)         (!!(pte_val(pte) & PTE_DIRTY))
+#define pte_young(pte)         (!!(pte_val(pte) & PTE_AF))
+#define pte_special(pte)       (!!(pte_val(pte) & PTE_SPECIAL))
+#define pte_write(pte)         (!!(pte_val(pte) & PTE_WRITE))
 #define pte_exec(pte)          (!(pte_val(pte) & PTE_UXN))
 
 #define pte_valid_user(pte) \
index 495ab6f84a6117a43344a49707bd400698bcf737..eaf54a30bedcef3ee1b88b93e2e0f4741f0ef10d 100644 (file)
@@ -148,6 +148,15 @@ struct kvm_arch_memory_slot {
 #define KVM_REG_ARM_TIMER_CNT          ARM64_SYS_REG(3, 3, 14, 3, 2)
 #define KVM_REG_ARM_TIMER_CVAL         ARM64_SYS_REG(3, 3, 14, 0, 2)
 
+/* Device Control API: ARM VGIC */
+#define KVM_DEV_ARM_VGIC_GRP_ADDR      0
+#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
+#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS  2
+#define   KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
+#define   KVM_DEV_ARM_VGIC_CPUID_MASK  (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
+#define   KVM_DEV_ARM_VGIC_OFFSET_SHIFT        0
+#define   KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
+
 /* KVM_IRQ_LINE irq field index values */
 #define KVM_ARM_IRQ_TYPE_SHIFT         24
 #define KVM_ARM_IRQ_TYPE_MASK          0xff
index c3b6c63ea5fb3abe0f154544aee2eb09063c0eb8..38f0558f0c0a56a7a57fe9bb12d08eb01dea7cdc 100644 (file)
@@ -48,7 +48,11 @@ int unwind_frame(struct stackframe *frame)
 
        frame->sp = fp + 0x10;
        frame->fp = *(unsigned long *)(fp);
-       frame->pc = *(unsigned long *)(fp + 8);
+       /*
+        * -4 here because we care about the PC at time of bl,
+        * not where the return will go.
+        */
+       frame->pc = *(unsigned long *)(fp + 8) - 4;
 
        return 0;
 }
index 3b47c36e10ffcdac920a08277ee9e3e1df00a211..2c56012cb2d2c8d82588063058f4444e188d13f6 100644 (file)
@@ -694,6 +694,24 @@ __hyp_panic_str:
 
        .align  2
 
+/*
+ * u64 kvm_call_hyp(void *hypfn, ...);
+ *
+ * This is not really a variadic function in the classic C-way and care must
+ * be taken when calling this to ensure parameters are passed in registers
+ * only, since the stack will change between the caller and the callee.
+ *
+ * Call the function with the first argument containing a pointer to the
+ * function you wish to call in Hyp mode, and subsequent arguments will be
+ * passed as x0, x1, and x2 (a maximum of 3 arguments in addition to the
+ * function pointer can be passed).  The function being called must be mapped
+ * in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c).  Return values are
+ * passed in r0 and r1.
+ *
+ * A function pointer with a value of 0 has a special meaning, and is
+ * used to implement __hyp_get_vectors in the same way as in
+ * arch/arm64/kernel/hyp_stub.S.
+ */
 ENTRY(kvm_call_hyp)
        hvc     #0
        ret
@@ -737,7 +755,12 @@ el1_sync:                                  // Guest trapped into EL2
        pop     x2, x3
        pop     x0, x1
 
-       push    lr, xzr
+       /* Check for __hyp_get_vectors */
+       cbnz    x0, 1f
+       mrs     x0, vbar_el2
+       b       2f
+
+1:     push    lr, xzr
 
        /*
         * Compute the function address in EL2, and shuffle the parameters.
@@ -750,7 +773,7 @@ el1_sync:                                   // Guest trapped into EL2
        blr     lr
 
        pop     lr, xzr
-       eret
+2:     eret
 
 el1_trap:
        /*
index 22fb66590dcd0e6f7339c9723a9128eb078cdb06..dba48a5d5bb9db351ff62bafc23a62a7047b42b5 100644 (file)
@@ -11,7 +11,7 @@ all: uImage vmlinux.elf
 
 KBUILD_DEFCONFIG       := atstk1002_defconfig
 
-KBUILD_CFLAGS  += -pipe -fno-builtin -mno-pic
+KBUILD_CFLAGS  += -pipe -fno-builtin -mno-pic -D__linux__
 KBUILD_AFLAGS  += -mrelax -mno-pic
 KBUILD_CFLAGS_MODULE += -mno-relax
 LDFLAGS_vmlinux        += --relax
index 9764a1a1073e933aa1c2d6a73e51483553da2dfa..c1466a872b9c8598ca184f65eb32f3320669f4b1 100644 (file)
@@ -11,6 +11,7 @@
 #define FRAM_VERSION   "1.0"
 
 #include <linux/miscdevice.h>
+#include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/mm.h>
 #include <linux/io.h>
index cfb9fe1b8df9528b8bdbf8d2570b860af3fd4a4b..c7c64a63c29f470ebbec5071422d148ba9bc074a 100644 (file)
@@ -17,5 +17,6 @@ generic-y       += scatterlist.h
 generic-y       += sections.h
 generic-y       += topology.h
 generic-y      += trace_clock.h
+generic-y += vga.h
 generic-y       += xor.h
 generic-y      += hash.h
index fc6483f83ccca748a3dc4319bb1ee849f8435654..4f5ec2bb71727279a952843051f44e3297c7b222 100644 (file)
@@ -295,6 +295,8 @@ extern void __iounmap(void __iomem *addr);
 #define iounmap(addr)                          \
        __iounmap(addr)
 
+#define ioremap_wc ioremap_nocache
+
 #define cached(addr) P1SEGADDR(addr)
 #define uncached(addr) P2SEGADDR(addr)
 
index 09c5a0f5f4d1778156a5ee83715e6a2aec7f0441..86648c083bb4b1297275dc2bc4ceb3ecd949aa5b 100644 (file)
@@ -12,6 +12,7 @@
 #define _ASM_C6X_CACHE_H
 
 #include <linux/irqflags.h>
+#include <linux/init.h>
 
 /*
  * Cache line size
index 184066ceb1f6146c9254a778c8e9c7f6b9656668..053c17b3655926ed97427a927a83081ec289d224 100644 (file)
@@ -144,7 +144,7 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr)
  * definition, which doesn't have the same semantics.  We don't want to
  * use -fno-builtin, so just hide the name ffs.
  */
-#define ffs kernel_ffs
+#define ffs(x) kernel_ffs(x)
 
 #include <asm-generic/bitops/fls.h>
 #include <asm-generic/bitops/__fls.h>
index a96bcf83a735dae2f812f81e0fc54635bb3de072..20e8a9b21d7519ebf7d506e4825d83c05629ba37 100644 (file)
@@ -98,7 +98,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
        /* attempt to allocate a granule's worth of cached memory pages */
 
        page = alloc_pages_exact_node(nid,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                IA64_GRANULE_SHIFT-PAGE_SHIFT);
        if (!page) {
                mutex_unlock(&uc_pool->add_chunk_mutex);
index 7cc8c364924dff8e8529be82406f0acfb7dfe0f2..6fb9e813a91074cb8ae41205bb8f899bcc35cf38 100644 (file)
@@ -1,4 +1,4 @@
-
+generic-y += barrier.h
 generic-y += bitsperlong.h
 generic-y += clkdev.h
 generic-y += cputime.h
@@ -6,6 +6,7 @@ generic-y += device.h
 generic-y += emergency-restart.h
 generic-y += errno.h
 generic-y += exec.h
+generic-y += hash.h
 generic-y += hw_irq.h
 generic-y += ioctl.h
 generic-y += ipcbuf.h
@@ -18,6 +19,7 @@ generic-y += local.h
 generic-y += mman.h
 generic-y += mutex.h
 generic-y += percpu.h
+generic-y += preempt.h
 generic-y += resource.h
 generic-y += scatterlist.h
 generic-y += sections.h
@@ -31,5 +33,3 @@ generic-y += trace_clock.h
 generic-y += types.h
 generic-y += word-at-a-time.h
 generic-y += xor.h
-generic-y += preempt.h
-generic-y += hash.h
diff --git a/arch/m68k/include/asm/barrier.h b/arch/m68k/include/asm/barrier.h
deleted file mode 100644 (file)
index 15c5f77..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _M68K_BARRIER_H
-#define _M68K_BARRIER_H
-
-#define nop()          do { asm volatile ("nop"); barrier(); } while (0)
-
-#include <asm-generic/barrier.h>
-
-#endif /* _M68K_BARRIER_H */
index 014f288fc81354e0eb088e500184e7e032ea6ba3..9d38b73989eb597d677acd95ea53cf0ddb99b624 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            349
+#define NR_syscalls            351
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
index 625f321001dc077fe13da02eb0844a50099653dc..b932dd470041c2c5130dfcc44448c80033525259 100644 (file)
 #define __NR_process_vm_writev 346
 #define __NR_kcmp              347
 #define __NR_finit_module      348
+#define __NR_sched_setattr     349
+#define __NR_sched_getattr     350
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 3f04ea0ab802750866835fcd9c3aa75ac7b28282..b6223dc41d82870953be64b35fc409c4b5634070 100644 (file)
@@ -369,4 +369,6 @@ ENTRY(sys_call_table)
        .long sys_process_vm_writev
        .long sys_kcmp
        .long sys_finit_module
+       .long sys_sched_setattr
+       .long sys_sched_getattr         /* 350 */
 
index 05b7d39e4391218775b701c12d5138b25ca2ca34..66fc24c24238f64cac057fa33e9b330af10867e3 100644 (file)
@@ -13,6 +13,8 @@
 #ifndef _ASM_MICROBLAZE_DELAY_H
 #define _ASM_MICROBLAZE_DELAY_H
 
+#include <linux/param.h>
+
 extern inline void __delay(unsigned long loops)
 {
        asm volatile ("# __delay                \n\t"           \
index a2cea72060777a5df8fd1065f80e627d56a29787..3fbb7f1db3bcdcfbe867c9e6ab7ce3189d0a74c0 100644 (file)
@@ -89,6 +89,11 @@ static inline unsigned int readl(const volatile void __iomem *addr)
 {
        return le32_to_cpu(*(volatile unsigned int __force *)addr);
 }
+#define readq readq
+static inline u64 readq(const volatile void __iomem *addr)
+{
+       return le64_to_cpu(__raw_readq(addr));
+}
 static inline void writeb(unsigned char v, volatile void __iomem *addr)
 {
        *(volatile unsigned char __force *)addr = v;
@@ -101,6 +106,7 @@ static inline void writel(unsigned int v, volatile void __iomem *addr)
 {
        *(volatile unsigned int __force *)addr = cpu_to_le32(v);
 }
+#define writeq(b, addr) __raw_writeq(cpu_to_le64(b), addr)
 
 /* ioread and iowrite variants. thease are for now same as __raw_
  * variants of accessors. we might check for endianess in the feature
index b7fb0438458ca8960bd0a730ec9c0da520112136..17645b2e2f075d69a41fb4a4fcee7ba468c76c36 100644 (file)
@@ -66,7 +66,7 @@ real_start:
        mts     rmsr, r0
 /* Disable stack protection from bootloader */
        mts     rslr, r0
-       addi    r8, r0, 0xFFFFFFF
+       addi    r8, r0, 0xFFFFFFFF
        mts     rshr, r8
 /*
  * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
index dcae3a7035db55a278b1a8cac80faa5ac2199003..95fa1f1d5c8b4a70d3ee991e7a5bb32b5db22740 100644 (file)
@@ -1776,12 +1776,12 @@ endchoice
 
 config FORCE_MAX_ZONEORDER
        int "Maximum zone order"
-       range 14 64 if HUGETLB_PAGE && PAGE_SIZE_64KB
-       default "14" if HUGETLB_PAGE && PAGE_SIZE_64KB
-       range 13 64 if HUGETLB_PAGE && PAGE_SIZE_32KB
-       default "13" if HUGETLB_PAGE && PAGE_SIZE_32KB
-       range 12 64 if HUGETLB_PAGE && PAGE_SIZE_16KB
-       default "12" if HUGETLB_PAGE && PAGE_SIZE_16KB
+       range 14 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+       default "14" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_64KB
+       range 13 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+       default "13" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_32KB
+       range 12 64 if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
+       default "12" if MIPS_HUGE_TLB_SUPPORT && PAGE_SIZE_16KB
        range 11 64
        default "11"
        help
@@ -2353,9 +2353,8 @@ config SECCOMP
          If unsure, say Y. Only embedded should say N here.
 
 config MIPS_O32_FP64_SUPPORT
-       bool "Support for O32 binaries using 64-bit FP"
+       bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)"
        depends on 32BIT || MIPS32_O32
-       default y
        help
          When this is enabled, the kernel will support use of 64-bit floating
          point registers with binaries using the O32 ABI along with the
@@ -2367,7 +2366,14 @@ config MIPS_O32_FP64_SUPPORT
          of your kernel & potentially improve FP emulation performance by
          saying N here.
 
-         If unsure, say Y.
+         Although binutils currently supports use of this flag the details
+         concerning its effect upon the O32 ABI in userland are still being
+         worked on. In order to avoid userland becoming dependant upon current
+         behaviour before the details have been finalised, this option should
+         be considered experimental and only enabled by those working upon
+         said details.
+
+         If unsure, say N.
 
 config USE_OF
        bool
index 9edc35ff8cf1420e9576f195f92658e71517c073..acf9a2a37f5a055a0c794d7aa62a46e75527f6a4 100644 (file)
@@ -53,10 +53,8 @@ void __init prom_init(void)
        prom_init_cmdline();
 
        memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
+       if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
                memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
        add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
index 9969dbab19e36e3f2bd1210c93840bc85bfd7f16..25a59a23547e392b593a140d4f9bac3f2e882831 100644 (file)
@@ -52,10 +52,8 @@ void __init prom_init(void)
        prom_init_cmdline();
 
        memsize_str = prom_getenv("memsize");
-       if (!memsize_str)
+       if (!memsize_str || kstrtoul(memsize_str, 0, &memsize))
                memsize = 0x04000000;
-       else
-               strict_strtoul(memsize_str, 0, &memsize);
        add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
index 6d612e2b949b20f3875f7993b29de8e77435194c..cdd8246f92b33f8494712247a16348a8b41f27f1 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/errno.h>
 #include <linux/export.h>
 #include <linux/string.h>
 #include <bcm47xx_board.h>
index 6decb27cf48b4343e9358283775f82df82ed0aa5..2bed73a684aea021b4a296076880fed6a2ec489b 100644 (file)
@@ -196,7 +196,7 @@ int bcm47xx_nvram_gpio_pin(const char *name)
        char nvram_var[10];
        char buf[30];
 
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < 32; i++) {
                err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
                if (err <= 0)
                        continue;
index 25fbfae06c1f8585359c65d975bfc3240e00faa8..c2bb4f896ce788cbba4b6c48cd18ef875e5bdfd6 100644 (file)
@@ -975,10 +975,6 @@ static int octeon_irq_ciu_xlat(struct irq_domain *d,
        if (ciu > 1 || bit > 63)
                return -EINVAL;
 
-       /* These are the GPIO lines */
-       if (ciu == 0 && bit >= 16 && bit < 32)
-               return -EINVAL;
-
        *out_hwirq = (ciu << 6) | bit;
        *out_type = 0;
 
@@ -1007,6 +1003,10 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
        if (!octeon_irq_virq_in_range(virq))
                return -EINVAL;
 
+       /* Don't map irq if it is reserved for GPIO. */
+       if (line == 0 && bit >= 16 && bit <32)
+               return 0;
+
        if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
                return -EINVAL;
 
@@ -1525,10 +1525,6 @@ static int octeon_irq_ciu2_xlat(struct irq_domain *d,
        ciu = intspec[0];
        bit = intspec[1];
 
-       /* Line 7  are the GPIO lines */
-       if (ciu > 6 || bit > 63)
-               return -EINVAL;
-
        *out_hwirq = (ciu << 6) | bit;
        *out_type = 0;
 
@@ -1570,8 +1566,14 @@ static int octeon_irq_ciu2_map(struct irq_domain *d,
        if (!octeon_irq_virq_in_range(virq))
                return -EINVAL;
 
-       /* Line 7  are the GPIO lines */
-       if (line > 6 || octeon_irq_ciu_to_irq[line][bit] != 0)
+       /*
+        * Don't map irq if it is reserved for GPIO.
+        * (Line 7 are the GPIO lines.)
+        */
+       if (line == 7)
+               return 0;
+
+       if (line > 7 || octeon_irq_ciu_to_irq[line][bit] != 0)
                return -EINVAL;
 
        if (octeon_irq_ciu2_is_edge(line, bit))
index 3220c93ea981da828e94820bb6ec7c9a570db70f..4225e99bd7bfdbe75b0e47cd8b974c2dd92e1ddc 100644 (file)
@@ -9,6 +9,7 @@
 #define _ASM_ASMMACRO_H
 
 #include <asm/hazards.h>
+#include <asm/asm-offsets.h>
 
 #ifdef CONFIG_32BIT
 #include <asm/asmmacro-32.h>
        .endm
 
        .macro  local_irq_disable reg=t0
+#ifdef CONFIG_PREEMPT
+       lw      \reg, TI_PRE_COUNT($28)
+       addi    \reg, \reg, 1
+       sw      \reg, TI_PRE_COUNT($28)
+#endif
        mfc0    \reg, CP0_STATUS
        ori     \reg, \reg, 1
        xori    \reg, \reg, 1
        mtc0    \reg, CP0_STATUS
        irq_disable_hazard
+#ifdef CONFIG_PREEMPT
+       lw      \reg, TI_PRE_COUNT($28)
+       addi    \reg, \reg, -1
+       sw      \reg, TI_PRE_COUNT($28)
+#endif
        .endm
 #endif /* CONFIG_MIPS_MT_SMTC */
 
        .endm
 
        .macro  fpu_save_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        sll     \tmp, \status, 5
        bgez    \tmp, 10f
        fpu_save_16odd \thread
        .endm
 
        .macro  fpu_restore_double thread status tmp
-#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        sll     \tmp, \status, 5
        bgez    \tmp, 10f                               # 16 register mode?
 
index 6b9749540edffedf8903b0384cb8a505d1054edd..58e50cbdb1a6d577ef6ffbac115efcd593b6dedc 100644 (file)
@@ -57,7 +57,7 @@ static inline int __enable_fpu(enum fpu_mode mode)
                return 0;
 
        case FPU_64BIT:
-#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
+#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_64BIT))
                /* we only have a 32-bit FPU */
                return SIGFPE;
 #endif
index ce35c9af0c28b2dd8d179e1f5ad75d9fc610ba4c..992aaba603b5ca24da6242c5aebef4ea80aeb0e2 100644 (file)
@@ -22,12 +22,12 @@ extern void _mcount(void);
 #define safe_load(load, src, dst, error)               \
 do {                                                   \
        asm volatile (                                  \
-               "1: " load " %[" STR(dst) "], 0(%[" STR(src) "])\n"\
-               "   li %[" STR(error) "], 0\n"          \
+               "1: " load " %[tmp_dst], 0(%[tmp_src])\n"       \
+               "   li %[tmp_err], 0\n"                 \
                "2:\n"                                  \
                                                        \
                ".section .fixup, \"ax\"\n"             \
-               "3: li %[" STR(error) "], 1\n"          \
+               "3: li %[tmp_err], 1\n"                 \
                "   j 2b\n"                             \
                ".previous\n"                           \
                                                        \
@@ -35,8 +35,8 @@ do {                                                  \
                STR(PTR) "\t1b, 3b\n\t"                 \
                ".previous\n"                           \
                                                        \
-               : [dst] "=&r" (dst), [error] "=r" (error)\
-               : [src] "r" (src)                       \
+               : [tmp_dst] "=&r" (dst), [tmp_err] "=r" (error)\
+               : [tmp_src] "r" (src)                   \
                : "memory"                              \
        );                                              \
 } while (0)
@@ -44,12 +44,12 @@ do {                                                        \
 #define safe_store(store, src, dst, error)     \
 do {                                           \
        asm volatile (                          \
-               "1: " store " %[" STR(src) "], 0(%[" STR(dst) "])\n"\
-               "   li %[" STR(error) "], 0\n"  \
+               "1: " store " %[tmp_src], 0(%[tmp_dst])\n"\
+               "   li %[tmp_err], 0\n"         \
                "2:\n"                          \
                                                \
                ".section .fixup, \"ax\"\n"     \
-               "3: li %[" STR(error) "], 1\n"  \
+               "3: li %[tmp_err], 1\n"         \
                "   j 2b\n"                     \
                ".previous\n"                   \
                                                \
@@ -57,8 +57,8 @@ do {                                          \
                STR(PTR) "\t1b, 3b\n\t"         \
                ".previous\n"                   \
                                                \
-               : [error] "=r" (error)          \
-               : [dst] "r" (dst), [src] "r" (src)\
+               : [tmp_err] "=r" (error)        \
+               : [tmp_dst] "r" (dst), [tmp_src] "r" (src)\
                : "memory"                      \
        );                                      \
 } while (0)
index 33e8dbfc1b631626b3f52dd9c60d27957ae0f364..f35b131977e62a3ef0d81c47da6827f47d527b71 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef __ASM_MIPS_SYSCALL_H
 #define __ASM_MIPS_SYSCALL_H
 
+#include <linux/compiler.h>
 #include <linux/audit.h>
 #include <linux/elf-em.h>
 #include <linux/kernel.h>
@@ -39,14 +40,14 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
 
 #ifdef CONFIG_32BIT
        case 4: case 5: case 6: case 7:
-               return get_user(*arg, (int *)usp + 4 * n);
+               return get_user(*arg, (int *)usp + n);
 #endif
 
 #ifdef CONFIG_64BIT
        case 4: case 5: case 6: case 7:
 #ifdef CONFIG_MIPS32_O32
                if (test_thread_flag(TIF_32BIT_REGS))
-                       return get_user(*arg, (int *)usp + 4 * n);
+                       return get_user(*arg, (int *)usp + n);
                else
 #endif
                        *arg = regs->regs[4 + n];
@@ -57,6 +58,8 @@ static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
        default:
                BUG();
        }
+
+       unreachable();
 }
 
 static inline long syscall_get_return_value(struct task_struct *task,
@@ -83,11 +86,10 @@ static inline void syscall_get_arguments(struct task_struct *task,
                                         unsigned int i, unsigned int n,
                                         unsigned long *args)
 {
-       unsigned long arg;
        int ret;
 
        while (n--)
-               ret |= mips_get_syscall_arg(&arg, task, regs, i++);
+               ret |= mips_get_syscall_arg(args++, task, regs, i++);
 
        /*
         * No way to communicate an error because this is a void function.
index b39ba25b41ccd2db0ae723ba01c4fab3a82621a6..f25181b19941db0544dc8e98187827343df99238 100644 (file)
@@ -163,8 +163,8 @@ enum cop1_sdw_func {
  */
 enum cop1x_func {
        lwxc1_op     =  0x00, ldxc1_op     =  0x01,
-       pfetch_op    =  0x07, swxc1_op     =  0x08,
-       sdxc1_op     =  0x09, madd_s_op    =  0x20,
+       swxc1_op     =  0x08, sdxc1_op     =  0x09,
+       pfetch_op    =  0x0f, madd_s_op    =  0x20,
        madd_d_op    =  0x21, madd_e_op    =  0x22,
        msub_s_op    =  0x28, msub_d_op    =  0x29,
        msub_e_op    =  0x2a, nmadd_s_op   =  0x30,
index 185ba258361b979ee9531bd18d38b0242e1de979..374ed74cd516d91e27638ce12e4c3c731a191ef4 100644 (file)
@@ -111,11 +111,10 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
        safe_store_code(new_code1, ip, faulted);
        if (unlikely(faulted))
                return -EFAULT;
-       ip += 4;
-       safe_store_code(new_code2, ip, faulted);
+       safe_store_code(new_code2, ip + 4, faulted);
        if (unlikely(faulted))
                return -EFAULT;
-       flush_icache_range(ip, ip + 8); /* original ip + 12 */
+       flush_icache_range(ip, ip + 8);
        return 0;
 }
 #endif
index 253b2fb520267fb3536584df6d395a6b860392f1..73b0ddf910d41b08dd1bacd97f862e97f94f4c95 100644 (file)
@@ -35,9 +35,9 @@
 LEAF(_save_fp_context)
        cfc1    t1, fcr31
 
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        .set    push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
        .set    mips64r2
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5
@@ -146,11 +146,11 @@ LEAF(_save_fp_context32)
  *  - cp1 status/control register
  */
 LEAF(_restore_fp_context)
-       EX      lw t0, SC_FPC_CSR(a0)
+       EX      lw t1, SC_FPC_CSR(a0)
 
-#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        .set    push
-#ifdef CONFIG_MIPS32_R2
+#ifdef CONFIG_CPU_MIPS32_R2
        .set    mips64r2
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5
@@ -191,7 +191,7 @@ LEAF(_restore_fp_context)
        EX      ldc1 $f26, SC_FPREGS+208(a0)
        EX      ldc1 $f28, SC_FPREGS+224(a0)
        EX      ldc1 $f30, SC_FPREGS+240(a0)
-       ctc1    t0, fcr31
+       ctc1    t1, fcr31
        jr      ra
         li     v0, 0                                   # success
        END(_restore_fp_context)
@@ -199,7 +199,7 @@ LEAF(_restore_fp_context)
 #ifdef CONFIG_MIPS32_COMPAT
 LEAF(_restore_fp_context32)
        /* Restore an o32 sigcontext.  */
-       EX      lw t0, SC32_FPC_CSR(a0)
+       EX      lw t1, SC32_FPC_CSR(a0)
 
        mfc0    t0, CP0_STATUS
        sll     t0, t0, 5
@@ -239,7 +239,7 @@ LEAF(_restore_fp_context32)
        EX      ldc1 $f26, SC32_FPREGS+208(a0)
        EX      ldc1 $f28, SC32_FPREGS+224(a0)
        EX      ldc1 $f30, SC32_FPREGS+240(a0)
-       ctc1    t0, fcr31
+       ctc1    t1, fcr31
        jr      ra
         li     v0, 0                                   # success
        END(_restore_fp_context32)
index 56dc6963515314962ad22ee0a5676edf87937122..758fb3cd2326c34dd119d86d1c3ee5c5d148ee29 100644 (file)
@@ -112,5 +112,8 @@ void __exit rtlx_module_exit(void)
 
        for (i = 0; i < RTLX_CHANNELS; i++)
                device_destroy(mt_class, MKDEV(major, i));
+
        unregister_chrdev(major, RTLX_MODULE_NAME);
+
+       aprp_hook = NULL;
 }
index 91d61ba422b4677fdc956b0a5707ddb58740212a..9c1aca00fd5442e8b44a259ad99e2c328718b600 100644 (file)
@@ -144,5 +144,8 @@ void __exit rtlx_module_exit(void)
 
        for (i = 0; i < RTLX_CHANNELS; i++)
                device_destroy(mt_class, MKDEV(major, i));
+
        unregister_chrdev(major, RTLX_MODULE_NAME);
+
+       aprp_hook = NULL;
 }
index 506925b2c3f366a12aecfb8ecc3cf6d69274654d..0b4e2e38294bf174132fcb4036cc958a370cfbec 100644 (file)
@@ -1538,10 +1538,10 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                break;
        }
 
-       case 0x7:               /* 7 */
-               if (MIPSInst_FUNC(ir) != pfetch_op) {
+       case 0x3:
+               if (MIPSInst_FUNC(ir) != pfetch_op)
                        return SIGILL;
-               }
+
                /* ignore prefx operation */
                break;
 
index 592ac0427426acd4b83d1272f4e8c43c7716bca1..84ac523b0ce08675ecd102a2beeda2b66ce92f11 100644 (file)
@@ -72,7 +72,7 @@ int amon_cpu_start(int cpu,
        return 0;
 }
 
-#ifdef CONFIG_MIPS_VPE_LOADER
+#ifdef CONFIG_MIPS_VPE_LOADER_CMP
 int vpe_run(struct vpe *v)
 {
        struct vpe_notifications *n;
index ca3e3a46a42f90dedc359c1729d7b3c55365fc92..2242181a62841e2c86cd87ab3859bee35ca91099 100644 (file)
@@ -119,7 +119,7 @@ static void malta_hw0_irqdispatch(void)
 
        do_IRQ(MALTA_INT_BASE + irq);
 
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_MT
        if (aprp_hook)
                aprp_hook();
 #endif
@@ -310,7 +310,7 @@ static void ipi_call_dispatch(void)
 
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 {
-#ifdef MIPS_VPE_APSP_API
+#ifdef CONFIG_MIPS_VPE_APSP_API_CMP
        if (aprp_hook)
                aprp_hook();
 #endif
index d37be36dc659b4df1f3b22787f84c6908bc5eb45..2b91b0e6156670a723c4cd46749065a0f798d347 100644 (file)
@@ -150,6 +150,7 @@ msi_irq_allocated:
                msg.address_lo =
                        ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff;
                msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32;
+               break;
        case OCTEON_DMA_BAR_TYPE_BIG:
                /* When using big bar, Bar 0 is based at 0 */
                msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff;
index 637fe031aa8476d743a8141ca9b549019985a0c6..60d5d174dfe413e14cb5117a04536ce7948d937d 100644 (file)
@@ -32,17 +32,6 @@ void copy_page_asm(void *to, void *from);
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
                        struct page *pg);
 
-/* #define CONFIG_PARISC_TMPALIAS */
-
-#ifdef CONFIG_PARISC_TMPALIAS
-void clear_user_highpage(struct page *page, unsigned long vaddr);
-#define clear_user_highpage clear_user_highpage
-struct vm_area_struct;
-void copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr, struct vm_area_struct *vma);
-#define __HAVE_ARCH_COPY_USER_HIGHPAGE
-#endif
-
 /*
  * These are used to make use of C type-checking..
  */
index 3516e0b27044d5e5cf987cf53acf735059a5b016..64f2992e439fcd81811e7a44d322bdc5aafd9ff1 100644 (file)
@@ -191,8 +191,4 @@ static __inline__ int arch_write_can_lock(arch_rwlock_t *rw)
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
 
-#define arch_spin_relax(lock)  cpu_relax()
-#define arch_read_relax(lock)  cpu_relax()
-#define arch_write_relax(lock) cpu_relax()
-
 #endif /* __ASM_SPINLOCK_H */
index 42706794a36f34d12fa598df238ade3db602e9c6..265ae5190b0a70e4dc2539d9a661e1e3d2deda05 100644 (file)
 #define __NR_finit_module      (__NR_Linux + 333)
 #define __NR_sched_setattr     (__NR_Linux + 334)
 #define __NR_sched_getattr     (__NR_Linux + 335)
+#define __NR_utimes            (__NR_Linux + 336)
 
-#define __NR_Linux_syscalls    (__NR_sched_getattr + 1)
+#define __NR_Linux_syscalls    (__NR_utimes + 1)
 
 
 #define __IGNORE_select                /* newselect */
 #define __IGNORE_fadvise64     /* fadvise64_64 */
-#define __IGNORE_utimes                /* utime */
 
 
 #define HPUX_GATEWAY_ADDR       0xC0000004
index ac87a40502e6f6a0e11d21eaf6789259859ad092..a6ffc775a9f8105381b3da46214290a421a79c6c 100644 (file)
@@ -581,67 +581,3 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
                __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
        }
 }
-
-#ifdef CONFIG_PARISC_TMPALIAS
-
-void clear_user_highpage(struct page *page, unsigned long vaddr)
-{
-       void *vto;
-       unsigned long flags;
-
-       /* Clear using TMPALIAS region.  The page doesn't need to
-          be flushed but the kernel mapping needs to be purged.  */
-
-       vto = kmap_atomic(page);
-
-       /* The PA-RISC 2.0 Architecture book states on page F-6:
-          "Before a write-capable translation is enabled, *all*
-          non-equivalently-aliased translations must be removed
-          from the page table and purged from the TLB.  (Note
-          that the caches are not required to be flushed at this
-          time.)  Before any non-equivalent aliased translation
-          is re-enabled, the virtual address range for the writeable
-          page (the entire page) must be flushed from the cache,
-          and the write-capable translation removed from the page
-          table and purged from the TLB."  */
-
-       purge_kernel_dcache_page_asm((unsigned long)vto);
-       purge_tlb_start(flags);
-       pdtlb_kernel(vto);
-       purge_tlb_end(flags);
-       preempt_disable();
-       clear_user_page_asm(vto, vaddr);
-       preempt_enable();
-
-       pagefault_enable();             /* kunmap_atomic(addr, KM_USER0); */
-}
-
-void copy_user_highpage(struct page *to, struct page *from,
-       unsigned long vaddr, struct vm_area_struct *vma)
-{
-       void *vfrom, *vto;
-       unsigned long flags;
-
-       /* Copy using TMPALIAS region.  This has the advantage
-          that the `from' page doesn't need to be flushed.  However,
-          the `to' page must be flushed in copy_user_page_asm since
-          it can be used to bring in executable code.  */
-
-       vfrom = kmap_atomic(from);
-       vto = kmap_atomic(to);
-
-       purge_kernel_dcache_page_asm((unsigned long)vto);
-       purge_tlb_start(flags);
-       pdtlb_kernel(vto);
-       pdtlb_kernel(vfrom);
-       purge_tlb_end(flags);
-       preempt_disable();
-       copy_user_page_asm(vto, vfrom, vaddr);
-       flush_dcache_page_asm(__pa(vto), vaddr);
-       preempt_enable();
-
-       pagefault_enable();             /* kunmap_atomic(addr, KM_USER1); */
-       pagefault_enable();             /* kunmap_atomic(addr, KM_USER0); */
-}
-
-#endif /* CONFIG_PARISC_TMPALIAS */
index 8fa3fbb3e4d3806f15ab0d98543a35d8b18155ce..80e5dd248934e26ca94916c1e1f7c2cd6cffbefd 100644 (file)
        ENTRY_SAME(finit_module)
        ENTRY_SAME(sched_setattr)
        ENTRY_SAME(sched_getattr)       /* 335 */
+       ENTRY_COMP(utimes)
 
        /* Nothing yet */
 
index 84fdf6857c31d1ccf878911b416f32e104eba8fb..a613d2c82fd9e7cbb024a28f493c0be54748d7e0 100644 (file)
@@ -200,10 +200,11 @@ static inline void __user *arch_compat_alloc_user_space(long len)
 
        /*
         * We can't access below the stack pointer in the 32bit ABI and
-        * can access 288 bytes in the 64bit ABI
+        * can access 288 bytes in the 64bit big-endian ABI,
+        * or 512 bytes with the new ELFv2 little-endian ABI.
         */
        if (!is_32bit_task())
-               usp -= 288;
+               usp -= USER_REDZONE_SIZE;
 
        return (void __user *) (usp - len);
 }
index e27e9ad6818ea815164734711e1eb048e52ab5a2..150866b2a3fe07337f38905511a73cd726e07689 100644 (file)
@@ -134,6 +134,7 @@ static inline int dma_supported(struct device *dev, u64 mask)
 }
 
 extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern int __dma_set_mask(struct device *dev, u64 dma_mask);
 
 #define dma_alloc_coherent(d,s,h,f)    dma_alloc_attrs(d,s,h,f,NULL)
 
index 9e39ceb1d19fd706014794a6918f671ef12a5a58..d4dd41fb951b343918dda3db91399702d0e86423 100644 (file)
@@ -172,10 +172,20 @@ struct eeh_ops {
 };
 
 extern struct eeh_ops *eeh_ops;
-extern int eeh_subsystem_enabled;
+extern bool eeh_subsystem_enabled;
 extern raw_spinlock_t confirm_error_lock;
 extern int eeh_probe_mode;
 
+static inline bool eeh_enabled(void)
+{
+       return eeh_subsystem_enabled;
+}
+
+static inline void eeh_set_enable(bool mode)
+{
+       eeh_subsystem_enabled = mode;
+}
+
 #define EEH_PROBE_MODE_DEV     (1<<0)  /* From PCI device      */
 #define EEH_PROBE_MODE_DEVTREE (1<<1)  /* From device tree     */
 
@@ -246,7 +256,7 @@ void eeh_remove_device(struct pci_dev *);
  * If this macro yields TRUE, the caller relays to eeh_check_failure()
  * which does further tests out of line.
  */
-#define EEH_POSSIBLE_ERROR(val, type)  ((val) == (type)~0 && eeh_subsystem_enabled)
+#define EEH_POSSIBLE_ERROR(val, type)  ((val) == (type)~0 && eeh_enabled())
 
 /*
  * Reads from a device which has been isolated by EEH will return
@@ -257,6 +267,13 @@ void eeh_remove_device(struct pci_dev *);
 
 #else /* !CONFIG_EEH */
 
+static inline bool eeh_enabled(void)
+{
+        return false;
+}
+
+static inline void eeh_set_enable(bool mode) { }
+
 static inline int eeh_init(void)
 {
        return 0;
index d750336b171db4cf2c75f7e1fb95cbf6bcba8d74..623f2971ce0ed8d4d947642c862d4dce7640d28d 100644 (file)
@@ -127,7 +127,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
                                            unsigned long addr, pte_t *ptep)
 {
 #ifdef CONFIG_PPC64
-       return __pte(pte_update(mm, addr, ptep, ~0UL, 1));
+       return __pte(pte_update(mm, addr, ptep, ~0UL, 0, 1));
 #else
        return __pte(pte_update(ptep, ~0UL, 0));
 #endif
index f7a8036579b5a43d19ea0730b7e541b61272ab13..42632c7a2a4e77e86fa0768646f30b7508365fd9 100644 (file)
@@ -77,6 +77,7 @@ struct iommu_table {
 #ifdef CONFIG_IOMMU_API
        struct iommu_group *it_group;
 #endif
+       void (*set_bypass)(struct iommu_table *tbl, bool enable);
 };
 
 /* Pure 2^n version of get_order */
index 40157e2ca6914467cddae0225070d8582ad0861c..ed82142a325111ca18ecbc5ad05ec5760cb03a87 100644 (file)
@@ -816,8 +816,8 @@ int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
 int64_t opal_pci_poll(uint64_t phb_id);
 int64_t opal_return_cpu(void);
 
-int64_t opal_xscom_read(uint32_t gcid, uint32_t pcb_addr, __be64 *val);
-int64_t opal_xscom_write(uint32_t gcid, uint32_t pcb_addr, uint64_t val);
+int64_t opal_xscom_read(uint32_t gcid, uint64_t pcb_addr, __be64 *val);
+int64_t opal_xscom_write(uint32_t gcid, uint64_t pcb_addr, uint64_t val);
 
 int64_t opal_lpc_write(uint32_t chip_id, enum OpalLPCAddressType addr_type,
                       uint32_t addr, uint32_t data, uint32_t sz);
index bc141c950b1e6c8128769b786df189eb275f583f..eb9261024f5192386dec97bff1ee10e62da4b7c3 100644 (file)
@@ -195,6 +195,7 @@ extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
 static inline unsigned long pte_update(struct mm_struct *mm,
                                       unsigned long addr,
                                       pte_t *ptep, unsigned long clr,
+                                      unsigned long set,
                                       int huge)
 {
 #ifdef PTE_ATOMIC_UPDATES
@@ -205,14 +206,15 @@ static inline unsigned long pte_update(struct mm_struct *mm,
        andi.   %1,%0,%6\n\
        bne-    1b \n\
        andc    %1,%0,%4 \n\
+       or      %1,%1,%7\n\
        stdcx.  %1,0,%3 \n\
        bne-    1b"
        : "=&r" (old), "=&r" (tmp), "=m" (*ptep)
-       : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
+       : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY), "r" (set)
        : "cc" );
 #else
        unsigned long old = pte_val(*ptep);
-       *ptep = __pte(old & ~clr);
+       *ptep = __pte((old & ~clr) | set);
 #endif
        /* huge pages use the old page table lock */
        if (!huge)
@@ -231,9 +233,9 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
 {
        unsigned long old;
 
-               if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+       if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
                return 0;
-       old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
+       old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0, 0);
        return (old & _PAGE_ACCESSED) != 0;
 }
 #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
@@ -252,7 +254,7 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
        if ((pte_val(*ptep) & _PAGE_RW) == 0)
                return;
 
-       pte_update(mm, addr, ptep, _PAGE_RW, 0);
+       pte_update(mm, addr, ptep, _PAGE_RW, 0, 0);
 }
 
 static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
@@ -261,7 +263,7 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
        if ((pte_val(*ptep) & _PAGE_RW) == 0)
                return;
 
-       pte_update(mm, addr, ptep, _PAGE_RW, 1);
+       pte_update(mm, addr, ptep, _PAGE_RW, 0, 1);
 }
 
 /*
@@ -284,14 +286,14 @@ static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
 static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
                                       unsigned long addr, pte_t *ptep)
 {
-       unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
+       unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0, 0);
        return __pte(old);
 }
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
                             pte_t * ptep)
 {
-       pte_update(mm, addr, ptep, ~0UL, 0);
+       pte_update(mm, addr, ptep, ~0UL, 0, 0);
 }
 
 
@@ -506,7 +508,9 @@ extern int pmdp_set_access_flags(struct vm_area_struct *vma,
 
 extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
                                         unsigned long addr,
-                                        pmd_t *pmdp, unsigned long clr);
+                                        pmd_t *pmdp,
+                                        unsigned long clr,
+                                        unsigned long set);
 
 static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
                                              unsigned long addr, pmd_t *pmdp)
@@ -515,7 +519,7 @@ static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
 
        if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
                return 0;
-       old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED);
+       old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED, 0);
        return ((old & _PAGE_ACCESSED) != 0);
 }
 
@@ -542,7 +546,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
        if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
                return;
 
-       pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW);
+       pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW, 0);
 }
 
 #define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
index f83b6f3e1b39b68c5b25f8df6a107f59bf20ae1b..3ebb188c3ff51a5ec0d55c31ce26601354a1bef7 100644 (file)
@@ -75,12 +75,34 @@ static inline pte_t pte_mknuma(pte_t pte)
        return pte;
 }
 
+#define ptep_set_numa ptep_set_numa
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+                                pte_t *ptep)
+{
+       if ((pte_val(*ptep) & _PAGE_PRESENT) == 0)
+               VM_BUG_ON(1);
+
+       pte_update(mm, addr, ptep, _PAGE_PRESENT, _PAGE_NUMA, 0);
+       return;
+}
+
 #define pmd_numa pmd_numa
 static inline int pmd_numa(pmd_t pmd)
 {
        return pte_numa(pmd_pte(pmd));
 }
 
+#define pmdp_set_numa pmdp_set_numa
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+                                pmd_t *pmdp)
+{
+       if ((pmd_val(*pmdp) & _PAGE_PRESENT) == 0)
+               VM_BUG_ON(1);
+
+       pmd_hugepage_update(mm, addr, pmdp, _PAGE_PRESENT, _PAGE_NUMA);
+       return;
+}
+
 #define pmd_mknonnuma pmd_mknonnuma
 static inline pmd_t pmd_mknonnuma(pmd_t pmd)
 {
index becc08e6a65c585e0b6bc995f7699d74e2c36338..279b80f3bb293d0bceceecb9eb38ff344e26b8fb 100644 (file)
 
 #ifdef __powerpc64__
 
+/*
+ * Size of redzone that userspace is allowed to use below the stack
+ * pointer.  This is 288 in the 64-bit big-endian ELF ABI, and 512 in
+ * the new ELFv2 little-endian ABI, so we allow the larger amount.
+ *
+ * For kernel code we allow a 288-byte redzone, in order to conserve
+ * kernel stack space; gcc currently only uses 288 bytes, and will
+ * hopefully allow explicit control of the redzone size in future.
+ */
+#define USER_REDZONE_SIZE      512
+#define KERNEL_REDZONE_SIZE    288
+
 #define STACK_FRAME_OVERHEAD   112     /* size of minimum stack frame */
 #define STACK_FRAME_LR_SAVE    2       /* Location of LR in stack frame */
 #define STACK_FRAME_REGS_MARKER        ASM_CONST(0x7265677368657265)
 #define STACK_INT_FRAME_SIZE   (sizeof(struct pt_regs) + \
-                                       STACK_FRAME_OVERHEAD + 288)
+                                STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
 #define STACK_FRAME_MARKER     12
 
 /* Size of dummy stack frame allocated when calling signal handler. */
@@ -41,6 +53,8 @@
 
 #else /* __powerpc64__ */
 
+#define USER_REDZONE_SIZE      0
+#define KERNEL_REDZONE_SIZE    0
 #define STACK_FRAME_OVERHEAD   16      /* size of minimum stack frame */
 #define STACK_FRAME_LR_SAVE    1       /* Location of LR in stack frame */
 #define STACK_FRAME_REGS_MARKER        ASM_CONST(0x72656773)
index 4ee06fe15de41d11e77f7c7c44d2daaea8d10ed2..d0e784e0ff484f0053f807e081a4c89fec13dee6 100644 (file)
@@ -8,6 +8,7 @@
 
 #ifdef __powerpc64__
 
+extern char __start_interrupts[];
 extern char __end_interrupts[];
 
 extern char __prom_init_toc_start[];
@@ -21,6 +22,17 @@ static inline int in_kernel_text(unsigned long addr)
        return 0;
 }
 
+static inline int overlaps_interrupt_vector_text(unsigned long start,
+                                                       unsigned long end)
+{
+       unsigned long real_start, real_end;
+       real_start = __start_interrupts - _stext;
+       real_end = __end_interrupts - _stext;
+
+       return start < (unsigned long)__va(real_end) &&
+               (unsigned long)__va(real_start) < end;
+}
+
 static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
 {
        return start < (unsigned long)__init_end &&
index 0d9cecddf8a4f5ae133415f5e0bd49d780318e01..c53f5f6d1761f711b280c9e29509da15e6f1f4b8 100644 (file)
@@ -4,11 +4,11 @@
 #ifdef __KERNEL__
 
 /* Default link addresses for the vDSOs */
-#define VDSO32_LBASE   0x100000
-#define VDSO64_LBASE   0x100000
+#define VDSO32_LBASE   0x0
+#define VDSO64_LBASE   0x0
 
 /* Default map addresses for 32bit vDSO */
-#define VDSO32_MBASE   VDSO32_LBASE
+#define VDSO32_MBASE   0x100000
 
 #define VDSO_VERSION_STRING    LINUX_2.6.15
 
index 11c1d069d920a1fc97ec601ab0542c41708d7cc1..7a13f378ca2c7b1c715b9719e01329f99bf2ef2e 100644 (file)
@@ -98,17 +98,19 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
                        size_t csize, unsigned long offset, int userbuf)
 {
        void  *vaddr;
+       phys_addr_t paddr;
 
        if (!csize)
                return 0;
 
        csize = min_t(size_t, csize, PAGE_SIZE);
+       paddr = pfn << PAGE_SHIFT;
 
-       if ((min_low_pfn < pfn) && (pfn < max_pfn)) {
-               vaddr = __va(pfn << PAGE_SHIFT);
+       if (memblock_is_region_memory(paddr, csize)) {
+               vaddr = __va(paddr);
                csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
        } else {
-               vaddr = __ioremap(pfn << PAGE_SHIFT, PAGE_SIZE, 0);
+               vaddr = __ioremap(paddr, PAGE_SIZE, 0);
                csize = copy_oldmem_vaddr(vaddr, buf, csize, offset, userbuf);
                iounmap(vaddr);
        }
index 8032b97ccdcb6668f01dc9c2026c0080f0a14449..ee78f6e49d64bddc78d58382b73008841896b38a 100644 (file)
@@ -191,12 +191,10 @@ EXPORT_SYMBOL(dma_direct_ops);
 
 #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
 
-int dma_set_mask(struct device *dev, u64 dma_mask)
+int __dma_set_mask(struct device *dev, u64 dma_mask)
 {
        struct dma_map_ops *dma_ops = get_dma_ops(dev);
 
-       if (ppc_md.dma_set_mask)
-               return ppc_md.dma_set_mask(dev, dma_mask);
        if ((dma_ops != NULL) && (dma_ops->set_dma_mask != NULL))
                return dma_ops->set_dma_mask(dev, dma_mask);
        if (!dev->dma_mask || !dma_supported(dev, dma_mask))
@@ -204,6 +202,12 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
        *dev->dma_mask = dma_mask;
        return 0;
 }
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       if (ppc_md.dma_set_mask)
+               return ppc_md.dma_set_mask(dev, dma_mask);
+       return __dma_set_mask(dev, dma_mask);
+}
 EXPORT_SYMBOL(dma_set_mask);
 
 u64 dma_get_required_mask(struct device *dev)
index 148db72a8c4371e69f79009683eb8b3baf12c3d6..e7b76a6bf15083704136459dc1dc69f2c6c9183e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/rbtree.h>
+#include <linux/reboot.h>
 #include <linux/seq_file.h>
 #include <linux/spinlock.h>
 #include <linux/export.h>
@@ -89,7 +90,7 @@
 /* Platform dependent EEH operations */
 struct eeh_ops *eeh_ops = NULL;
 
-int eeh_subsystem_enabled;
+bool eeh_subsystem_enabled = false;
 EXPORT_SYMBOL(eeh_subsystem_enabled);
 
 /*
@@ -364,7 +365,7 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
 
        eeh_stats.total_mmio_ffs++;
 
-       if (!eeh_subsystem_enabled)
+       if (!eeh_enabled())
                return 0;
 
        if (!edev) {
@@ -747,6 +748,17 @@ int __exit eeh_ops_unregister(const char *name)
        return -EEXIST;
 }
 
+static int eeh_reboot_notifier(struct notifier_block *nb,
+                              unsigned long action, void *unused)
+{
+       eeh_set_enable(false);
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block eeh_reboot_nb = {
+       .notifier_call = eeh_reboot_notifier,
+};
+
 /**
  * eeh_init - EEH initialization
  *
@@ -778,6 +790,14 @@ int eeh_init(void)
        if (machine_is(powernv) && cnt++ <= 0)
                return ret;
 
+       /* Register reboot notifier */
+       ret = register_reboot_notifier(&eeh_reboot_nb);
+       if (ret) {
+               pr_warn("%s: Failed to register notifier (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
        /* call platform initialization function */
        if (!eeh_ops) {
                pr_warning("%s: Platform EEH operation not found\n",
@@ -822,7 +842,7 @@ int eeh_init(void)
                        return ret;
        }
 
-       if (eeh_subsystem_enabled)
+       if (eeh_enabled())
                pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
        else
                pr_warning("EEH: No capable adapters found\n");
@@ -897,7 +917,7 @@ void eeh_add_device_late(struct pci_dev *dev)
        struct device_node *dn;
        struct eeh_dev *edev;
 
-       if (!dev || !eeh_subsystem_enabled)
+       if (!dev || !eeh_enabled())
                return;
 
        pr_debug("EEH: Adding device %s\n", pci_name(dev));
@@ -1005,7 +1025,7 @@ void eeh_remove_device(struct pci_dev *dev)
 {
        struct eeh_dev *edev;
 
-       if (!dev || !eeh_subsystem_enabled)
+       if (!dev || !eeh_enabled())
                return;
        edev = pci_dev_to_eeh_dev(dev);
 
@@ -1045,7 +1065,7 @@ void eeh_remove_device(struct pci_dev *dev)
 
 static int proc_eeh_show(struct seq_file *m, void *v)
 {
-       if (0 == eeh_subsystem_enabled) {
+       if (!eeh_enabled()) {
                seq_printf(m, "EEH Subsystem is globally disabled\n");
                seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs);
        } else {
index 7bb30dca4e192f55ca689319eefdc2a50646ff3a..fdc679d309ec4c030d6f407d35675fb1b2527473 100644 (file)
@@ -362,9 +362,13 @@ static void *eeh_rmv_device(void *data, void *userdata)
         */
        if (!dev || (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE))
                return NULL;
+
        driver = eeh_pcid_get(dev);
-       if (driver && driver->err_handler)
-               return NULL;
+       if (driver) {
+               eeh_pcid_put(dev);
+               if (driver->err_handler)
+                       return NULL;
+       }
 
        /* Remove it from PCI subsystem */
        pr_debug("EEH: Removing %s without EEH sensitive driver\n",
index 9b27b293a9226903c81529a4f01aee64a7f07d23..b0ded97ee4e11148cd436809aaab2c36c106893a 100644 (file)
@@ -74,6 +74,7 @@ ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new)
  */
 static int test_24bit_addr(unsigned long ip, unsigned long addr)
 {
+       addr = ppc_function_entry((void *)addr);
 
        /* use the create_branch to verify that this offset can be branched */
        return create_branch((unsigned int *)ip, addr, 0);
index d773dd440a45a32560fed0176120709ff5ea860d..88e3ec6e1d965a38ade11ecff745e8c029e84ced 100644 (file)
@@ -1088,6 +1088,14 @@ int iommu_take_ownership(struct iommu_table *tbl)
        memset(tbl->it_map, 0xff, sz);
        iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size);
 
+       /*
+        * Disable iommu bypass, otherwise the user can DMA to all of
+        * our physical memory via the bypass window instead of just
+        * the pages that has been explicitly mapped into the iommu
+        */
+       if (tbl->set_bypass)
+               tbl->set_bypass(tbl, false);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_take_ownership);
@@ -1102,6 +1110,10 @@ void iommu_release_ownership(struct iommu_table *tbl)
        /* Restore bit#0 set by iommu_init_table() */
        if (tbl->it_offset == 0)
                set_bit(0, tbl->it_map);
+
+       /* The kernel owns the device now, we can restore the iommu bypass */
+       if (tbl->set_bypass)
+               tbl->set_bypass(tbl, true);
 }
 EXPORT_SYMBOL_GPL(iommu_release_ownership);
 
index 9729b23bfb0a2deebf0e5157accb2d68541b6bf0..1d0848bba049bf2c97bd09d9d86864857af128a7 100644 (file)
@@ -559,8 +559,13 @@ void exc_lvl_ctx_init(void)
 #ifdef CONFIG_PPC64
                cpu_nr = i;
 #else
+#ifdef CONFIG_SMP
                cpu_nr = get_hard_smp_processor_id(i);
+#else
+               cpu_nr = 0;
 #endif
+#endif
+
                memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE);
                tp = critirq_ctx[cpu_nr];
                tp->cpu = cpu_nr;
index 75d4f7340da893bc2825f97dda750409d8963323..015ae55c18686ffb794938531aa52692e0843b0e 100644 (file)
@@ -196,7 +196,9 @@ int overlaps_crashkernel(unsigned long start, unsigned long size)
 
 /* Values we need to export to the second kernel via the device tree. */
 static phys_addr_t kernel_end;
+static phys_addr_t crashk_base;
 static phys_addr_t crashk_size;
+static unsigned long long mem_limit;
 
 static struct property kernel_end_prop = {
        .name = "linux,kernel-end",
@@ -207,7 +209,7 @@ static struct property kernel_end_prop = {
 static struct property crashk_base_prop = {
        .name = "linux,crashkernel-base",
        .length = sizeof(phys_addr_t),
-       .value = &crashk_res.start,
+       .value = &crashk_base
 };
 
 static struct property crashk_size_prop = {
@@ -219,9 +221,11 @@ static struct property crashk_size_prop = {
 static struct property memory_limit_prop = {
        .name = "linux,memory-limit",
        .length = sizeof(unsigned long long),
-       .value = &memory_limit,
+       .value = &mem_limit,
 };
 
+#define cpu_to_be_ulong        __PASTE(cpu_to_be, BITS_PER_LONG)
+
 static void __init export_crashk_values(struct device_node *node)
 {
        struct property *prop;
@@ -237,8 +241,9 @@ static void __init export_crashk_values(struct device_node *node)
                of_remove_property(node, prop);
 
        if (crashk_res.start != 0) {
+               crashk_base = cpu_to_be_ulong(crashk_res.start),
                of_add_property(node, &crashk_base_prop);
-               crashk_size = resource_size(&crashk_res);
+               crashk_size = cpu_to_be_ulong(resource_size(&crashk_res));
                of_add_property(node, &crashk_size_prop);
        }
 
@@ -246,6 +251,7 @@ static void __init export_crashk_values(struct device_node *node)
         * memory_limit is required by the kexec-tools to limit the
         * crash regions to the actual memory used.
         */
+       mem_limit = cpu_to_be_ulong(memory_limit);
        of_update_property(node, &memory_limit_prop);
 }
 
@@ -264,7 +270,7 @@ static int __init kexec_setup(void)
                of_remove_property(node, prop);
 
        /* information needed by userspace when using default_machine_kexec */
-       kernel_end = __pa(_end);
+       kernel_end = cpu_to_be_ulong(__pa(_end));
        of_add_property(node, &kernel_end_prop);
 
        export_crashk_values(node);
index be4e6d648f6093d4efe7fe84155ebe9653a3baea..59d229a2a3e08dfcd1f18ca94e56cd00e787c987 100644 (file)
@@ -369,6 +369,7 @@ void default_machine_kexec(struct kimage *image)
 
 /* Values we need to export to the second kernel via the device tree. */
 static unsigned long htab_base;
+static unsigned long htab_size;
 
 static struct property htab_base_prop = {
        .name = "linux,htab-base",
@@ -379,7 +380,7 @@ static struct property htab_base_prop = {
 static struct property htab_size_prop = {
        .name = "linux,htab-size",
        .length = sizeof(unsigned long),
-       .value = &htab_size_bytes,
+       .value = &htab_size,
 };
 
 static int __init export_htab_values(void)
@@ -403,8 +404,9 @@ static int __init export_htab_values(void)
        if (prop)
                of_remove_property(node, prop);
 
-       htab_base = __pa(htab_address);
+       htab_base = cpu_to_be64(__pa(htab_address));
        of_add_property(node, &htab_base_prop);
+       htab_size = cpu_to_be64(htab_size_bytes);
        of_add_property(node, &htab_size_prop);
 
        of_node_put(node);
index 879f09620f8341e27dbfd1ed6be47fe242eab812..7c6bb4b17b4960d111f29bc7f37632f9026d944c 100644 (file)
@@ -57,11 +57,14 @@ _GLOBAL(call_do_softirq)
        mtlr    r0
        blr
 
+/*
+ * void call_do_irq(struct pt_regs *regs, struct thread_info *irqtp);
+ */
 _GLOBAL(call_do_irq)
        mflr    r0
        stw     r0,4(r1)
        lwz     r10,THREAD+KSP_LIMIT(r2)
-       addi    r11,r3,THREAD_INFO_GAP
+       addi    r11,r4,THREAD_INFO_GAP
        stwu    r1,THREAD_SIZE-STACK_FRAME_OVERHEAD(r4)
        mr      r1,r4
        stw     r10,8(r1)
index 8d4c247f17389f283d02bc48dba044ff077e3ffe..af064d28b36524c5ce9c8fc982a58eec65ebbfc7 100644 (file)
@@ -1048,6 +1048,15 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
        flush_altivec_to_thread(src);
        flush_vsx_to_thread(src);
        flush_spe_to_thread(src);
+       /*
+        * Flush TM state out so we can copy it.  __switch_to_tm() does this
+        * flush but it removes the checkpointed state from the current CPU and
+        * transitions the CPU out of TM mode.  Hence we need to call
+        * tm_recheckpoint_new_task() (on the same task) to restore the
+        * checkpointed state back and the TM mode.
+        */
+       __switch_to_tm(src);
+       tm_recheckpoint_new_task(src);
 
        *dst = *src;
 
index b47a0e1ab00150926df137b68d79684050f13b26..d88736fbece67c6627e6f33a9c4fd3e31ee2b533 100644 (file)
@@ -69,8 +69,8 @@ _GLOBAL(relocate)
         * R_PPC64_RELATIVE ones.
         */
        mtctr   r8
-5:     lwz     r0,12(9)        /* ELF64_R_TYPE(reloc->r_info) */
-       cmpwi   r0,R_PPC64_RELATIVE
+5:     ld      r0,8(9)         /* ELF64_R_TYPE(reloc->r_info) */
+       cmpdi   r0,R_PPC64_RELATIVE
        bne     6f
        ld      r6,0(r9)        /* reloc->r_offset */
        ld      r0,16(r9)       /* reloc->r_addend */
@@ -81,6 +81,7 @@ _GLOBAL(relocate)
 
 6:     blr
 
+.balign 8
 p_dyn: .llong  __dynamic_start - 0b
 p_rela:        .llong  __rela_dyn_start - 0b
 p_st:  .llong  _stext - 0b
index 2b0da27eaee4242f156d37bfbb4efa06bad334df..04cc4fcca78b690f86c089708745e6c4cc0f5939 100644 (file)
@@ -247,7 +247,12 @@ static void __init exc_lvl_early_init(void)
        /* interrupt stacks must be in lowmem, we get that for free on ppc32
         * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */
        for_each_possible_cpu(i) {
+#ifdef CONFIG_SMP
                hw_cpu = get_hard_smp_processor_id(i);
+#else
+               hw_cpu = 0;
+#endif
+
                critirq_ctx[hw_cpu] = (struct thread_info *)
                        __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
 #ifdef CONFIG_BOOKE
index e35bf773df7a8d972990374cbb1507db261ccea2..8d253c29649b514e6f12694a5794329e008f1ea2 100644 (file)
@@ -65,8 +65,8 @@ struct rt_sigframe {
        struct siginfo __user *pinfo;
        void __user *puc;
        struct siginfo info;
-       /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
-       char abigap[288];
+       /* New 64 bit little-endian ABI allows redzone of 512 bytes below sp */
+       char abigap[USER_REDZONE_SIZE];
 } __attribute__ ((aligned (16)));
 
 static const char fmt32[] = KERN_INFO \
index 79683d0393f5d01577503b02d7d298018647a758..6ac107ac402a93ffcabb5f0cd365132f922fe88d 100644 (file)
@@ -6,7 +6,7 @@
        .globl vdso32_start, vdso32_end
        .balign PAGE_SIZE
 vdso32_start:
-       .incbin "arch/powerpc/kernel/vdso32/vdso32.so"
+       .incbin "arch/powerpc/kernel/vdso32/vdso32.so.dbg"
        .balign PAGE_SIZE
 vdso32_end:
 
index 8df9e2463007c1601012aae7062c6a8896ebf9ef..df60fca6a13d1eb745612e78c0be86a32fb78c45 100644 (file)
@@ -6,7 +6,7 @@
        .globl vdso64_start, vdso64_end
        .balign PAGE_SIZE
 vdso64_start:
-       .incbin "arch/powerpc/kernel/vdso64/vdso64.so"
+       .incbin "arch/powerpc/kernel/vdso64/vdso64.so.dbg"
        .balign PAGE_SIZE
 vdso64_end:
 
index e66d4ec04d953a78a314b43a3a07f47ca27f5ae7..818dce344e82a0fa0a94fe7f21eefdb2483fbc68 100644 (file)
@@ -1504,73 +1504,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 1:     addi    r8,r8,16
        .endr
 
-       /* Save DEC */
-       mfspr   r5,SPRN_DEC
-       mftb    r6
-       extsw   r5,r5
-       add     r5,r5,r6
-       std     r5,VCPU_DEC_EXPIRES(r9)
-
-BEGIN_FTR_SECTION
-       b       8f
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
-       /* Save POWER8-specific registers */
-       mfspr   r5, SPRN_IAMR
-       mfspr   r6, SPRN_PSPB
-       mfspr   r7, SPRN_FSCR
-       std     r5, VCPU_IAMR(r9)
-       stw     r6, VCPU_PSPB(r9)
-       std     r7, VCPU_FSCR(r9)
-       mfspr   r5, SPRN_IC
-       mfspr   r6, SPRN_VTB
-       mfspr   r7, SPRN_TAR
-       std     r5, VCPU_IC(r9)
-       std     r6, VCPU_VTB(r9)
-       std     r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       mfspr   r5, SPRN_TFHAR
-       mfspr   r6, SPRN_TFIAR
-       mfspr   r7, SPRN_TEXASR
-       std     r5, VCPU_TFHAR(r9)
-       std     r6, VCPU_TFIAR(r9)
-       std     r7, VCPU_TEXASR(r9)
-#endif
-       mfspr   r8, SPRN_EBBHR
-       std     r8, VCPU_EBBHR(r9)
-       mfspr   r5, SPRN_EBBRR
-       mfspr   r6, SPRN_BESCR
-       mfspr   r7, SPRN_CSIGR
-       mfspr   r8, SPRN_TACR
-       std     r5, VCPU_EBBRR(r9)
-       std     r6, VCPU_BESCR(r9)
-       std     r7, VCPU_CSIGR(r9)
-       std     r8, VCPU_TACR(r9)
-       mfspr   r5, SPRN_TCSCR
-       mfspr   r6, SPRN_ACOP
-       mfspr   r7, SPRN_PID
-       mfspr   r8, SPRN_WORT
-       std     r5, VCPU_TCSCR(r9)
-       std     r6, VCPU_ACOP(r9)
-       stw     r7, VCPU_GUEST_PID(r9)
-       std     r8, VCPU_WORT(r9)
-8:
-
-       /* Save and reset AMR and UAMOR before turning on the MMU */
-BEGIN_FTR_SECTION
-       mfspr   r5,SPRN_AMR
-       mfspr   r6,SPRN_UAMOR
-       std     r5,VCPU_AMR(r9)
-       std     r6,VCPU_UAMOR(r9)
-       li      r6,0
-       mtspr   SPRN_AMR,r6
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
        /* Unset guest mode */
        li      r0, KVM_GUEST_MODE_NONE
        stb     r0, HSTATE_IN_GUEST(r13)
@@ -2203,7 +2136,7 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        mfspr   r6,SPRN_VRSAVE
-       stw     r6,VCPU_VRSAVE(r3)
+       stw     r6,VCPU_VRSAVE(r31)
        mtlr    r30
        mtmsrd  r5
        isync
@@ -2240,7 +2173,7 @@ BEGIN_FTR_SECTION
        bl      .load_vr_state
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
-       lwz     r7,VCPU_VRSAVE(r4)
+       lwz     r7,VCPU_VRSAVE(r31)
        mtspr   SPRN_VRSAVE,r7
        mtlr    r30
        mr      r4,r31
index de6881259aef3bd552c53ea77751093336e2e5be..d766d6ee33fe6889e5a96b3898f8c47b0050fc14 100644 (file)
@@ -207,6 +207,20 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
                if (overlaps_kernel_text(vaddr, vaddr + step))
                        tprot &= ~HPTE_R_N;
 
+               /*
+                * If relocatable, check if it overlaps interrupt vectors that
+                * are copied down to real 0. For relocatable kernel
+                * (e.g. kdump case) we copy interrupt vectors down to real
+                * address 0. Mark that region as executable. This is
+                * because on p8 system with relocation on exception feature
+                * enabled, exceptions are raised with MMU (IR=DR=1) ON. Hence
+                * in order to execute the interrupt handlers in virtual
+                * mode the vector region need to be marked as executable.
+                */
+               if ((PHYSICAL_START > MEMORY_START) &&
+                       overlaps_interrupt_vector_text(vaddr, vaddr + step))
+                               tprot &= ~HPTE_R_N;
+
                hash = hpt_hash(vpn, shift, ssize);
                hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
 
index 65b7b65e8708bd1867861f4b519d207b25beb5a7..62bf5e8e78daaaf5051fb6e5727bfd99be81a088 100644 (file)
@@ -510,7 +510,8 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
 }
 
 unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
-                                 pmd_t *pmdp, unsigned long clr)
+                                 pmd_t *pmdp, unsigned long clr,
+                                 unsigned long set)
 {
 
        unsigned long old, tmp;
@@ -526,14 +527,15 @@ unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
                andi.   %1,%0,%6\n\
                bne-    1b \n\
                andc    %1,%0,%4 \n\
+               or      %1,%1,%7\n\
                stdcx.  %1,0,%3 \n\
                bne-    1b"
        : "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
-       : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY)
+       : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY), "r" (set)
        : "cc" );
 #else
        old = pmd_val(*pmdp);
-       *pmdp = __pmd(old & ~clr);
+       *pmdp = __pmd((old & ~clr) | set);
 #endif
        if (old & _PAGE_HASHPTE)
                hpte_do_hugepage_flush(mm, addr, pmdp);
@@ -708,7 +710,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
 void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
                     pmd_t *pmdp)
 {
-       pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT);
+       pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
 }
 
 /*
@@ -835,7 +837,7 @@ pmd_t pmdp_get_and_clear(struct mm_struct *mm,
        unsigned long old;
        pgtable_t *pgtable_slot;
 
-       old = pmd_hugepage_update(mm, addr, pmdp, ~0UL);
+       old = pmd_hugepage_update(mm, addr, pmdp, ~0UL, 0);
        old_pmd = __pmd(old);
        /*
         * We have pmd == none and we are holding page_table_lock.
index a770df2dae7050bafd28daf1c354165113e378f9..6c0b1f5f8d2ccef746ccddfed70684c45f3adec2 100644 (file)
@@ -78,7 +78,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
        pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
        arch_enter_lazy_mmu_mode();
        for (; npages > 0; --npages) {
-               pte_update(mm, addr, pte, 0, 0);
+               pte_update(mm, addr, pte, 0, 0, 0);
                addr += PAGE_SIZE;
                ++pte;
        }
index 555034f8505e8d1d83bfeef3480a9bc058499754..808ce1cae21ab998439854e31eacaced66c044cb 100644 (file)
@@ -390,9 +390,9 @@ static int bpf_jit_build_body(struct sk_filter *fp, u32 *image,
                                                          mark));
                        break;
                case BPF_S_ANC_RXHASH:
-                       BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+                       BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
                        PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff,
-                                                         rxhash));
+                                                         hash));
                        break;
                case BPF_S_ANC_VLAN_TAG:
                case BPF_S_ANC_VLAN_TAG_PRESENT:
@@ -689,6 +689,7 @@ void bpf_jit_compile(struct sk_filter *fp)
                ((u64 *)image)[0] = (u64)code_base;
                ((u64 *)image)[1] = local_paca->kernel_toc;
                fp->bpf_func = (void *)image;
+               fp->jited = 1;
        }
 out:
        kfree(addrs);
@@ -697,7 +698,7 @@ out:
 
 void bpf_jit_free(struct sk_filter *fp)
 {
-       if (fp->bpf_func != sk_run_filter)
+       if (fp->jited)
                module_free(NULL, fp->bpf_func);
        kfree(fp);
 }
index 29b89e863d7cc11328cb2d93e08f4b4598ec47a2..67cf22083f4c2cfd6175c91ce416efb68ae1a6e6 100644 (file)
@@ -1147,6 +1147,9 @@ static void power_pmu_enable(struct pmu *pmu)
        mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
 
        mb();
+       if (cpuhw->bhrb_users)
+               ppmu->config_bhrb(cpuhw->bhrb_filter);
+
        write_mmcr0(cpuhw, mmcr0);
 
        /*
@@ -1158,8 +1161,6 @@ static void power_pmu_enable(struct pmu *pmu)
        }
 
  out:
-       if (cpuhw->bhrb_users)
-               ppmu->config_bhrb(cpuhw->bhrb_filter);
 
        local_irq_restore(flags);
 }
index a3f7abd2f13f7a0793ce4e2bdb00855f9724d108..96cee20dcd34ec2cf33f6d836d4f4fd49b7848c6 100644 (file)
 #define PM_BRU_FIN                     0x10068
 #define PM_BR_MPRED_CMPL               0x400f6
 
+/* All L1 D cache load references counted at finish, gated by reject */
+#define PM_LD_REF_L1                   0x100ee
+/* Load Missed L1 */
+#define PM_LD_MISS_L1                  0x3e054
+/* Store Missed L1 */
+#define PM_ST_MISS_L1                  0x300f0
+/* L1 cache data prefetches */
+#define PM_L1_PREF                     0x0d8b8
+/* Instruction fetches from L1 */
+#define PM_INST_FROM_L1                        0x04080
+/* Demand iCache Miss */
+#define PM_L1_ICACHE_MISS              0x200fd
+/* Instruction Demand sectors wriittent into IL1 */
+#define PM_L1_DEMAND_WRITE             0x0408c
+/* Instruction prefetch written into IL1 */
+#define PM_IC_PREF_WRITE               0x0408e
+/* The data cache was reloaded from local core's L3 due to a demand load */
+#define PM_DATA_FROM_L3                        0x4c042
+/* Demand LD - L3 Miss (not L2 hit and not L3 hit) */
+#define PM_DATA_FROM_L3MISS            0x300fe
+/* All successful D-side store dispatches for this thread */
+#define PM_L2_ST                       0x17080
+/* All successful D-side store dispatches for this thread that were L2 Miss */
+#define PM_L2_ST_MISS                  0x17082
+/* Total HW L3 prefetches(Load+store) */
+#define PM_L3_PREF_ALL                 0x4e052
+/* Data PTEG reload */
+#define PM_DTLB_MISS                   0x300fc
+/* ITLB Reloaded */
+#define PM_ITLB_MISS                   0x400fc
+
 
 /*
  * Raw event encoding for POWER8:
@@ -557,6 +588,8 @@ static int power8_generic_events[] = {
        [PERF_COUNT_HW_INSTRUCTIONS] =                  PM_INST_CMPL,
        [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] =           PM_BRU_FIN,
        [PERF_COUNT_HW_BRANCH_MISSES] =                 PM_BR_MPRED_CMPL,
+       [PERF_COUNT_HW_CACHE_REFERENCES] =              PM_LD_REF_L1,
+       [PERF_COUNT_HW_CACHE_MISSES] =                  PM_LD_MISS_L1,
 };
 
 static u64 power8_bhrb_filter_map(u64 branch_sample_type)
@@ -596,6 +629,116 @@ static void power8_config_bhrb(u64 pmu_bhrb_filter)
        mtspr(SPRN_MMCRA, (mfspr(SPRN_MMCRA) | pmu_bhrb_filter));
 }
 
+#define C(x)   PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int power8_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+       [ C(L1D) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_LD_REF_L1,
+                       [ C(RESULT_MISS)   ] = PM_LD_MISS_L1,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = 0,
+                       [ C(RESULT_MISS)   ] = PM_ST_MISS_L1,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_L1_PREF,
+                       [ C(RESULT_MISS)   ] = 0,
+               },
+       },
+       [ C(L1I) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_INST_FROM_L1,
+                       [ C(RESULT_MISS)   ] = PM_L1_ICACHE_MISS,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_L1_DEMAND_WRITE,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_IC_PREF_WRITE,
+                       [ C(RESULT_MISS)   ] = 0,
+               },
+       },
+       [ C(LL) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_DATA_FROM_L3,
+                       [ C(RESULT_MISS)   ] = PM_DATA_FROM_L3MISS,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_L2_ST,
+                       [ C(RESULT_MISS)   ] = PM_L2_ST_MISS,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_L3_PREF_ALL,
+                       [ C(RESULT_MISS)   ] = 0,
+               },
+       },
+       [ C(DTLB) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = 0,
+                       [ C(RESULT_MISS)   ] = PM_DTLB_MISS,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+       },
+       [ C(ITLB) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = 0,
+                       [ C(RESULT_MISS)   ] = PM_ITLB_MISS,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+       },
+       [ C(BPU) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = PM_BRU_FIN,
+                       [ C(RESULT_MISS)   ] = PM_BR_MPRED_CMPL,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+       },
+       [ C(NODE) ] = {
+               [ C(OP_READ) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+               [ C(OP_WRITE) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+               [ C(OP_PREFETCH) ] = {
+                       [ C(RESULT_ACCESS) ] = -1,
+                       [ C(RESULT_MISS)   ] = -1,
+               },
+       },
+};
+
+#undef C
+
 static struct power_pmu power8_pmu = {
        .name                   = "POWER8",
        .n_counter              = 6,
@@ -611,6 +754,7 @@ static struct power_pmu power8_pmu = {
        .flags                  = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB | PPMU_EBB,
        .n_generic              = ARRAY_SIZE(power8_generic_events),
        .generic_events         = power8_generic_events,
+       .cache_events           = &power8_cache_events,
        .attr_groups            = power8_pmu_attr_groups,
        .bhrb_nr                = 32,
 };
index 5ec1e47a0d771eba56e8b8c42111a19aed7df25a..e865d748179b2ac1b0b7550c1d3bebbcae71e049 100644 (file)
@@ -123,7 +123,8 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order)
 
        area->nid = nid;
        area->order = order;
-       area->pages = alloc_pages_exact_node(area->nid, GFP_KERNEL|GFP_THISNODE,
+       area->pages = alloc_pages_exact_node(area->nid,
+                                               GFP_KERNEL|__GFP_THISNODE,
                                                area->order);
 
        if (!area->pages) {
index e1e71618b70cfe5d4caa7d15e30bc42a37361c56..253fefe3d1a0e76fd4ed3996711b6f1784725d6c 100644 (file)
@@ -44,7 +44,8 @@ static int ioda_eeh_event(struct notifier_block *nb,
 
        /* We simply send special EEH event */
        if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
-           (events & OPAL_EVENT_PCI_ERROR))
+           (events & OPAL_EVENT_PCI_ERROR) &&
+           eeh_enabled())
                eeh_send_failure_event(NULL);
 
        return 0;
@@ -113,6 +114,7 @@ DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_inbB_dbgfs_ops, ioda_eeh_inbB_dbgfs_get,
                        ioda_eeh_inbB_dbgfs_set, "0x%llx\n");
 #endif /* CONFIG_DEBUG_FS */
 
+
 /**
  * ioda_eeh_post_init - Chip dependent post initialization
  * @hose: PCI controller
@@ -220,6 +222,22 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
        return ret;
 }
 
+static void ioda_eeh_phb_diag(struct pci_controller *hose)
+{
+       struct pnv_phb *phb = hose->private_data;
+       long rc;
+
+       rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+                                        PNV_PCI_DIAG_BUF_SIZE);
+       if (rc != OPAL_SUCCESS) {
+               pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
+                           __func__, hose->global_number, rc);
+               return;
+       }
+
+       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
+}
+
 /**
  * ioda_eeh_get_state - Retrieve the state of PE
  * @pe: EEH PE
@@ -271,6 +289,9 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
                        result |= EEH_STATE_DMA_ACTIVE;
                        result |= EEH_STATE_MMIO_ENABLED;
                        result |= EEH_STATE_DMA_ENABLED;
+               } else if (!(pe->state & EEH_PE_ISOLATED)) {
+                       eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+                       ioda_eeh_phb_diag(hose);
                }
 
                return result;
@@ -314,6 +335,15 @@ static int ioda_eeh_get_state(struct eeh_pe *pe)
                           __func__, fstate, hose->global_number, pe_no);
        }
 
+       /* Dump PHB diag-data for frozen PE */
+       if (result != EEH_STATE_NOT_SUPPORT &&
+           (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) !=
+           (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
+           !(pe->state & EEH_PE_ISOLATED)) {
+               eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+               ioda_eeh_phb_diag(hose);
+       }
+
        return result;
 }
 
@@ -489,8 +519,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose,
 static int ioda_eeh_reset(struct eeh_pe *pe, int option)
 {
        struct pci_controller *hose = pe->phb;
-       struct eeh_dev *edev;
-       struct pci_dev *dev;
+       struct pci_bus *bus;
        int ret;
 
        /*
@@ -519,72 +548,16 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option)
        if (pe->type & EEH_PE_PHB) {
                ret = ioda_eeh_phb_reset(hose, option);
        } else {
-               if (pe->type & EEH_PE_DEVICE) {
-                       /*
-                        * If it's device PE, we didn't refer to the parent
-                        * PCI bus yet. So we have to figure it out indirectly.
-                        */
-                       edev = list_first_entry(&pe->edevs,
-                                       struct eeh_dev, list);
-                       dev = eeh_dev_to_pci_dev(edev);
-                       dev = dev->bus->self;
-               } else {
-                       /*
-                        * If it's bus PE, the parent PCI bus is already there
-                        * and just pick it up.
-                        */
-                       dev = pe->bus->self;
-               }
-
-               /*
-                * Do reset based on the fact that the direct upstream bridge
-                * is root bridge (port) or not.
-                */
-               if (dev->bus->number == 0)
+               bus = eeh_pe_bus_get(pe);
+               if (pci_is_root_bus(bus))
                        ret = ioda_eeh_root_reset(hose, option);
                else
-                       ret = ioda_eeh_bridge_reset(hose, dev, option);
+                       ret = ioda_eeh_bridge_reset(hose, bus->self, option);
        }
 
        return ret;
 }
 
-/**
- * ioda_eeh_get_log - Retrieve error log
- * @pe: EEH PE
- * @severity: Severity level of the log
- * @drv_log: buffer to store the log
- * @len: space of the log buffer
- *
- * The function is used to retrieve error log from P7IOC.
- */
-static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
-                           char *drv_log, unsigned long len)
-{
-       s64 ret;
-       unsigned long flags;
-       struct pci_controller *hose = pe->phb;
-       struct pnv_phb *phb = hose->private_data;
-
-       spin_lock_irqsave(&phb->lock, flags);
-
-       ret = opal_pci_get_phb_diag_data2(phb->opal_id,
-                       phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
-       if (ret) {
-               spin_unlock_irqrestore(&phb->lock, flags);
-               pr_warning("%s: Can't get log for PHB#%x-PE#%x (%lld)\n",
-                          __func__, hose->global_number, pe->addr, ret);
-               return -EIO;
-       }
-
-       /* The PHB diag-data is always indicative */
-       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-
-       spin_unlock_irqrestore(&phb->lock, flags);
-
-       return 0;
-}
-
 /**
  * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
  * @pe: EEH PE
@@ -666,22 +639,6 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
        }
 }
 
-static void ioda_eeh_phb_diag(struct pci_controller *hose)
-{
-       struct pnv_phb *phb = hose->private_data;
-       long rc;
-
-       rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
-                                        PNV_PCI_DIAG_BUF_SIZE);
-       if (rc != OPAL_SUCCESS) {
-               pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
-                           __func__, hose->global_number, rc);
-               return;
-       }
-
-       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
-}
-
 static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
                               struct eeh_pe **pe)
 {
@@ -854,6 +811,20 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                                __func__, err_type);
                }
 
+               /*
+                * EEH core will try recover from fenced PHB or
+                * frozen PE. In the time for frozen PE, EEH core
+                * enable IO path for that before collecting logs,
+                * but it ruins the site. So we have to dump the
+                * log in advance here.
+                */
+               if ((ret == EEH_NEXT_ERR_FROZEN_PE  ||
+                   ret == EEH_NEXT_ERR_FENCED_PHB) &&
+                   !((*pe)->state & EEH_PE_ISOLATED)) {
+                       eeh_pe_state_mark(*pe, EEH_PE_ISOLATED);
+                       ioda_eeh_phb_diag(hose);
+               }
+
                /*
                 * If we have no errors on the specific PHB or only
                 * informative error there, we continue poking it.
@@ -872,7 +843,6 @@ struct pnv_eeh_ops ioda_eeh_ops = {
        .set_option             = ioda_eeh_set_option,
        .get_state              = ioda_eeh_get_state,
        .reset                  = ioda_eeh_reset,
-       .get_log                = ioda_eeh_get_log,
        .configure_bridge       = ioda_eeh_configure_bridge,
        .next_error             = ioda_eeh_next_error
 };
index a79fddc5e74e58ac0a0b18fc1b7cb5db607095b2..a59788e83b8b377152ed5d70db86fbb7bc9fb805 100644 (file)
@@ -145,7 +145,7 @@ static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
         * Enable EEH explicitly so that we will do EEH check
         * while accessing I/O stuff
         */
-       eeh_subsystem_enabled = 1;
+       eeh_set_enable(true);
 
        /* Save memory bars */
        eeh_save_bars(edev);
index 4fbf276ac99eeb4e2900196e3905a3343bedc988..4cd2ea6c0dbe13ecf2fb7926838cfeac9277730c 100644 (file)
@@ -71,11 +71,11 @@ static int opal_xscom_err_xlate(int64_t rc)
        }
 }
 
-static u64 opal_scom_unmangle(u64 reg)
+static u64 opal_scom_unmangle(u64 addr)
 {
        /*
         * XSCOM indirect addresses have the top bit set. Additionally
-        * the reset of the top 3 nibbles is always 0.
+        * the rest of the top 3 nibbles is always 0.
         *
         * Because the debugfs interface uses signed offsets and shifts
         * the address left by 3, we basically cannot use the top 4 bits
@@ -86,10 +86,13 @@ static u64 opal_scom_unmangle(u64 reg)
         * conversion here. To leave room for further xscom address
         * expansion, we only clear out the top byte
         *
+        * For in-kernel use, we also support the real indirect bit, so
+        * we test for any of the top 5 bits
+        *
         */
-       if (reg & (1ull << 59))
-               reg = (reg & ~(0xffull << 56)) | (1ull << 63);
-       return reg;
+       if (addr & (0x1full << 59))
+               addr = (addr & ~(0xffull << 56)) | (1ull << 63);
+       return addr;
 }
 
 static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
@@ -98,8 +101,8 @@ static int opal_scom_read(scom_map_t map, u64 reg, u64 *value)
        int64_t rc;
        __be64 v;
 
-       reg = opal_scom_unmangle(reg);
-       rc = opal_xscom_read(m->chip, m->addr + reg, (__be64 *)__pa(&v));
+       reg = opal_scom_unmangle(m->addr + reg);
+       rc = opal_xscom_read(m->chip, reg, (__be64 *)__pa(&v));
        *value = be64_to_cpu(v);
        return opal_xscom_err_xlate(rc);
 }
@@ -109,8 +112,8 @@ static int opal_scom_write(scom_map_t map, u64 reg, u64 value)
        struct opal_scom_map *m = map;
        int64_t rc;
 
-       reg = opal_scom_unmangle(reg);
-       rc = opal_xscom_write(m->chip, m->addr + reg, value);
+       reg = opal_scom_unmangle(m->addr + reg);
+       rc = opal_xscom_write(m->chip, reg, value);
        return opal_xscom_err_xlate(rc);
 }
 
index 7d6dcc6d5fa9a6551c2465285cc1886242cc0125..3b2b4fb3585b6b9fac45878041772285591d1d63 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/msi.h>
+#include <linux/memblock.h>
 
 #include <asm/sections.h>
 #include <asm/io.h>
@@ -460,9 +461,39 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
                return;
 
        pe = &phb->ioda.pe_array[pdn->pe_number];
+       WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
        set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
 }
 
+static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
+                                    struct pci_dev *pdev, u64 dma_mask)
+{
+       struct pci_dn *pdn = pci_get_pdn(pdev);
+       struct pnv_ioda_pe *pe;
+       uint64_t top;
+       bool bypass = false;
+
+       if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
+               return -ENODEV;;
+
+       pe = &phb->ioda.pe_array[pdn->pe_number];
+       if (pe->tce_bypass_enabled) {
+               top = pe->tce_bypass_base + memblock_end_of_DRAM() - 1;
+               bypass = (dma_mask >= top);
+       }
+
+       if (bypass) {
+               dev_info(&pdev->dev, "Using 64-bit DMA iommu bypass\n");
+               set_dma_ops(&pdev->dev, &dma_direct_ops);
+               set_dma_offset(&pdev->dev, pe->tce_bypass_base);
+       } else {
+               dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n");
+               set_dma_ops(&pdev->dev, &dma_iommu_ops);
+               set_iommu_table_base(&pdev->dev, &pe->tce32_table);
+       }
+       return 0;
+}
+
 static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
 {
        struct pci_dev *dev;
@@ -657,6 +688,56 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
                __free_pages(tce_mem, get_order(TCE32_TABLE_SIZE * segs));
 }
 
+static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
+{
+       struct pnv_ioda_pe *pe = container_of(tbl, struct pnv_ioda_pe,
+                                             tce32_table);
+       uint16_t window_id = (pe->pe_number << 1 ) + 1;
+       int64_t rc;
+
+       pe_info(pe, "%sabling 64-bit DMA bypass\n", enable ? "En" : "Dis");
+       if (enable) {
+               phys_addr_t top = memblock_end_of_DRAM();
+
+               top = roundup_pow_of_two(top);
+               rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
+                                                    pe->pe_number,
+                                                    window_id,
+                                                    pe->tce_bypass_base,
+                                                    top);
+       } else {
+               rc = opal_pci_map_pe_dma_window_real(pe->phb->opal_id,
+                                                    pe->pe_number,
+                                                    window_id,
+                                                    pe->tce_bypass_base,
+                                                    0);
+
+               /*
+                * We might want to reset the DMA ops of all devices on
+                * this PE. However in theory, that shouldn't be necessary
+                * as this is used for VFIO/KVM pass-through and the device
+                * hasn't yet been returned to its kernel driver
+                */
+       }
+       if (rc)
+               pe_err(pe, "OPAL error %lld configuring bypass window\n", rc);
+       else
+               pe->tce_bypass_enabled = enable;
+}
+
+static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb,
+                                         struct pnv_ioda_pe *pe)
+{
+       /* TVE #1 is selected by PCI address bit 59 */
+       pe->tce_bypass_base = 1ull << 59;
+
+       /* Install set_bypass callback for VFIO */
+       pe->tce32_table.set_bypass = pnv_pci_ioda2_set_bypass;
+
+       /* Enable bypass by default */
+       pnv_pci_ioda2_set_bypass(&pe->tce32_table, true);
+}
+
 static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
                                       struct pnv_ioda_pe *pe)
 {
@@ -727,6 +808,8 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
        else
                pnv_ioda_setup_bus_dma(pe, pe->pbus);
 
+       /* Also create a bypass window */
+       pnv_pci_ioda2_setup_bypass_pe(phb, pe);
        return;
 fail:
        if (pe->tce32_seg >= 0)
@@ -1286,6 +1369,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 
        /* Setup TCEs */
        phb->dma_dev_setup = pnv_pci_ioda_dma_dev_setup;
+       phb->dma_set_mask = pnv_pci_ioda_dma_set_mask;
 
        /* Setup shutdown function for kexec */
        phb->shutdown = pnv_pci_ioda_shutdown;
index b555ebc57ef5a33010ea4becbf992d3deb2dcbad..8518817dcdfdc95d04e3b1fc10bfe54432330079 100644 (file)
@@ -134,57 +134,72 @@ static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
        pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n",
                hose->global_number, common->version);
 
-       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
-       pr_info("  slotStatus:           %08x\n", data->slotStatus);
-       pr_info("  linkStatus:           %08x\n", data->linkStatus);
-       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
-       pr_info("  sourceId:             %08x\n", data->sourceId);
-       pr_info("  errorClass:           %016llx\n", data->errorClass);
-       pr_info("  correlator:           %016llx\n", data->correlator);
-       pr_info("  p7iocPlssr:           %016llx\n", data->p7iocPlssr);
-       pr_info("  p7iocCsr:             %016llx\n", data->p7iocCsr);
-       pr_info("  lemFir:               %016llx\n", data->lemFir);
-       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
+       if (data->brdgCtl)
+               pr_info("  brdgCtl:     %08x\n",
+                       data->brdgCtl);
+       if (data->portStatusReg || data->rootCmplxStatus ||
+           data->busAgentStatus)
+               pr_info("  UtlSts:      %08x %08x %08x\n",
+                       data->portStatusReg, data->rootCmplxStatus,
+                       data->busAgentStatus);
+       if (data->deviceStatus || data->slotStatus   ||
+           data->linkStatus   || data->devCmdStatus ||
+           data->devSecStatus)
+               pr_info("  RootSts:     %08x %08x %08x %08x %08x\n",
+                       data->deviceStatus, data->slotStatus,
+                       data->linkStatus, data->devCmdStatus,
+                       data->devSecStatus);
+       if (data->rootErrorStatus   || data->uncorrErrorStatus ||
+           data->corrErrorStatus)
+               pr_info("  RootErrSts:  %08x %08x %08x\n",
+                       data->rootErrorStatus, data->uncorrErrorStatus,
+                       data->corrErrorStatus);
+       if (data->tlpHdr1 || data->tlpHdr2 ||
+           data->tlpHdr3 || data->tlpHdr4)
+               pr_info("  RootErrLog:  %08x %08x %08x %08x\n",
+                       data->tlpHdr1, data->tlpHdr2,
+                       data->tlpHdr3, data->tlpHdr4);
+       if (data->sourceId || data->errorClass ||
+           data->correlator)
+               pr_info("  RootErrLog1: %08x %016llx %016llx\n",
+                       data->sourceId, data->errorClass,
+                       data->correlator);
+       if (data->p7iocPlssr || data->p7iocCsr)
+               pr_info("  PhbSts:      %016llx %016llx\n",
+                       data->p7iocPlssr, data->p7iocCsr);
+       if (data->lemFir || data->lemErrorMask ||
+           data->lemWOF)
+               pr_info("  Lem:         %016llx %016llx %016llx\n",
+                       data->lemFir, data->lemErrorMask,
+                       data->lemWOF);
+       if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+           data->phbErrorLog0   || data->phbErrorLog1)
+               pr_info("  PhbErr:      %016llx %016llx %016llx %016llx\n",
+                       data->phbErrorStatus, data->phbFirstErrorStatus,
+                       data->phbErrorLog0, data->phbErrorLog1);
+       if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+           data->mmioErrorLog0   || data->mmioErrorLog1)
+               pr_info("  OutErr:      %016llx %016llx %016llx %016llx\n",
+                       data->mmioErrorStatus, data->mmioFirstErrorStatus,
+                       data->mmioErrorLog0, data->mmioErrorLog1);
+       if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+           data->dma0ErrorLog0   || data->dma0ErrorLog1)
+               pr_info("  InAErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+                       data->dma0ErrorLog0, data->dma0ErrorLog1);
+       if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+           data->dma1ErrorLog0   || data->dma1ErrorLog1)
+               pr_info("  InBErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+                       data->dma1ErrorLog0, data->dma1ErrorLog1);
 
        for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
                if ((data->pestA[i] >> 63) == 0 &&
                    (data->pestB[i] >> 63) == 0)
                        continue;
 
-               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
+               pr_info("  PE[%3d] A/B: %016llx %016llx\n",
+                       i, data->pestA[i], data->pestB[i]);
        }
 }
 
@@ -197,62 +212,77 @@ static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
        data = (struct OpalIoPhb3ErrorData*)common;
        pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n",
                hose->global_number, common->version);
-
-       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
-       pr_info("  slotStatus:           %08x\n", data->slotStatus);
-       pr_info("  linkStatus:           %08x\n", data->linkStatus);
-       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
-       pr_info("  sourceId:             %08x\n", data->sourceId);
-       pr_info("  errorClass:           %016llx\n", data->errorClass);
-       pr_info("  correlator:           %016llx\n", data->correlator);
-
-       pr_info("  nFir:                 %016llx\n", data->nFir);
-       pr_info("  nFirMask:             %016llx\n", data->nFirMask);
-       pr_info("  nFirWOF:              %016llx\n", data->nFirWOF);
-       pr_info("  PhbPlssr:             %016llx\n", data->phbPlssr);
-       pr_info("  PhbCsr:               %016llx\n", data->phbCsr);
-       pr_info("  lemFir:               %016llx\n", data->lemFir);
-       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
+       if (data->brdgCtl)
+               pr_info("  brdgCtl:     %08x\n",
+                       data->brdgCtl);
+       if (data->portStatusReg || data->rootCmplxStatus ||
+           data->busAgentStatus)
+               pr_info("  UtlSts:      %08x %08x %08x\n",
+                       data->portStatusReg, data->rootCmplxStatus,
+                       data->busAgentStatus);
+       if (data->deviceStatus || data->slotStatus   ||
+           data->linkStatus   || data->devCmdStatus ||
+           data->devSecStatus)
+               pr_info("  RootSts:     %08x %08x %08x %08x %08x\n",
+                       data->deviceStatus, data->slotStatus,
+                       data->linkStatus, data->devCmdStatus,
+                       data->devSecStatus);
+       if (data->rootErrorStatus || data->uncorrErrorStatus ||
+           data->corrErrorStatus)
+               pr_info("  RootErrSts:  %08x %08x %08x\n",
+                       data->rootErrorStatus, data->uncorrErrorStatus,
+                       data->corrErrorStatus);
+       if (data->tlpHdr1 || data->tlpHdr2 ||
+           data->tlpHdr3 || data->tlpHdr4)
+               pr_info("  RootErrLog:  %08x %08x %08x %08x\n",
+                       data->tlpHdr1, data->tlpHdr2,
+                       data->tlpHdr3, data->tlpHdr4);
+       if (data->sourceId || data->errorClass ||
+           data->correlator)
+               pr_info("  RootErrLog1: %08x %016llx %016llx\n",
+                       data->sourceId, data->errorClass,
+                       data->correlator);
+       if (data->nFir || data->nFirMask ||
+           data->nFirWOF)
+               pr_info("  nFir:        %016llx %016llx %016llx\n",
+                       data->nFir, data->nFirMask,
+                       data->nFirWOF);
+       if (data->phbPlssr || data->phbCsr)
+               pr_info("  PhbSts:      %016llx %016llx\n",
+                       data->phbPlssr, data->phbCsr);
+       if (data->lemFir || data->lemErrorMask ||
+           data->lemWOF)
+               pr_info("  Lem:         %016llx %016llx %016llx\n",
+                       data->lemFir, data->lemErrorMask,
+                       data->lemWOF);
+       if (data->phbErrorStatus || data->phbFirstErrorStatus ||
+           data->phbErrorLog0   || data->phbErrorLog1)
+               pr_info("  PhbErr:      %016llx %016llx %016llx %016llx\n",
+                       data->phbErrorStatus, data->phbFirstErrorStatus,
+                       data->phbErrorLog0, data->phbErrorLog1);
+       if (data->mmioErrorStatus || data->mmioFirstErrorStatus ||
+           data->mmioErrorLog0   || data->mmioErrorLog1)
+               pr_info("  OutErr:      %016llx %016llx %016llx %016llx\n",
+                       data->mmioErrorStatus, data->mmioFirstErrorStatus,
+                       data->mmioErrorLog0, data->mmioErrorLog1);
+       if (data->dma0ErrorStatus || data->dma0FirstErrorStatus ||
+           data->dma0ErrorLog0   || data->dma0ErrorLog1)
+               pr_info("  InAErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma0ErrorStatus, data->dma0FirstErrorStatus,
+                       data->dma0ErrorLog0, data->dma0ErrorLog1);
+       if (data->dma1ErrorStatus || data->dma1FirstErrorStatus ||
+           data->dma1ErrorLog0   || data->dma1ErrorLog1)
+               pr_info("  InBErr:      %016llx %016llx %016llx %016llx\n",
+                       data->dma1ErrorStatus, data->dma1FirstErrorStatus,
+                       data->dma1ErrorLog0, data->dma1ErrorLog1);
 
        for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) {
                if ((data->pestA[i] >> 63) == 0 &&
                    (data->pestB[i] >> 63) == 0)
                        continue;
 
-               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
+               pr_info("  PE[%3d] A/B: %016llx %016llx\n",
+                       i, data->pestA[i], data->pestB[i]);
        }
 }
 
@@ -634,6 +664,16 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
                pnv_pci_dma_fallback_setup(hose, pdev);
 }
 
+int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
+{
+       struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+       struct pnv_phb *phb = hose->private_data;
+
+       if (phb && phb->dma_set_mask)
+               return phb->dma_set_mask(phb, pdev, dma_mask);
+       return __dma_set_mask(&pdev->dev, dma_mask);
+}
+
 void pnv_pci_shutdown(void)
 {
        struct pci_controller *hose;
index 13f1942a9a5f98708038808a2d816f2bec0d6e1a..cde169442775c1684f0cd9f2db799d17c685deb3 100644 (file)
@@ -54,7 +54,9 @@ struct pnv_ioda_pe {
        struct iommu_table      tce32_table;
        phys_addr_t             tce_inval_reg_phys;
 
-       /* XXX TODO: Add support for additional 64-bit iommus */
+       /* 64-bit TCE bypass region */
+       bool                    tce_bypass_enabled;
+       uint64_t                tce_bypass_base;
 
        /* MSIs. MVE index is identical for for 32 and 64 bit MSI
         * and -1 if not supported. (It's actually identical to the
@@ -113,6 +115,8 @@ struct pnv_phb {
                         unsigned int hwirq, unsigned int virq,
                         unsigned int is_64, struct msi_msg *msg);
        void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
+       int (*dma_set_mask)(struct pnv_phb *phb, struct pci_dev *pdev,
+                           u64 dma_mask);
        void (*fixup_phb)(struct pci_controller *hose);
        u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
        void (*shutdown)(struct pnv_phb *phb);
index de6819be1f95ea11911bbadd5080fb05db66e884..0051e108ef0f86bd971e212db24c3110cfbf8993 100644 (file)
@@ -7,12 +7,20 @@ extern void pnv_smp_init(void);
 static inline void pnv_smp_init(void) { }
 #endif
 
+struct pci_dev;
+
 #ifdef CONFIG_PCI
 extern void pnv_pci_init(void);
 extern void pnv_pci_shutdown(void);
+extern int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask);
 #else
 static inline void pnv_pci_init(void) { }
 static inline void pnv_pci_shutdown(void) { }
+
+static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
+{
+       return -ENODEV;
+}
 #endif
 
 extern void pnv_lpc_init(void);
index 21166f65c97c37df19e48a938c33c49d5bad845e..110f4fbd319f628373522e99672a95dcffda6688 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <linux/bug.h>
 #include <linux/cpuidle.h>
+#include <linux/pci.h>
 
 #include <asm/machdep.h>
 #include <asm/firmware.h>
@@ -141,6 +142,13 @@ static void pnv_progress(char *s, unsigned short hex)
 {
 }
 
+static int pnv_dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       if (dev_is_pci(dev))
+               return pnv_pci_dma_set_mask(to_pci_dev(dev), dma_mask);
+       return __dma_set_mask(dev, dma_mask);
+}
+
 static void pnv_shutdown(void)
 {
        /* Let the PCI code clear up IODA tables */
@@ -238,6 +246,7 @@ define_machine(powernv) {
        .machine_shutdown       = pnv_shutdown,
        .power_save             = powernv_idle,
        .calibrate_decr         = generic_calibrate_decr,
+       .dma_set_mask           = pnv_dma_set_mask,
 #ifdef CONFIG_KEXEC
        .kexec_cpu_down         = pnv_kexec_cpu_down,
 #endif
index 37300f6ee244edeb96f7ebbf86c2b476d3dfbb23..80b1d57c306a997e9b3c0a2933efa00ed1ac946e 100644 (file)
@@ -20,6 +20,7 @@ config PPC_PSERIES
        select PPC_DOORBELL
        select HAVE_CONTEXT_TRACKING
        select HOTPLUG_CPU if SMP
+       select ARCH_RANDOM
        default y
 
 config PPC_SPLPAR
index 9ef3cc8ebc11c7f533a3bc966d90bd6c085d891d..8a8f0472d98fd0e56d9c199c85c4d513e04f8d9a 100644 (file)
@@ -265,7 +265,7 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
                        enable = 1;
 
                if (enable) {
-                       eeh_subsystem_enabled = 1;
+                       eeh_set_enable(true);
                        eeh_add_to_parent_pe(edev);
 
                        pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n",
index 82789e79e53985cf2b6c856f313628ff1eb0ca3e..0ea99e3d4815733a74b8098864f3594839ed97eb 100644 (file)
 #include "offline_states.h"
 
 /* This version can't take the spinlock, because it never returns */
-static struct rtas_args rtas_stop_self_args = {
-       .token = RTAS_UNKNOWN_SERVICE,
-       .nargs = 0,
-       .nret = 1,
-       .rets = &rtas_stop_self_args.args[0],
-};
+static int rtas_stop_self_token = RTAS_UNKNOWN_SERVICE;
 
 static DEFINE_PER_CPU(enum cpu_state_vals, preferred_offline_state) =
                                                        CPU_STATE_OFFLINE;
@@ -93,15 +88,20 @@ void set_default_offline_state(int cpu)
 
 static void rtas_stop_self(void)
 {
-       struct rtas_args *args = &rtas_stop_self_args;
+       struct rtas_args args = {
+               .token = cpu_to_be32(rtas_stop_self_token),
+               .nargs = 0,
+               .nret = 1,
+               .rets = &args.args[0],
+       };
 
        local_irq_disable();
 
-       BUG_ON(args->token == RTAS_UNKNOWN_SERVICE);
+       BUG_ON(rtas_stop_self_token == RTAS_UNKNOWN_SERVICE);
 
        printk("cpu %u (hwid %u) Ready to die...\n",
               smp_processor_id(), hard_smp_processor_id());
-       enter_rtas(__pa(args));
+       enter_rtas(__pa(&args));
 
        panic("Alas, I survived.\n");
 }
@@ -392,10 +392,10 @@ static int __init pseries_cpu_hotplug_init(void)
                }
        }
 
-       rtas_stop_self_args.token = rtas_token("stop-self");
+       rtas_stop_self_token = rtas_token("stop-self");
        qcss_tok = rtas_token("query-cpu-stopped-state");
 
-       if (rtas_stop_self_args.token == RTAS_UNKNOWN_SERVICE ||
+       if (rtas_stop_self_token == RTAS_UNKNOWN_SERVICE ||
                        qcss_tok == RTAS_UNKNOWN_SERVICE) {
                printk(KERN_INFO "CPU Hotplug not supported by firmware "
                                "- disabling.\n");
index 70670a2d9cf2ddd691a936dbe489d8e338ed4029..c413ec158ff5a6587e7c611659f817dc33d9c7e4 100644 (file)
@@ -113,7 +113,8 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
 {
        struct device_node *dn, *pdn;
        struct pci_bus *bus;
-       const __be32 *pcie_link_speed_stats;
+       u32 pcie_link_speed_stats[2];
+       int rc;
 
        bus = bridge->bus;
 
@@ -122,38 +123,45 @@ int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
                return 0;
 
        for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
-               pcie_link_speed_stats = of_get_property(pdn,
-                       "ibm,pcie-link-speed-stats", NULL);
-               if (pcie_link_speed_stats)
+               rc = of_property_read_u32_array(pdn,
+                               "ibm,pcie-link-speed-stats",
+                               &pcie_link_speed_stats[0], 2);
+               if (!rc)
                        break;
        }
 
        of_node_put(pdn);
 
-       if (!pcie_link_speed_stats) {
+       if (rc) {
                pr_err("no ibm,pcie-link-speed-stats property\n");
                return 0;
        }
 
-       switch (be32_to_cpup(pcie_link_speed_stats)) {
+       switch (pcie_link_speed_stats[0]) {
        case 0x01:
                bus->max_bus_speed = PCIE_SPEED_2_5GT;
                break;
        case 0x02:
                bus->max_bus_speed = PCIE_SPEED_5_0GT;
                break;
+       case 0x04:
+               bus->max_bus_speed = PCIE_SPEED_8_0GT;
+               break;
        default:
                bus->max_bus_speed = PCI_SPEED_UNKNOWN;
                break;
        }
 
-       switch (be32_to_cpup(pcie_link_speed_stats)) {
+       switch (pcie_link_speed_stats[1]) {
        case 0x01:
                bus->cur_bus_speed = PCIE_SPEED_2_5GT;
                break;
        case 0x02:
                bus->cur_bus_speed = PCIE_SPEED_5_0GT;
                break;
+       case 0x04:
+               bus->cur_bus_speed = PCIE_SPEED_8_0GT;
+               break;
        default:
                bus->cur_bus_speed = PCI_SPEED_UNKNOWN;
                break;
index 8e639d7cbda72e057ab535083e29ef03f8d7f369..972df0ffd4dcc4dff154fe84ada40705b173b9f7 100644 (file)
@@ -430,8 +430,7 @@ static void pSeries_machine_kexec(struct kimage *image)
 {
        long rc;
 
-       if (firmware_has_feature(FW_FEATURE_SET_MODE) &&
-           (image->type != KEXEC_TYPE_CRASH)) {
+       if (firmware_has_feature(FW_FEATURE_SET_MODE)) {
                rc = pSeries_disable_reloc_on_exc();
                if (rc != H_SUCCESS)
                        pr_warning("Warning: Failed to disable relocation on "
index 0e166ed4cd16b7452f2656501de27c4f085e02da..8209744b28290b8a2466cf2a8600f0f34d920708 100644 (file)
@@ -886,25 +886,25 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
 
        /* Default: read HW settings */
        if (flow_type == IRQ_TYPE_DEFAULT) {
-               switch(vold & (MPIC_INFO(VECPRI_POLARITY_MASK) |
-                              MPIC_INFO(VECPRI_SENSE_MASK))) {
-                       case MPIC_INFO(VECPRI_SENSE_EDGE) |
-                            MPIC_INFO(VECPRI_POLARITY_POSITIVE):
-                               flow_type = IRQ_TYPE_EDGE_RISING;
-                               break;
-                       case MPIC_INFO(VECPRI_SENSE_EDGE) |
-                            MPIC_INFO(VECPRI_POLARITY_NEGATIVE):
-                               flow_type = IRQ_TYPE_EDGE_FALLING;
-                               break;
-                       case MPIC_INFO(VECPRI_SENSE_LEVEL) |
-                            MPIC_INFO(VECPRI_POLARITY_POSITIVE):
-                               flow_type = IRQ_TYPE_LEVEL_HIGH;
-                               break;
-                       case MPIC_INFO(VECPRI_SENSE_LEVEL) |
-                            MPIC_INFO(VECPRI_POLARITY_NEGATIVE):
-                               flow_type = IRQ_TYPE_LEVEL_LOW;
-                               break;
-               }
+               int vold_ps;
+
+               vold_ps = vold & (MPIC_INFO(VECPRI_POLARITY_MASK) |
+                                 MPIC_INFO(VECPRI_SENSE_MASK));
+
+               if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) |
+                               MPIC_INFO(VECPRI_POLARITY_POSITIVE)))
+                       flow_type = IRQ_TYPE_EDGE_RISING;
+               else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_EDGE) |
+                                    MPIC_INFO(VECPRI_POLARITY_NEGATIVE)))
+                       flow_type = IRQ_TYPE_EDGE_FALLING;
+               else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) |
+                                    MPIC_INFO(VECPRI_POLARITY_POSITIVE)))
+                       flow_type = IRQ_TYPE_LEVEL_HIGH;
+               else if (vold_ps == (MPIC_INFO(VECPRI_SENSE_LEVEL) |
+                                    MPIC_INFO(VECPRI_POLARITY_NEGATIVE)))
+                       flow_type = IRQ_TYPE_LEVEL_LOW;
+               else
+                       WARN_ONCE(1, "mpic: unknown IRQ type %d\n", vold);
        }
 
        /* Apply to irq desc */
index a90731b3d44a3ea41052690975aefcd8b3ce2db7..b07909850f77151b393f73a30bac727a79ea9921 100644 (file)
@@ -309,16 +309,23 @@ static void get_output_lock(void)
 
        if (xmon_speaker == me)
                return;
+
        for (;;) {
-               if (xmon_speaker == 0) {
-                       last_speaker = cmpxchg(&xmon_speaker, 0, me);
-                       if (last_speaker == 0)
-                               return;
-               }
-               timeout = 10000000;
+               last_speaker = cmpxchg(&xmon_speaker, 0, me);
+               if (last_speaker == 0)
+                       return;
+
+               /*
+                * Wait a full second for the lock, we might be on a slow
+                * console, but check every 100us.
+                */
+               timeout = 10000;
                while (xmon_speaker == last_speaker) {
-                       if (--timeout > 0)
+                       if (--timeout > 0) {
+                               udelay(100);
                                continue;
+                       }
+
                        /* hostile takeover */
                        prev = cmpxchg(&xmon_speaker, last_speaker, me);
                        if (prev == last_speaker)
@@ -397,7 +404,6 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
        }
 
        xmon_fault_jmp[cpu] = recurse_jmp;
-       cpumask_set_cpu(cpu, &cpus_in_xmon);
 
        bp = NULL;
        if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
@@ -419,6 +425,8 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
                release_output_lock();
        }
 
+       cpumask_set_cpu(cpu, &cpus_in_xmon);
+
  waiting:
        secondary = 1;
        while (secondary && !xmon_gate) {
index 4c4a1cef52087bf359c28d9077e315196f7630eb..47c8630c93cdd6c6a3f55d78798c32f7defa9f03 100644 (file)
@@ -529,6 +529,7 @@ static int __init appldata_init(void)
 {
        int rc;
 
+       init_virt_timer(&appldata_timer);
        appldata_timer.function = appldata_timer_function;
        appldata_timer.data = (unsigned long) &appldata_work;
 
index 59c8efce1b99b52964950f0933b4934a12b6a9db..0248949a756d7765d11a1d39f1568d37e3934406 100644 (file)
@@ -1421,5 +1421,5 @@ ENTRY(sys_sched_setattr_wrapper)
 ENTRY(sys_sched_getattr_wrapper)
        lgfr    %r2,%r2                 # pid_t
        llgtr   %r3,%r3                 # const char __user *
-       llgfr   %r3,%r3                 # unsigned int
+       llgfr   %r4,%r4                 # unsigned int
        jg      sys_sched_getattr
index b9e25ae2579c9f04c3d4bb422cab012c943dda58..d7c00507568a73e8f5acb45014f366154f839980 100644 (file)
@@ -59,7 +59,7 @@ ENTRY(startup_continue)
        .quad   0                       # cr12: tracing off
        .quad   0                       # cr13: home space segment table
        .quad   0xc0000000              # cr14: machine check handling off
-       .quad   0                       # cr15: linkage stack operations
+       .quad   .Llinkage_stack         # cr15: linkage stack operations
 .Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
 .Lscan2g:.quad 0x80000000 + 0x20000 - 8        # 2GB + 128K - 8
@@ -67,12 +67,15 @@ ENTRY(startup_continue)
 .Lparmaddr:
        .quad   PARMAREA
        .align  64
-.Lduct: .long  0,0,0,0,.Lduald,0,0,0
+.Lduct: .long  0,.Laste,.Laste,0,.Lduald,0,0,0
        .long   0,0,0,0,0,0,0,0
+.Laste:        .quad   0,0xffffffffffffffff,0,0,0,0,0,0
        .align  128
 .Lduald:.rept  8
        .long   0x80000000,0,0,0        # invalid access-list entries
        .endr
+.Llinkage_stack:
+       .long   0,0,0x89000000,0,0,0,0x8a000000,0
 
 ENTRY(_ehead)
 
index a90d45e9dfb0cbb7b1dce5fb8441a249dc0556c3..27c50f4d90cb32ce97db6004ce450096b807655c 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/mm.h>
 #include <linux/gfp.h>
 #include <linux/init.h>
+#include <asm/setup.h>
+#include <asm/ipl.h>
 
 #define ESSA_SET_STABLE                1
 #define ESSA_SET_UNUSED                2
@@ -41,6 +43,14 @@ void __init cmma_init(void)
 
        if (!cmma_flag)
                return;
+       /*
+        * Disable CMM for dump, otherwise  the tprot based memory
+        * detection can fail because of unstable pages.
+        */
+       if (OLDMEM_BASE || ipl_info.type == IPL_TYPE_FCP_DUMP) {
+               cmma_flag = 0;
+               return;
+       }
        asm volatile(
                "       .insn rrf,0xb9ab0000,%1,%1,0,0\n"
                "0:     la      %0,0\n"
index 708d60e4006676486b3892195b165ede007d2544..9c36dc398f9070afb4d6151d214623d1cbcf9f4a 100644 (file)
@@ -737,10 +737,10 @@ call_fn:  /* lg %r1,<d(function)>(%r13) */
                /* icm  %r5,3,<d(type)>(%r1) */
                EMIT4_DISP(0xbf531000, offsetof(struct net_device, type));
                break;
-       case BPF_S_ANC_RXHASH: /* A = skb->rxhash */
-               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
-               /* l %r5,<d(rxhash)>(%r2) */
-               EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
+       case BPF_S_ANC_RXHASH: /* A = skb->hash */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+               /* l %r5,<d(hash)>(%r2) */
+               EMIT4_DISP(0x58502000, offsetof(struct sk_buff, hash));
                break;
        case BPF_S_ANC_VLAN_TAG:
        case BPF_S_ANC_VLAN_TAG_PRESENT:
@@ -877,6 +877,7 @@ void bpf_jit_compile(struct sk_filter *fp)
        if (jit.start) {
                set_memory_ro((unsigned long)header, header->pages);
                fp->bpf_func = (void *) jit.start;
+               fp->jited = 1;
        }
 out:
        kfree(addrs);
@@ -887,10 +888,12 @@ void bpf_jit_free(struct sk_filter *fp)
        unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
        struct bpf_binary_header *header = (void *)addr;
 
-       if (fp->bpf_func == sk_run_filter)
+       if (!fp->jited)
                goto free_filter;
+
        set_memory_rw(addr, header->pages);
        module_free(NULL, header);
+
 free_filter:
        kfree(fp);
 }
index 60c11a629d96d0220d6b01cf1e1425d41c0ffaab..f91c03119804751894c39433eb52da1844dbcf3b 100644 (file)
@@ -206,11 +206,13 @@ static void dma_cleanup_tables(struct zpci_dev *zdev)
        zdev->dma_table = NULL;
 }
 
-static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, unsigned long start,
-                                  int size)
+static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev,
+                                      unsigned long start, int size)
 {
-       unsigned long boundary_size = 0x1000000;
+       unsigned long boundary_size;
 
+       boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1,
+                             PAGE_SIZE) >> PAGE_SHIFT;
        return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages,
                                start, size, 0, boundary_size, 0);
 }
index 673515bc413559a24600f988baeb91e8a6b9b1d4..aa1b2b9088a77b061758f48f4a434185e760d6ca 100644 (file)
@@ -18,7 +18,7 @@
 #define SH_CACHE_ASSOC         8
 
 #if defined(CONFIG_CPU_SUBTYPE_SH7619)
-#define CCR            0xffffffec
+#define SH_CCR         0xffffffec
 
 #define CCR_CACHE_CE   0x01    /* Cache enable */
 #define CCR_CACHE_WT   0x02    /* CCR[bit1=1,bit2=1] */
index defb0baa5a0682b95222bccc60440ee760bd6680..b27ce92cb600bc17c47dacda12d0e3dc9f8d06a1 100644 (file)
@@ -17,8 +17,8 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xfffc1000 /* CCR1 */
-#define CCR2           0xfffc1004
+#define SH_CCR         0xfffc1000 /* CCR1 */
+#define SH_CCR2                0xfffc1004
 
 /*
  * Most of the SH-2A CCR1 definitions resemble the SH-4 ones. All others not
index bee2d81c56bfbde6392866f1d4bb05b58d1aa4b8..29700fd88c75d30be16340966c3013f1c880f076 100644 (file)
@@ -17,7 +17,7 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xffffffec      /* Address of Cache Control Register */
+#define SH_CCR         0xffffffec      /* Address of Cache Control Register */
 
 #define CCR_CACHE_CE   0x01    /* Cache Enable */
 #define CCR_CACHE_WT   0x02    /* Write-Through (for P0,U0,P3) (else writeback) */
index 7bfb9e8b069c22d789318085e866440502f0c755..92c4cd119b662f99dc4ed9d0f5d1b54dea3001a9 100644 (file)
@@ -17,7 +17,7 @@
 #define SH_CACHE_COMBINED      4
 #define SH_CACHE_ASSOC         8
 
-#define CCR            0xff00001c      /* Address of Cache Control Register */
+#define SH_CCR         0xff00001c      /* Address of Cache Control Register */
 #define CCR_CACHE_OCE  0x0001  /* Operand Cache Enable */
 #define CCR_CACHE_WT   0x0002  /* Write-Through (for P0,U0,P3) (else writeback)*/
 #define CCR_CACHE_CB   0x0004  /* Copy-Back (for P1) (else writethrough) */
index ecf83cd158dc38fefb91f2fa83cdb452cfa5c6bf..0d7360d549c17858c59f93b6dc0d279f4222a640 100644 (file)
@@ -112,7 +112,7 @@ static void cache_init(void)
        unsigned long ccr, flags;
 
        jump_to_uncached();
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
 
        /*
         * At this point we don't know whether the cache is enabled or not - a
@@ -189,7 +189,7 @@ static void cache_init(void)
 
        l2_cache_init();
 
-       __raw_writel(flags, CCR);
+       __raw_writel(flags, SH_CCR);
        back_to_cached();
 }
 #else
index 115725198038da862a19ef634a0ec38adf23b76f..777e50f33c00f3f96fe4b34f7723132507b13935 100644 (file)
@@ -36,7 +36,7 @@ static int cache_seq_show(struct seq_file *file, void *iter)
         */
        jump_to_uncached();
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        if ((ccr & CCR_CACHE_ENABLE) == 0) {
                back_to_cached();
 
index defcf719f2e84eb5cae2b6be57fed58227eeb6ec..a74259f2f9815e93d499634b67d9756472662e76 100644 (file)
@@ -63,9 +63,9 @@ static void sh2__flush_invalidate_region(void *start, int size)
        local_irq_save(flags);
        jump_to_uncached();
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        ccr |= CCR_CACHE_INVALIDATE;
-       __raw_writel(ccr, CCR);
+       __raw_writel(ccr, SH_CCR);
 
        back_to_cached();
        local_irq_restore(flags);
index 949e2d3138a0ca24ffe07e6228a68eeeb72321e9..ee87d081259b86950d527151618a3e52814ade5a 100644 (file)
@@ -134,7 +134,8 @@ static void sh2a__flush_invalidate_region(void *start, int size)
 
        /* If there are too many pages then just blow the cache */
        if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) {
-               __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
+               __raw_writel(__raw_readl(SH_CCR) | CCR_OCACHE_INVALIDATE,
+                            SH_CCR);
        } else {
                for (v = begin; v < end; v += L1_CACHE_BYTES)
                        sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v);
@@ -167,7 +168,8 @@ static void sh2a_flush_icache_range(void *args)
        /* I-Cache invalidate */
        /* If there are too many pages then just blow the cache */
        if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) {
-               __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR);
+               __raw_writel(__raw_readl(SH_CCR) | CCR_ICACHE_INVALIDATE,
+                            SH_CCR);
        } else {
                for (v = start; v < end; v += L1_CACHE_BYTES)
                        sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v);
index 0e529285b28d42c688fb0901349ba70218385d51..51d8f7f31d1d797392ab2813f4fb3d4d33480598 100644 (file)
@@ -133,9 +133,9 @@ static void flush_icache_all(void)
        jump_to_uncached();
 
        /* Flush I-cache */
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
        ccr |= CCR_CACHE_ICI;
-       __raw_writel(ccr, CCR);
+       __raw_writel(ccr, SH_CCR);
 
        /*
         * back_to_cached() will take care of the barrier for us, don't add
index c0adbee97b5f29a2cdb33f6124c1d62ee821ebec..24c58b7dc02265c795000fa997ac96da59207175 100644 (file)
@@ -19,7 +19,7 @@ void __init shx3_cache_init(void)
 {
        unsigned int ccr;
 
-       ccr = __raw_readl(CCR);
+       ccr = __raw_readl(SH_CCR);
 
        /*
         * If we've got cache aliases, resolve them in hardware.
@@ -40,5 +40,5 @@ void __init shx3_cache_init(void)
        ccr |= CCR_CACHE_IBE;
 #endif
 
-       writel_uncached(ccr, CCR);
+       writel_uncached(ccr, SH_CCR);
 }
index 616966a96cba61d6a680d4bc57cf71150a04fb3e..097c2cdd117f53c543fb919ba6740210b1471a4a 100644 (file)
@@ -285,8 +285,8 @@ void __init cpu_cache_init(void)
 {
        unsigned int cache_disabled = 0;
 
-#ifdef CCR
-       cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE);
+#ifdef SH_CCR
+       cache_disabled = !(__raw_readl(SH_CCR) & CCR_CACHE_ENABLE);
 #endif
 
        compute_alias(&boot_cpu_data.icache);
index c51efdcd07a2d09e76c06e31671efcd19a6db4ed..7d8b7e94b93b6fb8e9795f49368c056053597bec 100644 (file)
@@ -27,7 +27,7 @@ config SPARC
        select RTC_DRV_M48T59
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
-       select HAVE_ARCH_JUMP_LABEL
+       select HAVE_ARCH_JUMP_LABEL if SPARC64
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_PCI_IOMAP
index 32a280ec38c1d6edef71b5576ce474221726ec1e..d7b4967f8fa6209307854c367347f88d14103839 100644 (file)
@@ -58,9 +58,12 @@ void arch_cpu_idle(void)
 {
        if (tlb_type != hypervisor) {
                touch_nmi_watchdog();
+               local_irq_enable();
        } else {
                unsigned long pstate;
 
+               local_irq_enable();
+
                 /* The sun4v sleeping code requires that we have PSTATE.IE cleared over
                  * the cpu sleep hypervisor call.
                  */
@@ -82,7 +85,6 @@ void arch_cpu_idle(void)
                        : "=&r" (pstate)
                        : "i" (PSTATE_IE));
        }
-       local_irq_enable();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
index 87729fff13b96729cd6cadcc3825dba172ab1d7c..33a17e7b3ccd0fad8477d4c5b051cca1b24f248a 100644 (file)
@@ -189,7 +189,8 @@ linux_sparc_syscall32:
         mov    %i0, %l5                                ! IEU1
 5:     call    %l7                                     ! CTI   Group brk forced
         srl    %i5, 0, %o5                             ! IEU1
-       ba,a,pt %xcc, 3f
+       ba,pt   %xcc, 3f
+        sra    %o0, 0, %o0
 
        /* Linux native system calls enter here... */
        .align  32
@@ -217,7 +218,6 @@ linux_sparc_syscall:
 3:     stx     %o0, [%sp + PTREGS_OFF + PT_V9_I0]
 ret_sys_call:
        ldx     [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
-       sra     %o0, 0, %o0
        mov     %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
        sllx    %g2, 32, %g2
 
index 869023abe5a4440c3ec08777e987c7abcc9777b8..cfbe53c17b0dbb61b25f8ae48c0f3017f307cc6f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/pagemap.h>
 #include <linux/vmalloc.h>
 #include <linux/kdebug.h>
+#include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/log2.h>
@@ -62,6 +63,7 @@ extern unsigned long last_valid_pfn;
 static pgd_t *srmmu_swapper_pg_dir;
 
 const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops;
+EXPORT_SYMBOL(sparc32_cachetlb_ops);
 
 #ifdef CONFIG_SMP
 const struct sparc32_cachetlb_ops *local_ops;
index 3b3a360b429a8ac78b5089a98c09027aa40634a3..f5d506fdddad3dea459aa97308e9a8872f34ffe8 100644 (file)
@@ -273,7 +273,7 @@ void __init pgtable_cache_init(void)
                prom_halt();
        }
 
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < ARRAY_SIZE(tsb_cache_names); i++) {
                unsigned long size = 8192 << i;
                const char *name = tsb_cache_names[i];
 
index 01fe9946d388de469e140532b3f973f8a6db28fb..a82c6b2a9780cab8d882c2d13429f4889375229e 100644 (file)
@@ -618,7 +618,7 @@ void bpf_jit_compile(struct sk_filter *fp)
                                emit_load16(r_A, struct net_device, type, r_A);
                                break;
                        case BPF_S_ANC_RXHASH:
-                               emit_skb_load32(rxhash, r_A);
+                               emit_skb_load32(hash, r_A);
                                break;
                        case BPF_S_ANC_VLAN_TAG:
                        case BPF_S_ANC_VLAN_TAG_PRESENT:
@@ -809,6 +809,7 @@ cond_branch:                        f_offset = addrs[i + filter[i].jf];
        if (image) {
                bpf_flush_icache(image, image + proglen);
                fp->bpf_func = (void *)image;
+               fp->jited = 1;
        }
 out:
        kfree(addrs);
@@ -817,7 +818,7 @@ out:
 
 void bpf_jit_free(struct sk_filter *fp)
 {
-       if (fp->bpf_func != sk_run_filter)
+       if (fp->jited)
                module_free(NULL, fp->bpf_func);
        kfree(fp);
 }
index 39f186252e02521ccc33eb0fad6b450ccfb19d73..7d26d9c0b2fb85cd96ca25953f2bb84d4022be9d 100644 (file)
@@ -240,7 +240,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
index c026cca5602c6fe5c84619f0b43b2fe7c3bb2382..f3aaf231b4e590fad07b58b51583eb6693a924cd 100644 (file)
@@ -341,10 +341,6 @@ config X86_USE_3DNOW
        def_bool y
        depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
 
-config X86_OOSTORE
-       def_bool y
-       depends on (MWINCHIP3D || MWINCHIPC6) && MTRR
-
 #
 # P6_NOPs are a relatively minor optimization that require a family >=
 # 6 processor, except that it is broken on certain VIA chips.
index 90a21f430117d1690f847c8b198e80d6afb3c825..4dbf967da50daab8c7ed9f3952fa08b18b5b6271 100644 (file)
@@ -111,7 +111,7 @@ struct mem_vector {
 };
 
 #define MEM_AVOID_MAX 5
-struct mem_vector mem_avoid[MEM_AVOID_MAX];
+static struct mem_vector mem_avoid[MEM_AVOID_MAX];
 
 static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
 {
@@ -180,7 +180,7 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
 }
 
 /* Does this memory vector overlap a known avoided area? */
-bool mem_avoid_overlap(struct mem_vector *img)
+static bool mem_avoid_overlap(struct mem_vector *img)
 {
        int i;
 
@@ -192,8 +192,9 @@ bool mem_avoid_overlap(struct mem_vector *img)
        return false;
 }
 
-unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET / CONFIG_PHYSICAL_ALIGN];
-unsigned long slot_max = 0;
+static unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
+                          CONFIG_PHYSICAL_ALIGN];
+static unsigned long slot_max;
 
 static void slots_append(unsigned long addr)
 {
index 04a48903b2eb31973080d60d36cfd93b3fc68a5f..69bbb484502089b6a01d93d58e4c16a3f90e14f9 100644 (file)
 #else
 # define smp_rmb()     barrier()
 #endif
-#ifdef CONFIG_X86_OOSTORE
-# define smp_wmb()     wmb()
-#else
-# define smp_wmb()     barrier()
-#endif
+#define smp_wmb()      barrier()
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
 #else /* !SMP */
 #define set_mb(var, value) do { var = value; barrier(); } while (0)
 #endif /* SMP */
 
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
 
 /*
  * For either of these options x86 doesn't have a strong TSO memory
index 3b978c472d08b51aa8ff33d7fab589a3205fc87a..acd86c850414e7f3adfffe860ffd22bd17e0d459 100644 (file)
@@ -132,6 +132,9 @@ extern void __init efi_map_region_fixed(efi_memory_desc_t *md);
 extern void efi_sync_low_kernel_mappings(void);
 extern void efi_setup_page_tables(void);
 extern void __init old_map_region(efi_memory_desc_t *md);
+extern void __init runtime_code_page_mkexec(void);
+extern void __init efi_runtime_mkexec(void);
+extern void __init efi_apply_memmap_quirks(void);
 
 struct efi_setup_data {
        u64 fw_vendor;
index 34f69cb9350ae3ecf36e4b8cd8d410a6a7b67a0b..91d9c69a629e2731f25aa152de91dd17663ec619 100644 (file)
@@ -237,7 +237,7 @@ memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
 
 static inline void flush_write_buffers(void)
 {
-#if defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE)
+#if defined(CONFIG_X86_PPRO_FENCE)
        asm volatile("lock; addl $0,0(%%esp)": : :"memory");
 #endif
 }
index bf156ded74b56006a76cc02b8917984117af8afd..0f62f5482d91ec8fca86e884b6822fc467239dbc 100644 (file)
 # define LOCK_PTR_REG "D"
 #endif
 
-#if defined(CONFIG_X86_32) && \
-       (defined(CONFIG_X86_OOSTORE) || defined(CONFIG_X86_PPRO_FENCE))
+#if defined(CONFIG_X86_32) && (defined(CONFIG_X86_PPRO_FENCE))
 /*
- * On PPro SMP or if we are using OOSTORE, we use a locked operation to unlock
+ * On PPro SMP, we use a locked operation to unlock
  * (PPro errata 66, 92)
  */
 # define UNLOCK_LOCK_PREFIX LOCK_PREFIX
index d35f24e231cd2429c8d17c0d5b3d722951d3e04b..1306d117967daa60b2947c30b1fd682255641a51 100644 (file)
@@ -119,9 +119,10 @@ static inline void setup_node_to_cpumask_map(void) { }
 
 extern const struct cpumask *cpu_coregroup_mask(int cpu);
 
-#ifdef ENABLE_TOPO_DEFINES
 #define topology_physical_package_id(cpu)      (cpu_data(cpu).phys_proc_id)
 #define topology_core_id(cpu)                  (cpu_data(cpu).cpu_core_id)
+
+#ifdef ENABLE_TOPO_DEFINES
 #define topology_core_cpumask(cpu)             (per_cpu(cpu_core_map, cpu))
 #define topology_thread_cpumask(cpu)           (per_cpu(cpu_sibling_map, cpu))
 #endif
index 57ae63cd6ee2ec8aba5135a33e363267b65e4075..94605c0e9ceebc0058b18b995a5ac4f73a0d2aa6 100644 (file)
@@ -66,6 +66,6 @@ extern void tsc_save_sched_clock_state(void);
 extern void tsc_restore_sched_clock_state(void);
 
 /* MSR based TSC calibration for Intel Atom SoC platforms */
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate);
+unsigned long try_msr_calibrate_tsc(void);
 
 #endif /* _ASM_X86_TSC_H */
index fd972a3e4cbb0919221f6f69299a857972ef44e6..9fa8aa051f54b235ed516d32e2eca2c3c9d62b5e 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
 #include <linux/bitops.h>
-#include <linux/ioport.h>
 #include <linux/suspend.h>
 #include <asm/e820.h>
 #include <asm/io.h>
@@ -54,18 +53,6 @@ int fallback_aper_force __initdata;
 
 int fix_aperture __initdata = 1;
 
-static struct resource gart_resource = {
-       .name   = "GART",
-       .flags  = IORESOURCE_MEM,
-};
-
-static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
-{
-       gart_resource.start = aper_base;
-       gart_resource.end = aper_base + aper_size - 1;
-       insert_resource(&iomem_resource, &gart_resource);
-}
-
 /* This code runs before the PCI subsystem is initialized, so just
    access the northbridge directly. */
 
@@ -96,7 +83,6 @@ static u32 __init allocate_aperture(void)
        memblock_reserve(addr, aper_size);
        printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n",
                        aper_size >> 10, addr);
-       insert_aperture_resource((u32)addr, aper_size);
        register_nosave_region(addr >> PAGE_SHIFT,
                               (addr+aper_size) >> PAGE_SHIFT);
 
@@ -444,12 +430,8 @@ int __init gart_iommu_hole_init(void)
 
 out:
        if (!fix && !fallback_aper_force) {
-               if (last_aper_base) {
-                       unsigned long n = (32 * 1024 * 1024) << last_aper_order;
-
-                       insert_aperture_resource((u32)last_aper_base, n);
+               if (last_aper_base)
                        return 1;
-               }
                return 0;
        }
 
index 8779edab684efdcd04fd93d22d79d4633c6fd4f9..d8fba5c15fbd8882f317daa2779c39ff4429b0d4 100644 (file)
@@ -8,236 +8,6 @@
 
 #include "cpu.h"
 
-#ifdef CONFIG_X86_OOSTORE
-
-static u32 power2(u32 x)
-{
-       u32 s = 1;
-
-       while (s <= x)
-               s <<= 1;
-
-       return s >>= 1;
-}
-
-
-/*
- * Set up an actual MCR
- */
-static void centaur_mcr_insert(int reg, u32 base, u32 size, int key)
-{
-       u32 lo, hi;
-
-       hi = base & ~0xFFF;
-       lo = ~(size-1);         /* Size is a power of 2 so this makes a mask */
-       lo &= ~0xFFF;           /* Remove the ctrl value bits */
-       lo |= key;              /* Attribute we wish to set */
-       wrmsr(reg+MSR_IDT_MCR0, lo, hi);
-       mtrr_centaur_report_mcr(reg, lo, hi);   /* Tell the mtrr driver */
-}
-
-/*
- * Figure what we can cover with MCR's
- *
- * Shortcut: We know you can't put 4Gig of RAM on a winchip
- */
-static u32 ramtop(void)
-{
-       u32 clip = 0xFFFFFFFFUL;
-       u32 top = 0;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               unsigned long start, end;
-
-               if (e820.map[i].addr > 0xFFFFFFFFUL)
-                       continue;
-               /*
-                * Don't MCR over reserved space. Ignore the ISA hole
-                * we frob around that catastrophe already
-                */
-               if (e820.map[i].type == E820_RESERVED) {
-                       if (e820.map[i].addr >= 0x100000UL &&
-                           e820.map[i].addr < clip)
-                               clip = e820.map[i].addr;
-                       continue;
-               }
-               start = e820.map[i].addr;
-               end = e820.map[i].addr + e820.map[i].size;
-               if (start >= end)
-                       continue;
-               if (end > top)
-                       top = end;
-       }
-       /*
-        * Everything below 'top' should be RAM except for the ISA hole.
-        * Because of the limited MCR's we want to map NV/ACPI into our
-        * MCR range for gunk in RAM
-        *
-        * Clip might cause us to MCR insufficient RAM but that is an
-        * acceptable failure mode and should only bite obscure boxes with
-        * a VESA hole at 15Mb
-        *
-        * The second case Clip sometimes kicks in is when the EBDA is marked
-        * as reserved. Again we fail safe with reasonable results
-        */
-       if (top > clip)
-               top = clip;
-
-       return top;
-}
-
-/*
- * Compute a set of MCR's to give maximum coverage
- */
-static int centaur_mcr_compute(int nr, int key)
-{
-       u32 mem = ramtop();
-       u32 root = power2(mem);
-       u32 base = root;
-       u32 top = root;
-       u32 floor = 0;
-       int ct = 0;
-
-       while (ct < nr) {
-               u32 fspace = 0;
-               u32 high;
-               u32 low;
-
-               /*
-                * Find the largest block we will fill going upwards
-                */
-               high = power2(mem-top);
-
-               /*
-                * Find the largest block we will fill going downwards
-                */
-               low = base/2;
-
-               /*
-                * Don't fill below 1Mb going downwards as there
-                * is an ISA hole in the way.
-                */
-               if (base <= 1024*1024)
-                       low = 0;
-
-               /*
-                * See how much space we could cover by filling below
-                * the ISA hole
-                */
-
-               if (floor == 0)
-                       fspace = 512*1024;
-               else if (floor == 512*1024)
-                       fspace = 128*1024;
-
-               /* And forget ROM space */
-
-               /*
-                * Now install the largest coverage we get
-                */
-               if (fspace > high && fspace > low) {
-                       centaur_mcr_insert(ct, floor, fspace, key);
-                       floor += fspace;
-               } else if (high > low) {
-                       centaur_mcr_insert(ct, top, high, key);
-                       top += high;
-               } else if (low > 0) {
-                       base -= low;
-                       centaur_mcr_insert(ct, base, low, key);
-               } else
-                       break;
-               ct++;
-       }
-       /*
-        * We loaded ct values. We now need to set the mask. The caller
-        * must do this bit.
-        */
-       return ct;
-}
-
-static void centaur_create_optimal_mcr(void)
-{
-       int used;
-       int i;
-
-       /*
-        * Allocate up to 6 mcrs to mark as much of ram as possible
-        * as write combining and weak write ordered.
-        *
-        * To experiment with: Linux never uses stack operations for
-        * mmio spaces so we could globally enable stack operation wc
-        *
-        * Load the registers with type 31 - full write combining, all
-        * writes weakly ordered.
-        */
-       used = centaur_mcr_compute(6, 31);
-
-       /*
-        * Wipe unused MCRs
-        */
-       for (i = used; i < 8; i++)
-               wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-static void winchip2_create_optimal_mcr(void)
-{
-       u32 lo, hi;
-       int used;
-       int i;
-
-       /*
-        * Allocate up to 6 mcrs to mark as much of ram as possible
-        * as write combining, weak store ordered.
-        *
-        * Load the registers with type 25
-        *      8       -       weak write ordering
-        *      16      -       weak read ordering
-        *      1       -       write combining
-        */
-       used = centaur_mcr_compute(6, 25);
-
-       /*
-        * Mark the registers we are using.
-        */
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       for (i = 0; i < used; i++)
-               lo |= 1<<(9+i);
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-
-       /*
-        * Wipe unused MCRs
-        */
-
-       for (i = used; i < 8; i++)
-               wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-/*
- * Handle the MCR key on the Winchip 2.
- */
-static void winchip2_unprotect_mcr(void)
-{
-       u32 lo, hi;
-       u32 key;
-
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       lo &= ~0x1C0;   /* blank bits 8-6 */
-       key = (lo>>17) & 7;
-       lo |= key<<6;   /* replace with unlock key */
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-static void winchip2_protect_mcr(void)
-{
-       u32 lo, hi;
-
-       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-       lo &= ~0x1C0;   /* blank bits 8-6 */
-       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-#endif /* CONFIG_X86_OOSTORE */
-
 #define ACE_PRESENT    (1 << 6)
 #define ACE_ENABLED    (1 << 7)
 #define ACE_FCR                (1 << 28)       /* MSR_VIA_FCR */
@@ -362,20 +132,6 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        fcr_clr = DPDC;
                        printk(KERN_NOTICE "Disabling bugged TSC.\n");
                        clear_cpu_cap(c, X86_FEATURE_TSC);
-#ifdef CONFIG_X86_OOSTORE
-                       centaur_create_optimal_mcr();
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        *
-                        * The C6 original lacks weak read order
-                        *
-                        * Note 0x120 is write only on Winchip 1
-                        */
-                       wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
-#endif
                        break;
                case 8:
                        switch (c->x86_mask) {
@@ -392,40 +148,12 @@ static void init_centaur(struct cpuinfo_x86 *c)
                        fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
                                  E2MMX|EAMD3D;
                        fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
-                       winchip2_unprotect_mcr();
-                       winchip2_create_optimal_mcr();
-                       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        */
-                       lo |= 31;
-                       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       winchip2_protect_mcr();
-#endif
                        break;
                case 9:
                        name = "3";
                        fcr_set = ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|
                                  E2MMX|EAMD3D;
                        fcr_clr = DPDC;
-#ifdef CONFIG_X86_OOSTORE
-                       winchip2_unprotect_mcr();
-                       winchip2_create_optimal_mcr();
-                       rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       /*
-                        * Enable:
-                        *      write combining on non-stack, non-string
-                        *      write combining on string, all types
-                        *      weak write ordering
-                        */
-                       lo |= 31;
-                       wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-                       winchip2_protect_mcr();
-#endif
                        break;
                default:
                        name = "??";
index 24b6fd10625a5a95aeb0331da66cea8c148a08c9..8e28bf2fc3ef4a15bf672dee29bc6729552556f2 100644 (file)
@@ -284,8 +284,13 @@ static __always_inline void setup_smap(struct cpuinfo_x86 *c)
        raw_local_save_flags(eflags);
        BUG_ON(eflags & X86_EFLAGS_AC);
 
-       if (cpu_has(c, X86_FEATURE_SMAP))
+       if (cpu_has(c, X86_FEATURE_SMAP)) {
+#ifdef CONFIG_X86_SMAP
                set_in_cr4(X86_CR4_SMAP);
+#else
+               clear_in_cr4(X86_CR4_SMAP);
+#endif
+       }
 }
 
 /*
index b88645191fe559b89b8d330c984865d07dbae21b..79f9f848bee4b1c021b80bed07e0dcbcec88a20b 100644 (file)
@@ -1192,6 +1192,9 @@ static void x86_pmu_del(struct perf_event *event, int flags)
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event_list[i]) {
 
+                       if (i >= cpuc->n_events - cpuc->n_added)
+                               --cpuc->n_added;
+
                        if (x86_pmu.put_event_constraints)
                                x86_pmu.put_event_constraints(cpuc, event);
 
@@ -1521,6 +1524,8 @@ static int __init init_hw_perf_events(void)
 
        pr_cont("%s PMU driver.\n", x86_pmu.name);
 
+       x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
+
        for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next)
                quirk->func();
 
@@ -1534,7 +1539,6 @@ static int __init init_hw_perf_events(void)
                __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1,
                                   0, x86_pmu.num_counters, 0, 0);
 
-       x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */
        x86_pmu_format_group.attrs = x86_pmu.format_attrs;
 
        if (x86_pmu.event_attrs)
@@ -1820,9 +1824,12 @@ static ssize_t set_attr_rdpmc(struct device *cdev,
        if (ret)
                return ret;
 
+       if (x86_pmu.attr_rdpmc_broken)
+               return -ENOTSUPP;
+
        if (!!val != !!x86_pmu.attr_rdpmc) {
                x86_pmu.attr_rdpmc = !!val;
-               smp_call_function(change_rdpmc, (void *)val, 1);
+               on_each_cpu(change_rdpmc, (void *)val, 1);
        }
 
        return count;
index c1a861829d817a2749372060df21c6d689294fff..4972c244d0bc2fbe445706943e0248073fd17a26 100644 (file)
@@ -409,6 +409,7 @@ struct x86_pmu {
        /*
         * sysfs attrs
         */
+       int             attr_rdpmc_broken;
        int             attr_rdpmc;
        struct attribute **format_attrs;
        struct attribute **event_attrs;
index 0fa4f242f0504ad53297360966e957b84a0edab8..aa333d9668866f808955209f8cd71737d447eafc 100644 (file)
@@ -1361,10 +1361,8 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
        intel_pmu_disable_all();
        handled = intel_pmu_drain_bts_buffer();
        status = intel_pmu_get_status();
-       if (!status) {
-               intel_pmu_enable_all(0);
-               return handled;
-       }
+       if (!status)
+               goto done;
 
        loops = 0;
 again:
@@ -2310,10 +2308,7 @@ __init int intel_pmu_init(void)
        if (version > 1)
                x86_pmu.num_counters_fixed = max((int)edx.split.num_counters_fixed, 3);
 
-       /*
-        * v2 and above have a perf capabilities MSR
-        */
-       if (version > 1) {
+       if (boot_cpu_has(X86_FEATURE_PDCM)) {
                u64 capabilities;
 
                rdmsrl(MSR_IA32_PERF_CAPABILITIES, capabilities);
index 29c248799cede4432ac2d57ca8689a215c35d0cc..047f540cf3f71cfe03f69d796a1957b8a58caebc 100644 (file)
@@ -501,8 +501,11 @@ static struct extra_reg snbep_uncore_cbox_extra_regs[] = {
        SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
                                  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0x6),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x8),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x8),
@@ -1178,10 +1181,15 @@ static struct extra_reg ivt_uncore_cbox_extra_regs[] = {
        SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
                                  SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
        SNBEP_CBO_EVENT_EXTRA_REG(0x1031, 0x10ff, 0x2),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x1134, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x5134, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0334, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4334, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0534, 0xffff, 0x4),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4534, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0934, 0xffff, 0x4),
-       SNBEP_CBO_EVENT_EXTRA_REG(0x4134, 0xffff, 0xc),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x4934, 0xffff, 0xc),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0135, 0xffff, 0x10),
        SNBEP_CBO_EVENT_EXTRA_REG(0x0335, 0xffff, 0x10),
        SNBEP_CBO_EVENT_EXTRA_REG(0x2135, 0xffff, 0x10),
@@ -3326,6 +3334,8 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
        if (!pmus)
                return -ENOMEM;
 
+       type->pmus = pmus;
+
        type->unconstrainted = (struct event_constraint)
                __EVENT_CONSTRAINT(0, (1ULL << type->num_counters) - 1,
                                0, type->num_counters, 0, 0);
@@ -3361,7 +3371,6 @@ static int __init uncore_type_init(struct intel_uncore_type *type)
        }
 
        type->pmu_group = &uncore_pmu_attr_group;
-       type->pmus = pmus;
        return 0;
 fail:
        uncore_type_exit(type);
index b1e2fe11532329bb9828ac4407f6b10093073187..7c1a0c07b607f1d882781978e1d08a8a94a546d2 100644 (file)
@@ -231,31 +231,49 @@ static __initconst const struct x86_pmu p6_pmu = {
 
 };
 
+static __init void p6_pmu_rdpmc_quirk(void)
+{
+       if (boot_cpu_data.x86_mask < 9) {
+               /*
+                * PPro erratum 26; fixed in stepping 9 and above.
+                */
+               pr_warn("Userspace RDPMC support disabled due to a CPU erratum\n");
+               x86_pmu.attr_rdpmc_broken = 1;
+               x86_pmu.attr_rdpmc = 0;
+       }
+}
+
 __init int p6_pmu_init(void)
 {
+       x86_pmu = p6_pmu;
+
        switch (boot_cpu_data.x86_model) {
-       case 1:
-       case 3:  /* Pentium Pro */
-       case 5:
-       case 6:  /* Pentium II */
-       case 7:
-       case 8:
-       case 11: /* Pentium III */
-       case 9:
-       case 13:
-               /* Pentium M */
+       case  1: /* Pentium Pro */
+               x86_add_quirk(p6_pmu_rdpmc_quirk);
+               break;
+
+       case  3: /* Pentium II - Klamath */
+       case  5: /* Pentium II - Deschutes */
+       case  6: /* Pentium II - Mendocino */
                break;
+
+       case  7: /* Pentium III - Katmai */
+       case  8: /* Pentium III - Coppermine */
+       case 10: /* Pentium III Xeon */
+       case 11: /* Pentium III - Tualatin */
+               break;
+
+       case  9: /* Pentium M - Banias */
+       case 13: /* Pentium M - Dothan */
+               break;
+
        default:
-               pr_cont("unsupported p6 CPU model %d ",
-                       boot_cpu_data.x86_model);
+               pr_cont("unsupported p6 CPU model %d ", boot_cpu_data.x86_model);
                return -ENODEV;
        }
 
-       x86_pmu = p6_pmu;
-
        memcpy(hw_cache_event_ids, p6_hw_cache_event_ids,
                sizeof(hw_cache_event_ids));
 
-
        return 0;
 }
index d4bdd253fea71358ca080ba567a44935a9830396..e6253195a301ade244143d4d13a73c947602a0cb 100644 (file)
@@ -77,8 +77,7 @@ within(unsigned long addr, unsigned long start, unsigned long end)
        return addr >= start && addr < end;
 }
 
-static int
-do_ftrace_mod_code(unsigned long ip, const void *new_code)
+static unsigned long text_ip_addr(unsigned long ip)
 {
        /*
         * On x86_64, kernel text mappings are mapped read-only with
@@ -91,7 +90,7 @@ do_ftrace_mod_code(unsigned long ip, const void *new_code)
        if (within(ip, (unsigned long)_text, (unsigned long)_etext))
                ip = (unsigned long)__va(__pa_symbol(ip));
 
-       return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE);
+       return ip;
 }
 
 static const unsigned char *ftrace_nop_replace(void)
@@ -123,8 +122,10 @@ ftrace_modify_code_direct(unsigned long ip, unsigned const char *old_code,
        if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0)
                return -EINVAL;
 
+       ip = text_ip_addr(ip);
+
        /* replace the text with the new text */
-       if (do_ftrace_mod_code(ip, new_code))
+       if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
                return -EPERM;
 
        sync_core();
@@ -221,37 +222,51 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
        return -EINVAL;
 }
 
-int ftrace_update_ftrace_func(ftrace_func_t func)
+static unsigned long ftrace_update_func;
+
+static int update_ftrace_func(unsigned long ip, void *new)
 {
-       unsigned long ip = (unsigned long)(&ftrace_call);
-       unsigned char old[MCOUNT_INSN_SIZE], *new;
+       unsigned char old[MCOUNT_INSN_SIZE];
        int ret;
 
-       memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
-       new = ftrace_call_replace(ip, (unsigned long)func);
+       memcpy(old, (void *)ip, MCOUNT_INSN_SIZE);
+
+       ftrace_update_func = ip;
+       /* Make sure the breakpoints see the ftrace_update_func update */
+       smp_wmb();
 
        /* See comment above by declaration of modifying_ftrace_code */
        atomic_inc(&modifying_ftrace_code);
 
        ret = ftrace_modify_code(ip, old, new);
 
+       atomic_dec(&modifying_ftrace_code);
+
+       return ret;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+       unsigned long ip = (unsigned long)(&ftrace_call);
+       unsigned char *new;
+       int ret;
+
+       new = ftrace_call_replace(ip, (unsigned long)func);
+       ret = update_ftrace_func(ip, new);
+
        /* Also update the regs callback function */
        if (!ret) {
                ip = (unsigned long)(&ftrace_regs_call);
-               memcpy(old, &ftrace_regs_call, MCOUNT_INSN_SIZE);
                new = ftrace_call_replace(ip, (unsigned long)func);
-               ret = ftrace_modify_code(ip, old, new);
+               ret = update_ftrace_func(ip, new);
        }
 
-       atomic_dec(&modifying_ftrace_code);
-
        return ret;
 }
 
 static int is_ftrace_caller(unsigned long ip)
 {
-       if (ip == (unsigned long)(&ftrace_call) ||
-               ip == (unsigned long)(&ftrace_regs_call))
+       if (ip == ftrace_update_func)
                return 1;
 
        return 0;
@@ -677,45 +692,41 @@ int __init ftrace_dyn_arch_init(void *data)
 #ifdef CONFIG_DYNAMIC_FTRACE
 extern void ftrace_graph_call(void);
 
-static int ftrace_mod_jmp(unsigned long ip,
-                         int old_offset, int new_offset)
+static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
 {
-       unsigned char code[MCOUNT_INSN_SIZE];
+       static union ftrace_code_union calc;
 
-       if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE))
-               return -EFAULT;
+       /* Jmp not a call (ignore the .e8) */
+       calc.e8         = 0xe9;
+       calc.offset     = ftrace_calc_offset(ip + MCOUNT_INSN_SIZE, addr);
 
-       if (code[0] != 0xe9 || old_offset != *(int *)(&code[1]))
-               return -EINVAL;
+       /*
+        * ftrace external locks synchronize the access to the static variable.
+        */
+       return calc.code;
+}
 
-       *(int *)(&code[1]) = new_offset;
+static int ftrace_mod_jmp(unsigned long ip, void *func)
+{
+       unsigned char *new;
 
-       if (do_ftrace_mod_code(ip, &code))
-               return -EPERM;
+       new = ftrace_jmp_replace(ip, (unsigned long)func);
 
-       return 0;
+       return update_ftrace_func(ip, new);
 }
 
 int ftrace_enable_ftrace_graph_caller(void)
 {
        unsigned long ip = (unsigned long)(&ftrace_graph_call);
-       int old_offset, new_offset;
 
-       old_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
-       new_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
-
-       return ftrace_mod_jmp(ip, old_offset, new_offset);
+       return ftrace_mod_jmp(ip, &ftrace_graph_caller);
 }
 
 int ftrace_disable_ftrace_graph_caller(void)
 {
        unsigned long ip = (unsigned long)(&ftrace_graph_call);
-       int old_offset, new_offset;
-
-       old_offset = (unsigned long)(&ftrace_graph_caller) - (ip + MCOUNT_INSN_SIZE);
-       new_offset = (unsigned long)(&ftrace_stub) - (ip + MCOUNT_INSN_SIZE);
 
-       return ftrace_mod_jmp(ip, old_offset, new_offset);
+       return ftrace_mod_jmp(ip, &ftrace_stub);
 }
 
 #endif /* !CONFIG_DYNAMIC_FTRACE */
index 81ba27679f18ec6100bd167c3739608631a7c475..f36bd42d6f0c8b5fc5cd75dcf133b35a1f6bfe3b 100644 (file)
@@ -544,6 +544,10 @@ ENDPROC(early_idt_handlers)
        /* This is global to keep gas from relaxing the jumps */
 ENTRY(early_idt_handler)
        cld
+
+       cmpl $2,(%esp)          # X86_TRAP_NMI
+       je is_nmi               # Ignore NMI
+
        cmpl $2,%ss:early_recursion_flag
        je hlt_loop
        incl %ss:early_recursion_flag
@@ -594,8 +598,9 @@ ex_entry:
        pop %edx
        pop %ecx
        pop %eax
-       addl $8,%esp            /* drop vector number and error code */
        decl %ss:early_recursion_flag
+is_nmi:
+       addl $8,%esp            /* drop vector number and error code */
        iret
 ENDPROC(early_idt_handler)
 
index e1aabdb314c83740dd686eb4c70a6f40c312e258..a468c0a65c42e00df4e10afd9921d81a53dbba3d 100644 (file)
@@ -343,6 +343,9 @@ early_idt_handlers:
 ENTRY(early_idt_handler)
        cld
 
+       cmpl $2,(%rsp)          # X86_TRAP_NMI
+       je is_nmi               # Ignore NMI
+
        cmpl $2,early_recursion_flag(%rip)
        jz  1f
        incl early_recursion_flag(%rip)
@@ -405,8 +408,9 @@ ENTRY(early_idt_handler)
        popq %rdx
        popq %rcx
        popq %rax
-       addq $16,%rsp           # drop vector number and error code
        decl early_recursion_flag(%rip)
+is_nmi:
+       addq $16,%rsp           # drop vector number and error code
        INTERRUPT_RETURN
 ENDPROC(early_idt_handler)
 
index e8368c6dd2a2988c2d9d68cacc7030554424ad70..d5dd808144190ffd1d443229b4dbbd56740fface 100644 (file)
@@ -86,10 +86,19 @@ EXPORT_SYMBOL(__kernel_fpu_begin);
 
 void __kernel_fpu_end(void)
 {
-       if (use_eager_fpu())
-               math_state_restore();
-       else
+       if (use_eager_fpu()) {
+               /*
+                * For eager fpu, most the time, tsk_used_math() is true.
+                * Restore the user math as we are done with the kernel usage.
+                * At few instances during thread exit, signal handling etc,
+                * tsk_used_math() is false. Those few places will take proper
+                * actions, so we don't need to restore the math here.
+                */
+               if (likely(tsk_used_math(current)))
+                       math_state_restore();
+       } else {
                stts();
+       }
 }
 EXPORT_SYMBOL(__kernel_fpu_end);
 
index 4eabc160696f510ec5ffaddc7939dd71856463d5..679cef0791cd842448216f4a6158cd2ae24fe0e0 100644 (file)
@@ -279,5 +279,7 @@ void arch_crash_save_vmcoreinfo(void)
        VMCOREINFO_SYMBOL(node_data);
        VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
 #endif
+       vmcoreinfo_append_str("KERNELOFFSET=%lx\n",
+                             (unsigned long)&_text - __START_KERNEL);
 }
 
index 872079a67e4d262151dfdbe74f537033be5ebcc0..f7d0672481fd7c328682d601467313acb586280a 100644 (file)
@@ -100,8 +100,10 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
        flag |= __GFP_ZERO;
 again:
        page = NULL;
-       if (!(flag & GFP_ATOMIC))
+       /* CMA can be used only in the context which permits sleeping */
+       if (flag & __GFP_WAIT)
                page = dma_alloc_from_contiguous(dev, count, get_order(size));
+       /* fallback */
        if (!page)
                page = alloc_pages_node(dev_to_node(dev), flag, get_order(size));
        if (!page)
index 7c6acd4b8995e532f5422a03a7fb65c716cbf35d..ff898bbf579d7f34ce7b8c98a5482f72e4d338bf 100644 (file)
@@ -529,7 +529,7 @@ static void quirk_amd_nb_node(struct pci_dev *dev)
                return;
 
        pci_read_config_dword(nb_ht, 0x60, &val);
-       node = val & 7;
+       node = pcibus_to_node(dev->bus) | (val & 7);
        /*
         * Some hardware may return an invalid node ID,
         * so check it first:
index 06853e6703541f8349106e17330f86621fa984db..ce72964b2f469db1b3c626ecadc18c2998ef98a4 100644 (file)
@@ -1239,14 +1239,8 @@ void __init setup_arch(char **cmdline_p)
        register_refined_jiffies(CLOCK_TICK_RATE);
 
 #ifdef CONFIG_EFI
-       /* Once setup is done above, unmap the EFI memory map on
-        * mismatched firmware/kernel archtectures since there is no
-        * support for runtime services.
-        */
-       if (efi_enabled(EFI_BOOT) && !efi_is_native()) {
-               pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
-               efi_unmap_memmap();
-       }
+       if (efi_enabled(EFI_BOOT))
+               efi_apply_memmap_quirks();
 #endif
 }
 
index 19e5adb49a27d8ae4f586ad88b30faeef0f8e727..cfbe99f888300d819b53552a7668ab9bd12c3708 100644 (file)
@@ -209,7 +209,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
         * dance when its actually needed.
         */
 
-       preempt_disable();
+       preempt_disable_notrace();
        data = this_cpu_read(cyc2ns.head);
        tail = this_cpu_read(cyc2ns.tail);
 
@@ -229,7 +229,7 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
                if (!--data->__count)
                        this_cpu_write(cyc2ns.tail, data);
        }
-       preempt_enable();
+       preempt_enable_notrace();
 
        return ns;
 }
@@ -653,13 +653,10 @@ unsigned long native_calibrate_tsc(void)
 
        /* Calibrate TSC using MSR for Intel Atom SoCs */
        local_irq_save(flags);
-       i = try_msr_calibrate_tsc(&fast_calibrate);
+       fast_calibrate = try_msr_calibrate_tsc();
        local_irq_restore(flags);
-       if (i >= 0) {
-               if (i == 0)
-                       pr_warn("Fast TSC calibration using MSR failed\n");
+       if (fast_calibrate)
                return fast_calibrate;
-       }
 
        local_irq_save(flags);
        fast_calibrate = quick_pit_calibrate();
index 8b5434f4389fc4afbbc7d297ab61ec403aedb9d8..92ae6acac8a7fbcb9b91cb386b3c23015c5377ea 100644 (file)
@@ -53,7 +53,7 @@ static struct freq_desc freq_desc_tables[] = {
        /* TNG */
        { 6, 0x4a, 1, { 0, FREQ_100, FREQ_133, 0, 0, 0, 0, 0 } },
        /* VLV2 */
-       { 6, 0x37, 1, { 0, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
+       { 6, 0x37, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_166, 0, 0, 0, 0 } },
        /* ANN */
        { 6, 0x5a, 1, { FREQ_83, FREQ_100, FREQ_133, FREQ_100, 0, 0, 0, 0 } },
 };
@@ -77,21 +77,18 @@ static int match_cpu(u8 family, u8 model)
 
 /*
  * Do MSR calibration only for known/supported CPUs.
- * Return values:
- * -1: CPU is unknown/unsupported for MSR based calibration
- *  0: CPU is known/supported, but calibration failed
- *  1: CPU is known/supported, and calibration succeeded
+ *
+ * Returns the calibration value or 0 if MSR calibration failed.
  */
-int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
+unsigned long try_msr_calibrate_tsc(void)
 {
-       int cpu_index;
        u32 lo, hi, ratio, freq_id, freq;
+       unsigned long res;
+       int cpu_index;
 
        cpu_index = match_cpu(boot_cpu_data.x86, boot_cpu_data.x86_model);
        if (cpu_index < 0)
-               return -1;
-
-       *fast_calibrate = 0;
+               return 0;
 
        if (freq_desc_tables[cpu_index].msr_plat) {
                rdmsr(MSR_PLATFORM_INFO, lo, hi);
@@ -103,7 +100,7 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
        pr_info("Maximum core-clock to bus-clock ratio: 0x%x\n", ratio);
 
        if (!ratio)
-               return 0;
+               goto fail;
 
        /* Get FSB FREQ ID */
        rdmsr(MSR_FSB_FREQ, lo, hi);
@@ -112,16 +109,19 @@ int try_msr_calibrate_tsc(unsigned long *fast_calibrate)
        pr_info("Resolved frequency ID: %u, frequency: %u KHz\n",
                                freq_id, freq);
        if (!freq)
-               return 0;
+               goto fail;
 
        /* TSC frequency = maximum resolved freq * maximum resolved bus ratio */
-       *fast_calibrate = freq * ratio;
-       pr_info("TSC runs at %lu KHz\n", *fast_calibrate);
+       res = freq * ratio;
+       pr_info("TSC runs at %lu KHz\n", res);
 
 #ifdef CONFIG_X86_LOCAL_APIC
        lapic_timer_frequency = (freq * 1000) / HZ;
        pr_info("lapic_timer_frequency = %d\n", lapic_timer_frequency);
 #endif
+       return res;
 
-       return 1;
+fail:
+       pr_warn("Fast TSC calibration using MSR failed\n");
+       return 0;
 }
index e50425d0f5f792c1c940f85cd66e890e5fa3a6ac..9b531351a5876835e3dda6527571383a7fbae751 100644 (file)
@@ -2672,6 +2672,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
                        break;
                }
 
+               drop_large_spte(vcpu, iterator.sptep);
                if (!is_shadow_present_pte(*iterator.sptep)) {
                        u64 base_addr = iterator.addr;
 
index e81df8fce0275781a654f356fe77e38129d5210a..2de1bc09a8d40a0508e7e364bc1de301215cc7c5 100644 (file)
@@ -3002,10 +3002,8 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        u8 cr8_prev = kvm_get_cr8(&svm->vcpu);
        /* instruction emulation calls kvm_set_cr8() */
        r = cr_interception(svm);
-       if (irqchip_in_kernel(svm->vcpu.kvm)) {
-               clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+       if (irqchip_in_kernel(svm->vcpu.kvm))
                return r;
-       }
        if (cr8_prev <= kvm_get_cr8(&svm->vcpu))
                return r;
        kvm_run->exit_reason = KVM_EXIT_SET_TPR;
@@ -3567,6 +3565,8 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
        if (is_guest_mode(vcpu) && (vcpu->arch.hflags & HF_VINTR_MASK))
                return;
 
+       clr_cr_intercept(svm, INTERCEPT_CR8_WRITE);
+
        if (irr == -1)
                return;
 
index a06f101ef64b4ae43e954319bbaa81a5c24c326b..3927528347510bb137e8420f4e26b07d09055483 100644 (file)
@@ -6688,7 +6688,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
                else if (is_page_fault(intr_info))
                        return enable_ept;
                else if (is_no_device(intr_info) &&
-                        !(nested_read_cr0(vmcs12) & X86_CR0_TS))
+                        !(vmcs12->guest_cr0 & X86_CR0_TS))
                        return 0;
                return vmcs12->exception_bitmap &
                                (1u << (intr_info & INTR_INFO_VECTOR_MASK));
index 39c28f09dfd5f03ca064be4bb5cfa01eb0d673a4..2b8578432d5bccd296fa6d5859e3575c0fe4aa02 100644 (file)
@@ -6186,7 +6186,7 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
                frag->len -= len;
        }
 
-       if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
+       if (vcpu->mmio_cur_fragment >= vcpu->mmio_nr_fragments) {
                vcpu->mmio_needed = 0;
 
                /* FIXME: return into emulator if single-stepping.  */
index 9d591c895803101e2decbc85a0ce9f23a0b4eaeb..a10c8c79216187d2faa5add449762710d51c759b 100644 (file)
@@ -1001,6 +1001,12 @@ static int fault_in_kernel_space(unsigned long address)
 
 static inline bool smap_violation(int error_code, struct pt_regs *regs)
 {
+       if (!IS_ENABLED(CONFIG_X86_SMAP))
+               return false;
+
+       if (!static_cpu_has(X86_FEATURE_SMAP))
+               return false;
+
        if (error_code & PF_USER)
                return false;
 
@@ -1014,13 +1020,17 @@ static inline bool smap_violation(int error_code, struct pt_regs *regs)
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
+ *
+ * This function must have noinline because both callers
+ * {,trace_}do_page_fault() have notrace on. Having this an actual function
+ * guarantees there's a function trace entry.
  */
-static void __kprobes
-__do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes noinline
+__do_page_fault(struct pt_regs *regs, unsigned long error_code,
+               unsigned long address)
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
-       unsigned long address;
        struct mm_struct *mm;
        int fault;
        unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
@@ -1028,9 +1038,6 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
        tsk = current;
        mm = tsk->mm;
 
-       /* Get the faulting address: */
-       address = read_cr2();
-
        /*
         * Detect and handle instructions that would cause a page fault for
         * both a tracked kernel page and a userspace page.
@@ -1087,11 +1094,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
        if (unlikely(error_code & PF_RSVD))
                pgtable_bad(regs, error_code, address);
 
-       if (static_cpu_has(X86_FEATURE_SMAP)) {
-               if (unlikely(smap_violation(error_code, regs))) {
-                       bad_area_nosemaphore(regs, error_code, address);
-                       return;
-               }
+       if (unlikely(smap_violation(error_code, regs))) {
+               bad_area_nosemaphore(regs, error_code, address);
+               return;
        }
 
        /*
@@ -1244,32 +1249,50 @@ good_area:
        up_read(&mm->mmap_sem);
 }
 
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
 do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+       unsigned long address = read_cr2(); /* Get the faulting address */
        enum ctx_state prev_state;
 
+       /*
+        * We must have this function tagged with __kprobes, notrace and call
+        * read_cr2() before calling anything else. To avoid calling any kind
+        * of tracing machinery before we've observed the CR2 value.
+        *
+        * exception_{enter,exit}() contain all sorts of tracepoints.
+        */
+
        prev_state = exception_enter();
-       __do_page_fault(regs, error_code);
+       __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
 
-static void trace_page_fault_entries(struct pt_regs *regs,
+#ifdef CONFIG_TRACING
+static void trace_page_fault_entries(unsigned long address, struct pt_regs *regs,
                                     unsigned long error_code)
 {
        if (user_mode(regs))
-               trace_page_fault_user(read_cr2(), regs, error_code);
+               trace_page_fault_user(address, regs, error_code);
        else
-               trace_page_fault_kernel(read_cr2(), regs, error_code);
+               trace_page_fault_kernel(address, regs, error_code);
 }
 
-dotraplinkage void __kprobes
+dotraplinkage void __kprobes notrace
 trace_do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+       /*
+        * The exception_enter and tracepoint processing could
+        * trigger another page faults (user space callchain
+        * reading) and destroy the original cr2 value, so read
+        * the faulting address now.
+        */
+       unsigned long address = read_cr2();
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
-       trace_page_fault_entries(regs, error_code);
-       __do_page_fault(regs, error_code);
+       trace_page_fault_entries(address, regs, error_code);
+       __do_page_fault(regs, error_code, address);
        exception_exit(prev_state);
 }
+#endif /* CONFIG_TRACING */
index 877b9a1b21523183d06973b60a9beb2459fff895..01495755701bd3d068db95df291ef71096d9cf33 100644 (file)
@@ -140,7 +140,7 @@ bpf_slow_path_byte_msh:
        push    %r9;                                            \
        push    SKBDATA;                                        \
 /* rsi already has offset */                                   \
-       mov     $SIZE,%ecx;     /* size */                      \
+       mov     $SIZE,%edx;     /* size */                      \
        call    bpf_internal_load_pointer_neg_helper;           \
        test    %rax,%rax;                                      \
        pop     SKBDATA;                                        \
index 4ed75dd81d052ff96cc832702d174ad4d63bffec..dc017735bb91b7b2ec61f333b091c63accdb921b 100644 (file)
@@ -553,13 +553,13 @@ void bpf_jit_compile(struct sk_filter *fp)
                                }
                                break;
                        case BPF_S_ANC_RXHASH:
-                               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
-                               if (is_imm8(offsetof(struct sk_buff, rxhash))) {
+                               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+                               if (is_imm8(offsetof(struct sk_buff, hash))) {
                                        /* mov off8(%rdi),%eax */
-                                       EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash));
+                                       EMIT3(0x8b, 0x47, offsetof(struct sk_buff, hash));
                                } else {
                                        EMIT2(0x8b, 0x87);
-                                       EMIT(offsetof(struct sk_buff, rxhash), 4);
+                                       EMIT(offsetof(struct sk_buff, hash), 4);
                                }
                                break;
                        case BPF_S_ANC_QUEUE:
@@ -772,6 +772,7 @@ cond_branch:                        f_offset = addrs[i + filter[i].jf] - addrs[i];
                bpf_flush_icache(header, image + proglen);
                set_memory_ro((unsigned long)header, header->pages);
                fp->bpf_func = (void *)image;
+               fp->jited = 1;
        }
 out:
        kfree(addrs);
@@ -791,7 +792,7 @@ static void bpf_jit_free_deferred(struct work_struct *work)
 
 void bpf_jit_free(struct sk_filter *fp)
 {
-       if (fp->bpf_func != sk_run_filter) {
+       if (fp->jited) {
                INIT_WORK(&fp->work, bpf_jit_free_deferred);
                schedule_work(&fp->work);
        } else {
index 4df9591eadad882d4238494c8ddc92d6244945de..f15103dff4b43f04e16ff8bbd59354435aec4cb7 100644 (file)
@@ -42,7 +42,7 @@ void __init efi_bgrt_init(void)
 
        if (bgrt_tab->header.length < sizeof(*bgrt_tab))
                return;
-       if (bgrt_tab->version != 1)
+       if (bgrt_tab->version != 1 || bgrt_tab->status != 1)
                return;
        if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address)
                return;
index d62ec87a2b26d5d51bf2228ac7c2155cf9e8b06e..b97acecf3fd95667e2b67bba8f88bb80428480bb 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/tlbflush.h>
 #include <asm/x86_init.h>
 #include <asm/rtc.h>
+#include <asm/uv/uv.h>
 
 #define EFI_DEBUG
 
@@ -792,7 +793,7 @@ void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
                set_memory_nx(addr, npages);
 }
 
-static void __init runtime_code_page_mkexec(void)
+void __init runtime_code_page_mkexec(void)
 {
        efi_memory_desc_t *md;
        void *p;
@@ -1069,8 +1070,7 @@ void __init efi_enter_virtual_mode(void)
        efi.update_capsule = virt_efi_update_capsule;
        efi.query_capsule_caps = virt_efi_query_capsule_caps;
 
-       if (efi_enabled(EFI_OLD_MEMMAP) && (__supported_pte_mask & _PAGE_NX))
-               runtime_code_page_mkexec();
+       efi_runtime_mkexec();
 
        kfree(new_memmap);
 
@@ -1211,3 +1211,22 @@ static int __init parse_efi_cmdline(char *str)
        return 0;
 }
 early_param("efi", parse_efi_cmdline);
+
+void __init efi_apply_memmap_quirks(void)
+{
+       /*
+        * Once setup is done earlier, unmap the EFI memory map on mismatched
+        * firmware/kernel architectures since there is no support for runtime
+        * services.
+        */
+       if (!efi_is_native()) {
+               pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
+               efi_unmap_memmap();
+       }
+
+       /*
+        * UV doesn't support the new EFI pagetable mapping yet.
+        */
+       if (is_uv_system())
+               set_bit(EFI_OLD_MEMMAP, &x86_efi_facility);
+}
index 249b183cf41799d473012321435b2bdedf979903..0b74cdf7f816aa0e4e6f26c020821266f51aefdb 100644 (file)
@@ -77,3 +77,9 @@ void efi_call_phys_epilog(void)
 
        local_irq_restore(efi_rt_eflags);
 }
+
+void __init efi_runtime_mkexec(void)
+{
+       if (__supported_pte_mask & _PAGE_NX)
+               runtime_code_page_mkexec();
+}
index 6284f158a47d851b1f4a0ca3f951e20ac5c3ffd7..0c2a234fef1e48794a14e13aad812a5b468c6605 100644 (file)
@@ -233,3 +233,12 @@ void __init parse_efi_setup(u64 phys_addr, u32 data_len)
 {
        efi_setup = phys_addr + sizeof(struct setup_data);
 }
+
+void __init efi_runtime_mkexec(void)
+{
+       if (!efi_enabled(EFI_OLD_MEMMAP))
+               return;
+
+       if (__supported_pte_mask & _PAGE_NX)
+               runtime_code_page_mkexec();
+}
index 7d01b8c56c0029a59aa9b5b9e33036728ea7c77e..cc04e67bfd0589966e1c4b4b2fa29079c439ae24 100644 (file)
 #define smp_rmb()      barrier()
 #endif /* CONFIG_X86_PPRO_FENCE */
 
-#ifdef CONFIG_X86_OOSTORE
-#define smp_wmb()      wmb()
-#else /* CONFIG_X86_OOSTORE */
 #define smp_wmb()      barrier()
-#endif /* CONFIG_X86_OOSTORE */
 
 #define smp_read_barrier_depends()     read_barrier_depends()
 #define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
index ba56e11cbf77697f4e972fadd7dd3281f07d4376..c87ae7c6e5f94636ab576a649ada006b4fb376dc 100644 (file)
@@ -20,6 +20,7 @@ config XTENSA
        select HAVE_FUNCTION_TRACER
        select HAVE_IRQ_TIME_ACCOUNTING
        select HAVE_PERF_EVENTS
+       select COMMON_CLK
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -80,7 +81,6 @@ choice
 config XTENSA_VARIANT_FSF
        bool "fsf - default (not generic) configuration"
        select MMU
-       select HAVE_XTENSA_GPIO32
 
 config XTENSA_VARIANT_DC232B
        bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
@@ -135,7 +135,6 @@ config HAVE_SMP
 config SMP
        bool "Enable Symmetric multi-processing support"
        depends on HAVE_SMP
-       select USE_GENERIC_SMP_HELPERS
        select GENERIC_SMP_IDLE_THREAD
        help
          Enabled SMP Software; allows more than one CPU/CORE
index 46b4f5eab421badbec1ae38cab4afac88fb7c731..e7370b11348e8d06c113d420704664740dbdec9b 100644 (file)
                interrupt-controller;
        };
 
+       clocks {
+               osc: main-oscillator {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+               };
+       };
+
        serial0: serial@fd050020 {
                device_type = "serial";
                compatible = "ns16550a";
@@ -42,9 +49,7 @@
                reg = <0xfd050020 0x20>;
                reg-shift = <2>;
                interrupts = <0 1>; /* external irq 0 */
-               /* Filled in by platform_setup from FPGA register
-                * clock-frequency = <100000000>;
-                */
+               clocks = <&osc>;
        };
 
        enet0: ethoc@fd030000 {
@@ -52,5 +57,6 @@
                reg = <0xfd030000 0x4000 0xfd800000 0x4000>;
                interrupts = <1 1>; /* external irq 1 */
                local-mac-address = [00 50 c2 13 6f 00];
+               clocks = <&osc>;
        };
 };
index 2a042d430c253b7dae704633727f0eabc0d5fc91..74944207167eccfb0f6e122ad7418d5728d4a2b7 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifdef CONFIG_MMU
 
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
 extern unsigned long xtensa_kio_paddr;
 
 static inline unsigned long xtensa_get_kio_paddr(void)
index 8c194f6af45e09932976b3f71d8d70a8f556488f..677bfcf4ee5ddab2207ed0e5f2885b4accd29f16 100644 (file)
@@ -23,25 +23,37 @@ void secondary_trap_init(void);
 
 static inline void spill_registers(void)
 {
-
+#if XCHAL_NUM_AREGS > 16
        __asm__ __volatile__ (
-               "movi   a14, "__stringify((1 << PS_EXCM_BIT) | LOCKLEVEL)"\n\t"
-               "mov    a12, a0\n\t"
-               "rsr    a13, sar\n\t"
-               "xsr    a14, ps\n\t"
-               "movi   a0, _spill_registers\n\t"
-               "rsync\n\t"
-               "callx0 a0\n\t"
-               "mov    a0, a12\n\t"
-               "wsr    a13, sar\n\t"
-               "wsr    a14, ps\n\t"
-               : :
-#if defined(CONFIG_FRAME_POINTER)
-               : "a2", "a3", "a4",       "a11", "a12", "a13", "a14", "a15",
+               "       call12  1f\n"
+               "       _j      2f\n"
+               "       retw\n"
+               "       .align  4\n"
+               "1:\n"
+               "       _entry  a1, 48\n"
+               "       addi    a12, a0, 3\n"
+#if XCHAL_NUM_AREGS > 32
+               "       .rept   (" __stringify(XCHAL_NUM_AREGS) " - 32) / 12\n"
+               "       _entry  a1, 48\n"
+               "       mov     a12, a0\n"
+               "       .endr\n"
+#endif
+               "       _entry  a1, 48\n"
+#if XCHAL_NUM_AREGS % 12 == 0
+               "       mov     a8, a8\n"
+#elif XCHAL_NUM_AREGS % 12 == 4
+               "       mov     a12, a12\n"
+#elif XCHAL_NUM_AREGS % 12 == 8
+               "       mov     a4, a4\n"
+#endif
+               "       retw\n"
+               "2:\n"
+               : : : "a12", "a13", "memory");
 #else
-               : "a2", "a3", "a4", "a7", "a11", "a12", "a13", "a14", "a15",
+       __asm__ __volatile__ (
+               "       mov     a12, a12\n"
+               : : : "memory");
 #endif
-                 "memory");
 }
 
 #endif /* _XTENSA_TRAPS_H */
index 5791b45d5a5d5b25f97f9d7d5ee8e05b80ace6cb..f74ddfbb92ef56587b618db2a7e80a2c96593499 100644 (file)
@@ -25,7 +25,7 @@
 #define XCHAL_KIO_DEFAULT_PADDR                0xf0000000
 #define XCHAL_KIO_SIZE                 0x10000000
 
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
 #define XCHAL_KIO_PADDR                        xtensa_get_kio_paddr()
 #else
 #define XCHAL_KIO_PADDR                        XCHAL_KIO_DEFAULT_PADDR
index 51940fec6990f2b9a1c86fa5c43a199c3eade2f0..b9395529f02d465643091d71c4d6b6ca9650ff4b 100644 (file)
@@ -734,7 +734,12 @@ __SYSCALL(332, sys_finit_module, 3)
 #define __NR_accept4                           333
 __SYSCALL(333, sys_accept4, 4)
 
-#define __NR_syscall_count                     334
+#define __NR_sched_setattr                     334
+__SYSCALL(334, sys_sched_setattr, 2)
+#define __NR_sched_getattr                     335
+__SYSCALL(335, sys_sched_getattr, 3)
+
+#define __NR_syscall_count                     336
 
 /*
  * sysxtensa syscall handler
index 21dbe6bdb8edc661d729f656a02a5f1cf01a18c1..ef7f4990722b4fde3a175a0d524f82c3b2ce8b7b 100644 (file)
@@ -1081,196 +1081,53 @@ ENTRY(fast_syscall_spill_registers)
 
        rsr     a0, sar
        s32i    a3, a2, PT_AREG3
-       s32i    a4, a2, PT_AREG4
-       s32i    a0, a2, PT_AREG5        # store SAR to PT_AREG5
+       s32i    a0, a2, PT_SAR
 
-       /* The spill routine might clobber a7, a11, and a15. */
+       /* The spill routine might clobber a4, a7, a8, a11, a12, and a15. */
 
+       s32i    a4, a2, PT_AREG4
        s32i    a7, a2, PT_AREG7
+       s32i    a8, a2, PT_AREG8
        s32i    a11, a2, PT_AREG11
+       s32i    a12, a2, PT_AREG12
        s32i    a15, a2, PT_AREG15
 
-       call0   _spill_registers        # destroys a3, a4, and SAR
-
-       /* Advance PC, restore registers and SAR, and return from exception. */
-
-       l32i    a3, a2, PT_AREG5
-       l32i    a4, a2, PT_AREG4
-       l32i    a0, a2, PT_AREG0
-       wsr     a3, sar
-       l32i    a3, a2, PT_AREG3
-
-       /* Restore clobbered registers. */
-
-       l32i    a7, a2, PT_AREG7
-       l32i    a11, a2, PT_AREG11
-       l32i    a15, a2, PT_AREG15
-
-       movi    a2, 0
-       rfe
-
-ENDPROC(fast_syscall_spill_registers)
-
-/* Fixup handler.
- *
- * We get here if the spill routine causes an exception, e.g. tlb miss.
- * We basically restore WINDOWBASE and WINDOWSTART to the condition when
- * we entered the spill routine and jump to the user exception handler.
- *
- * a0: value of depc, original value in depc
- * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
- * a3: exctable, original value in excsave1
- */
-
-ENTRY(fast_syscall_spill_registers_fixup)
-
-       rsr     a2, windowbase  # get current windowbase (a2 is saved)
-       xsr     a0, depc        # restore depc and a0
-       ssl     a2              # set shift (32 - WB)
-
-       /* We need to make sure the current registers (a0-a3) are preserved.
-        * To do this, we simply set the bit for the current window frame
-        * in WS, so that the exception handlers save them to the task stack.
-        */
-
-       xsr     a3, excsave1    # get spill-mask
-       slli    a3, a3, 1       # shift left by one
-
-       slli    a2, a3, 32-WSBITS
-       src     a2, a3, a2      # a2 = xxwww1yyxxxwww1yy......
-       wsr     a2, windowstart # set corrected windowstart
-
-       srli    a3, a3, 1
-       rsr     a2, excsave1
-       l32i    a2, a2, EXC_TABLE_DOUBLE_SAVE   # restore a2
-       xsr     a2, excsave1
-       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE   # save a3
-       l32i    a3, a2, EXC_TABLE_PARAM # original WB (in user task)
-       xsr     a2, excsave1
-
-       /* Return to the original (user task) WINDOWBASE.
-        * We leave the following frame behind:
-        * a0, a1, a2   same
-        * a3:          trashed (saved in EXC_TABLE_DOUBLE_SAVE)
-        * depc:        depc (we have to return to that address)
-        * excsave_1:   exctable
-        */
-
-       wsr     a3, windowbase
-       rsync
-
-       /* We are now in the original frame when we entered _spill_registers:
-        *  a0: return address
-        *  a1: used, stack pointer
-        *  a2: kernel stack pointer
-        *  a3: available
-        *  depc: exception address
-        *  excsave: exctable
-        * Note: This frame might be the same as above.
-        */
-
-       /* Setup stack pointer. */
-
-       addi    a2, a2, -PT_USER_SIZE
-       s32i    a0, a2, PT_AREG0
-
-       /* Make sure we return to this fixup handler. */
-
-       movi    a3, fast_syscall_spill_registers_fixup_return
-       s32i    a3, a2, PT_DEPC         # setup depc
-
-       /* Jump to the exception handler. */
-
-       rsr     a3, excsave1
-       rsr     a0, exccause
-       addx4   a0, a0, a3                      # find entry in table
-       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
-       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
-       jx      a0
-
-ENDPROC(fast_syscall_spill_registers_fixup)
-
-ENTRY(fast_syscall_spill_registers_fixup_return)
-
-       /* When we return here, all registers have been restored (a2: DEPC) */
-
-       wsr     a2, depc                # exception address
-
-       /* Restore fixup handler. */
-
-       rsr     a2, excsave1
-       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE
-       movi    a3, fast_syscall_spill_registers_fixup
-       s32i    a3, a2, EXC_TABLE_FIXUP
-       rsr     a3, windowbase
-       s32i    a3, a2, EXC_TABLE_PARAM
-       l32i    a2, a2, EXC_TABLE_KSTK
-
-       /* Load WB at the time the exception occurred. */
-
-       rsr     a3, sar                 # WB is still in SAR
-       neg     a3, a3
-       wsr     a3, windowbase
-       rsync
-
-       rsr     a3, excsave1
-       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
-
-       rfde
-
-ENDPROC(fast_syscall_spill_registers_fixup_return)
-
-/*
- * spill all registers.
- *
- * This is not a real function. The following conditions must be met:
- *
- *  - must be called with call0.
- *  - uses a3, a4 and SAR.
- *  - the last 'valid' register of each frame are clobbered.
- *  - the caller must have registered a fixup handler
- *    (or be inside a critical section)
- *  - PS_EXCM must be set (PS_WOE cleared?)
- */
-
-ENTRY(_spill_registers)
-
        /*
         * Rotate ws so that the current windowbase is at bit 0.
         * Assume ws = xxxwww1yy (www1 current window frame).
         * Rotate ws right so that a4 = yyxxxwww1.
         */
 
-       rsr     a4, windowbase
+       rsr     a0, windowbase
        rsr     a3, windowstart         # a3 = xxxwww1yy
-       ssr     a4                      # holds WB
-       slli    a4, a3, WSBITS
-       or      a3, a3, a4              # a3 = xxxwww1yyxxxwww1yy
+       ssr     a0                      # holds WB
+       slli    a0, a3, WSBITS
+       or      a3, a3, a0              # a3 = xxxwww1yyxxxwww1yy
        srl     a3, a3                  # a3 = 00xxxwww1yyxxxwww1
 
        /* We are done if there are no more than the current register frame. */
 
        extui   a3, a3, 1, WSBITS-1     # a3 = 0yyxxxwww
-       movi    a4, (1 << (WSBITS-1))
+       movi    a0, (1 << (WSBITS-1))
        _beqz   a3, .Lnospill           # only one active frame? jump
 
        /* We want 1 at the top, so that we return to the current windowbase */
 
-       or      a3, a3, a4              # 1yyxxxwww
+       or      a3, a3, a0              # 1yyxxxwww
 
        /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
 
        wsr     a3, windowstart         # save shifted windowstart
-       neg     a4, a3
-       and     a3, a4, a3              # first bit set from right: 000010000
+       neg     a0, a3
+       and     a3, a0, a3              # first bit set from right: 000010000
 
-       ffs_ws  a4, a3                  # a4: shifts to skip empty frames
+       ffs_ws  a0, a3                  # a0: shifts to skip empty frames
        movi    a3, WSBITS
-       sub     a4, a3, a4              # WSBITS-a4:number of 0-bits from right
-       ssr     a4                      # save in SAR for later.
+       sub     a0, a3, a0              # WSBITS-a0:number of 0-bits from right
+       ssr     a0                      # save in SAR for later.
 
        rsr     a3, windowbase
-       add     a3, a3, a4
+       add     a3, a3, a0
        wsr     a3, windowbase
        rsync
 
@@ -1285,22 +1142,6 @@ ENTRY(_spill_registers)
         * we have to save 4,8. or 12 registers.
         */
 
-       _bbsi.l a3, 1, .Lc4
-       _bbsi.l a3, 2, .Lc8
-
-       /* Special case: we have a call12-frame starting at a4. */
-
-       _bbci.l a3, 3, .Lc12    # bit 3 shouldn't be zero! (Jump to Lc12 first)
-
-       s32e    a4, a1, -16     # a1 is valid with an empty spill area
-       l32e    a4, a5, -12
-       s32e    a8, a4, -48
-       mov     a8, a4
-       l32e    a4, a1, -16
-       j       .Lc12c
-
-.Lnospill:
-       ret
 
 .Lloop: _bbsi.l        a3, 1, .Lc4
        _bbci.l a3, 2, .Lc12
@@ -1314,20 +1155,10 @@ ENTRY(_spill_registers)
        s32e    a9, a4, -28
        s32e    a10, a4, -24
        s32e    a11, a4, -20
-
        srli    a11, a3, 2              # shift windowbase by 2
        rotw    2
        _bnei   a3, 1, .Lloop
-
-.Lexit: /* Done. Do the final rotation, set WS, and return. */
-
-       rotw    1
-       rsr     a3, windowbase
-       ssl     a3
-       movi    a3, 1
-       sll     a3, a3
-       wsr     a3, windowstart
-       ret
+       j       .Lexit
 
 .Lc4:  s32e    a4, a9, -16
        s32e    a5, a9, -12
@@ -1343,11 +1174,11 @@ ENTRY(_spill_registers)
 
        /* 12-register frame (call12) */
 
-       l32e    a2, a5, -12
-       s32e    a8, a2, -48
-       mov     a8, a2
+       l32e    a0, a5, -12
+       s32e    a8, a0, -48
+       mov     a8, a0
 
-.Lc12c: s32e   a9, a8, -44
+       s32e    a9, a8, -44
        s32e    a10, a8, -40
        s32e    a11, a8, -36
        s32e    a12, a8, -32
@@ -1367,30 +1198,54 @@ ENTRY(_spill_registers)
         */
 
        rotw    1
-       mov     a5, a13
+       mov     a4, a13
        rotw    -1
 
-       s32e    a4, a9, -16
-       s32e    a5, a9, -12
-       s32e    a6, a9, -8
-       s32e    a7, a9, -4
+       s32e    a4, a8, -16
+       s32e    a5, a8, -12
+       s32e    a6, a8, -8
+       s32e    a7, a8, -4
 
        rotw    3
 
        _beqi   a3, 1, .Lexit
        j       .Lloop
 
-.Linvalid_mask:
+.Lexit:
 
-       /* We get here because of an unrecoverable error in the window
-        * registers. If we are in user space, we kill the application,
-        * however, this condition is unrecoverable in kernel space.
-        */
+       /* Done. Do the final rotation and set WS */
+
+       rotw    1
+       rsr     a3, windowbase
+       ssl     a3
+       movi    a3, 1
+       sll     a3, a3
+       wsr     a3, windowstart
+.Lnospill:
+
+       /* Advance PC, restore registers and SAR, and return from exception. */
+
+       l32i    a3, a2, PT_SAR
+       l32i    a0, a2, PT_AREG0
+       wsr     a3, sar
+       l32i    a3, a2, PT_AREG3
 
-       rsr     a0, ps
-       _bbci.l a0, PS_UM_BIT, 1f
+       /* Restore clobbered registers. */
 
-       /* User space: Setup a dummy frame and kill application.
+       l32i    a4, a2, PT_AREG4
+       l32i    a7, a2, PT_AREG7
+       l32i    a8, a2, PT_AREG8
+       l32i    a11, a2, PT_AREG11
+       l32i    a12, a2, PT_AREG12
+       l32i    a15, a2, PT_AREG15
+
+       movi    a2, 0
+       rfe
+
+.Linvalid_mask:
+
+       /* We get here because of an unrecoverable error in the window
+        * registers, so set up a dummy frame and kill the user application.
         * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
         */
 
@@ -1414,14 +1269,136 @@ ENTRY(_spill_registers)
        movi    a4, do_exit
        callx4  a4
 
-1:     /* Kernel space: PANIC! */
+       /* shouldn't return, so panic */
 
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
        callx0  a0              # should not return
 1:     j       1b
 
-ENDPROC(_spill_registers)
+
+ENDPROC(fast_syscall_spill_registers)
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * Note that we only need to restore the bits in windowstart that have not
+ * been spilled yet by the _spill_register routine. Luckily, a3 contains a
+ * rotated windowstart with only those bits set for frames that haven't been
+ * spilled yet. Because a3 is rotated such that bit 0 represents the register
+ * frame for the current windowbase - 1, we need to rotate a3 left by the
+ * value of the current windowbase + 1 and move it to windowstart.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+ENTRY(fast_syscall_spill_registers_fixup)
+
+       rsr     a2, windowbase  # get current windowbase (a2 is saved)
+       xsr     a0, depc        # restore depc and a0
+       ssl     a2              # set shift (32 - WB)
+
+       /* We need to make sure the current registers (a0-a3) are preserved.
+        * To do this, we simply set the bit for the current window frame
+        * in WS, so that the exception handlers save them to the task stack.
+        *
+        * Note: we use a3 to set the windowbase, so we take a special care
+        * of it, saving it in the original _spill_registers frame across
+        * the exception handler call.
+        */
+
+       xsr     a3, excsave1    # get spill-mask
+       slli    a3, a3, 1       # shift left by one
+       addi    a3, a3, 1       # set the bit for the current window frame
+
+       slli    a2, a3, 32-WSBITS
+       src     a2, a3, a2      # a2 = xxwww1yyxxxwww1yy......
+       wsr     a2, windowstart # set corrected windowstart
+
+       srli    a3, a3, 1
+       rsr     a2, excsave1
+       l32i    a2, a2, EXC_TABLE_DOUBLE_SAVE   # restore a2
+       xsr     a2, excsave1
+       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE   # save a3
+       l32i    a3, a2, EXC_TABLE_PARAM # original WB (in user task)
+       xsr     a2, excsave1
+
+       /* Return to the original (user task) WINDOWBASE.
+        * We leave the following frame behind:
+        * a0, a1, a2   same
+        * a3:          trashed (saved in EXC_TABLE_DOUBLE_SAVE)
+        * depc:        depc (we have to return to that address)
+        * excsave_1:   exctable
+        */
+
+       wsr     a3, windowbase
+       rsync
+
+       /* We are now in the original frame when we entered _spill_registers:
+        *  a0: return address
+        *  a1: used, stack pointer
+        *  a2: kernel stack pointer
+        *  a3: available
+        *  depc: exception address
+        *  excsave: exctable
+        * Note: This frame might be the same as above.
+        */
+
+       /* Setup stack pointer. */
+
+       addi    a2, a2, -PT_USER_SIZE
+       s32i    a0, a2, PT_AREG0
+
+       /* Make sure we return to this fixup handler. */
+
+       movi    a3, fast_syscall_spill_registers_fixup_return
+       s32i    a3, a2, PT_DEPC         # setup depc
+
+       /* Jump to the exception handler. */
+
+       rsr     a3, excsave1
+       rsr     a0, exccause
+       addx4   a0, a0, a3                      # find entry in table
+       l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
+       jx      a0
+
+ENDPROC(fast_syscall_spill_registers_fixup)
+
+ENTRY(fast_syscall_spill_registers_fixup_return)
+
+       /* When we return here, all registers have been restored (a2: DEPC) */
+
+       wsr     a2, depc                # exception address
+
+       /* Restore fixup handler. */
+
+       rsr     a2, excsave1
+       s32i    a3, a2, EXC_TABLE_DOUBLE_SAVE
+       movi    a3, fast_syscall_spill_registers_fixup
+       s32i    a3, a2, EXC_TABLE_FIXUP
+       rsr     a3, windowbase
+       s32i    a3, a2, EXC_TABLE_PARAM
+       l32i    a2, a2, EXC_TABLE_KSTK
+
+       /* Load WB at the time the exception occurred. */
+
+       rsr     a3, sar                 # WB is still in SAR
+       neg     a3, a3
+       wsr     a3, windowbase
+       rsync
+
+       rsr     a3, excsave1
+       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
+
+       rfde
+
+ENDPROC(fast_syscall_spill_registers_fixup_return)
 
 #ifdef CONFIG_MMU
 /*
@@ -1794,6 +1771,43 @@ ENTRY(system_call)
 
 ENDPROC(system_call)
 
+/*
+ * Spill live registers on the kernel stack macro.
+ *
+ * Entry condition: ps.woe is set, ps.excm is cleared
+ * Exit condition: windowstart has single bit set
+ * May clobber: a12, a13
+ */
+       .macro  spill_registers_kernel
+
+#if XCHAL_NUM_AREGS > 16
+       call12  1f
+       _j      2f
+       retw
+       .align  4
+1:
+       _entry  a1, 48
+       addi    a12, a0, 3
+#if XCHAL_NUM_AREGS > 32
+       .rept   (XCHAL_NUM_AREGS - 32) / 12
+       _entry  a1, 48
+       mov     a12, a0
+       .endr
+#endif
+       _entry  a1, 48
+#if XCHAL_NUM_AREGS % 12 == 0
+       mov     a8, a8
+#elif XCHAL_NUM_AREGS % 12 == 4
+       mov     a12, a12
+#elif XCHAL_NUM_AREGS % 12 == 8
+       mov     a4, a4
+#endif
+       retw
+2:
+#else
+       mov     a12, a12
+#endif
+       .endm
 
 /*
  * Task switch.
@@ -1806,21 +1820,20 @@ ENTRY(_switch_to)
 
        entry   a1, 16
 
-       mov     a12, a2                 # preserve 'prev' (a2)
-       mov     a13, a3                 # and 'next' (a3)
+       mov     a10, a2                 # preserve 'prev' (a2)
+       mov     a11, a3                 # and 'next' (a3)
 
        l32i    a4, a2, TASK_THREAD_INFO
        l32i    a5, a3, TASK_THREAD_INFO
 
-       save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+       save_xtregs_user a4 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
 
-       s32i    a0, a12, THREAD_RA      # save return address
-       s32i    a1, a12, THREAD_SP      # save stack pointer
+       s32i    a0, a10, THREAD_RA      # save return address
+       s32i    a1, a10, THREAD_SP      # save stack pointer
 
        /* Disable ints while we manipulate the stack pointer. */
 
-       movi    a14, (1 << PS_EXCM_BIT) | LOCKLEVEL
-       xsr     a14, ps
+       rsil    a14, LOCKLEVEL
        rsr     a3, excsave1
        rsync
        s32i    a3, a3, EXC_TABLE_FIXUP /* enter critical section */
@@ -1835,7 +1848,7 @@ ENTRY(_switch_to)
 
        /* Flush register file. */
 
-       call0   _spill_registers        # destroys a3, a4, and SAR
+       spill_registers_kernel
 
        /* Set kernel stack (and leave critical section)
         * Note: It's save to set it here. The stack will not be overwritten
@@ -1851,13 +1864,13 @@ ENTRY(_switch_to)
 
        /* restore context of the task 'next' */
 
-       l32i    a0, a13, THREAD_RA      # restore return address
-       l32i    a1, a13, THREAD_SP      # restore stack pointer
+       l32i    a0, a11, THREAD_RA      # restore return address
+       l32i    a1, a11, THREAD_SP      # restore stack pointer
 
-       load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER
+       load_xtregs_user a5 a6 a8 a9 a12 a13 THREAD_XTREGS_USER
 
        wsr     a14, ps
-       mov     a2, a12                 # return 'prev'
+       mov     a2, a10                 # return 'prev'
        rsync
 
        retw
index 7d12af1317f183d9af4b813ba4fd11bc94450924..84fe931bb60e1f012417d202d002813b12cf68aa 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/bootmem.h>
 #include <linux/kernel.h>
 #include <linux/percpu.h>
+#include <linux/clk-provider.h>
 #include <linux/cpu.h>
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
@@ -276,6 +277,7 @@ void __init early_init_devtree(void *params)
 
 static int __init xtensa_device_probe(void)
 {
+       of_clk_init(NULL);
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
        return 0;
 }
index 08b769d3b3a1c48482179eac8c68c562f61321c4..2a1823de69ccf621b6ea63e2ad815bbe118fa2f9 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/platform.h>
 
 unsigned long ccount_freq;             /* ccount Hz */
+EXPORT_SYMBOL(ccount_freq);
 
 static cycle_t ccount_read(struct clocksource *cs)
 {
index cb8fd44caabc6d246ce7975dfc0f370d87052fc2..f9e1ec346e359c7410482c5d8dfd5a9de88bfafc 100644 (file)
@@ -235,7 +235,7 @@ ENTRY(_DoubleExceptionVector)
 
        /* Check for overflow/underflow exception, jump if overflow. */
 
-       _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
+       bbci.l  a0, 6, _DoubleExceptionVector_WindowOverflow
 
        /*
         * Restart window underflow exception.
index 74a60c7e085ea40349336089889de2d52f9d142c..80b33ed51f31174fd41a53bebd957c140517d8f9 100644 (file)
@@ -122,9 +122,7 @@ EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
 
 extern long common_exception_return;
-extern long _spill_registers;
 EXPORT_SYMBOL(common_exception_return);
-EXPORT_SYMBOL(_spill_registers);
 
 #ifdef CONFIG_FUNCTION_TRACER
 EXPORT_SYMBOL(_mcount);
index 479d7537a32a4f8039ae02581f8644d53eb80dda..aff108df92d3a301e8ba0ccaf7e13a5fb26c9038 100644 (file)
@@ -90,7 +90,7 @@ int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
 
 
 /*
- * Initialize the bootmem system and give it all the memory we have available.
+ * Initialize the bootmem system and give it all low memory we have available.
  */
 
 void __init bootmem_init(void)
@@ -142,9 +142,14 @@ void __init bootmem_init(void)
 
        /* Add all remaining memory pieces into the bootmem map */
 
-       for (i=0; i<sysmem.nr_banks; i++)
-               free_bootmem(sysmem.bank[i].start,
-                            sysmem.bank[i].end - sysmem.bank[i].start);
+       for (i = 0; i < sysmem.nr_banks; i++) {
+               if (sysmem.bank[i].start >> PAGE_SHIFT < max_low_pfn) {
+                       unsigned long end = min(max_low_pfn << PAGE_SHIFT,
+                                               sysmem.bank[i].end);
+                       free_bootmem(sysmem.bank[i].start,
+                                    end - sysmem.bank[i].start);
+               }
+       }
 
 }
 
index 36ec171698b833ddbebb6c9e51e9f18d4c53f278..861203e958da828deb140122752e95b47ddbf35f 100644 (file)
@@ -39,7 +39,7 @@ void init_mmu(void)
        set_itlbcfg_register(0);
        set_dtlbcfg_register(0);
 #endif
-#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && CONFIG_OF
+#if XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY && defined(CONFIG_OF)
        /*
         * Update the IO area mapping in case xtensa_kio_paddr has changed
         */
index 800227862fe8b91d561e8b318b757675a1e21f68..57fd08b36f51a151a389794bf4e8af7c9b64fd13 100644 (file)
@@ -135,11 +135,11 @@ static void __init update_local_mac(struct device_node *node)
 
 static int __init machine_setup(void)
 {
-       struct device_node *serial;
+       struct device_node *clock;
        struct device_node *eth = NULL;
 
-       for_each_compatible_node(serial, NULL, "ns16550a")
-               update_clock_frequency(serial);
+       for_each_node_by_name(clock, "main-oscillator")
+               update_clock_frequency(clock);
 
        if ((eth = of_find_compatible_node(eth, NULL, "opencores,ethoc")))
                update_local_mac(eth);
@@ -290,6 +290,7 @@ static int __init xtavnet_init(void)
         * knows whether they set it correctly on the DIP switches.
         */
        pr_info("XTFPGA: Ethernet MAC %pM\n", ethoc_pdata.hwaddr);
+       ethoc_pdata.eth_clkfreq = *(long *)XTFPGA_CLKFRQ_VADDR;
 
        return 0;
 }
index bf4020116df521d18e1891d33a1815154b6046e9..244cdea4dee50252a06e41799badfb1c5c2e61a1 100644 (file)
 #define XCHAL_CP_MASK                  0x00    /* bitmask of all CPs by ID */
 #define XCHAL_CP_PORT_MASK             0x00    /* bitmask of only port CPs */
 
-/*  Basic parameters of each coprocessor:  */
-#define XCHAL_CP7_NAME                 "XTIOP"
-#define XCHAL_CP7_IDENT                        XTIOP
-#define XCHAL_CP7_SA_SIZE              0       /* size of state save area */
-#define XCHAL_CP7_SA_ALIGN             1       /* min alignment of save area */
-#define XCHAL_CP_ID_XTIOP              7       /* coprocessor ID (0..7) */
-
 /*  Filler info for unassigned coprocessors, to simplify arrays etc:  */
 #define XCHAL_NCP_SA_SIZE              0
 #define XCHAL_NCP_SA_ALIGN             1
@@ -42,6 +35,8 @@
 #define XCHAL_CP5_SA_ALIGN             1
 #define XCHAL_CP6_SA_SIZE              0
 #define XCHAL_CP6_SA_ALIGN             1
+#define XCHAL_CP7_SA_SIZE              0
+#define XCHAL_CP7_SA_ALIGN             1
 
 /*  Save area for non-coprocessor optional and custom (TIE) state:  */
 #define XCHAL_NCP_SA_SIZE              0
index 86154eab95239fdd6300ddc665f03650b80f1a5b..604f6d99ab92ca859d46b7ff7d8ce4b5519ebb61 100644 (file)
@@ -435,9 +435,9 @@ static inline uint64_t blkg_stat_read(struct blkg_stat *stat)
        uint64_t v;
 
        do {
-               start = u64_stats_fetch_begin_bh(&stat->syncp);
+               start = u64_stats_fetch_begin_irq(&stat->syncp);
                v = stat->cnt;
-       } while (u64_stats_fetch_retry_bh(&stat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&stat->syncp, start));
 
        return v;
 }
@@ -508,9 +508,9 @@ static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat)
        struct blkg_rwstat tmp;
 
        do {
-               start = u64_stats_fetch_begin_bh(&rwstat->syncp);
+               start = u64_stats_fetch_begin_irq(&rwstat->syncp);
                tmp = *rwstat;
-       } while (u64_stats_fetch_retry_bh(&rwstat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rwstat->syncp, start));
 
        return tmp;
 }
index c00e0bdeab4ab4724c42b379717200d405d9c584..bfe16d5af9f91a7eec049420e3f5b080476dc503 100644 (file)
@@ -708,9 +708,13 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
        if (!q)
                return NULL;
 
-       if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+       q->flush_rq = kzalloc(sizeof(struct request), GFP_KERNEL);
+       if (!q->flush_rq)
                return NULL;
 
+       if (blk_init_rl(&q->root_rl, q, GFP_KERNEL))
+               goto fail;
+
        q->request_fn           = rfn;
        q->prep_rq_fn           = NULL;
        q->unprep_rq_fn         = NULL;
@@ -733,12 +737,16 @@ blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
        /* init elevator */
        if (elevator_init(q, NULL)) {
                mutex_unlock(&q->sysfs_lock);
-               return NULL;
+               goto fail;
        }
 
        mutex_unlock(&q->sysfs_lock);
 
        return q;
+
+fail:
+       kfree(q->flush_rq);
+       return NULL;
 }
 EXPORT_SYMBOL(blk_init_allocated_queue);
 
@@ -1127,7 +1135,7 @@ static struct request *blk_old_get_request(struct request_queue *q, int rw,
 struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask)
 {
        if (q->mq_ops)
-               return blk_mq_alloc_request(q, rw, gfp_mask, false);
+               return blk_mq_alloc_request(q, rw, gfp_mask);
        else
                return blk_old_get_request(q, rw, gfp_mask);
 }
@@ -1278,6 +1286,11 @@ void __blk_put_request(struct request_queue *q, struct request *req)
        if (unlikely(!q))
                return;
 
+       if (q->mq_ops) {
+               blk_mq_free_request(req);
+               return;
+       }
+
        blk_pm_put_request(req);
 
        elv_completed_request(q, req);
index bbfc072a79c2b5d0921ee84d322e4391d85c529b..dbf4502b1d6779eadd1573f28f75def4e26a031a 100644 (file)
@@ -65,7 +65,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
         * be resued after dying flag is set
         */
        if (q->mq_ops) {
-               blk_mq_insert_request(q, rq, true);
+               blk_mq_insert_request(rq, at_head, true, false);
                return;
        }
 
index 9288aaf35c21fc8c0f579fa001f316e697a4dfbb..43e6b4755e9a7e74e05479a83d42fbd88762e9f4 100644 (file)
@@ -130,20 +130,29 @@ static void blk_flush_restore_request(struct request *rq)
        blk_clear_rq_complete(rq);
 }
 
-static void mq_flush_data_run(struct work_struct *work)
+static void mq_flush_run(struct work_struct *work)
 {
        struct request *rq;
 
-       rq = container_of(work, struct request, mq_flush_data);
+       rq = container_of(work, struct request, mq_flush_work);
 
        memset(&rq->csd, 0, sizeof(rq->csd));
-       blk_mq_run_request(rq, true, false);
+       blk_mq_insert_request(rq, false, true, false);
 }
 
-static void blk_mq_flush_data_insert(struct request *rq)
+static bool blk_flush_queue_rq(struct request *rq, bool add_front)
 {
-       INIT_WORK(&rq->mq_flush_data, mq_flush_data_run);
-       kblockd_schedule_work(rq->q, &rq->mq_flush_data);
+       if (rq->q->mq_ops) {
+               INIT_WORK(&rq->mq_flush_work, mq_flush_run);
+               kblockd_schedule_work(rq->q, &rq->mq_flush_work);
+               return false;
+       } else {
+               if (add_front)
+                       list_add(&rq->queuelist, &rq->q->queue_head);
+               else
+                       list_add_tail(&rq->queuelist, &rq->q->queue_head);
+               return true;
+       }
 }
 
 /**
@@ -187,12 +196,7 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
 
        case REQ_FSEQ_DATA:
                list_move_tail(&rq->flush.list, &q->flush_data_in_flight);
-               if (q->mq_ops)
-                       blk_mq_flush_data_insert(rq);
-               else {
-                       list_add(&rq->queuelist, &q->queue_head);
-                       queued = true;
-               }
+               queued = blk_flush_queue_rq(rq, true);
                break;
 
        case REQ_FSEQ_DONE:
@@ -216,9 +220,6 @@ static bool blk_flush_complete_seq(struct request *rq, unsigned int seq,
        }
 
        kicked = blk_kick_flush(q);
-       /* blk_mq_run_flush will run queue */
-       if (q->mq_ops)
-               return queued;
        return kicked | queued;
 }
 
@@ -230,10 +231,9 @@ static void flush_end_io(struct request *flush_rq, int error)
        struct request *rq, *n;
        unsigned long flags = 0;
 
-       if (q->mq_ops) {
-               blk_mq_free_request(flush_rq);
+       if (q->mq_ops)
                spin_lock_irqsave(&q->mq_flush_lock, flags);
-       }
+
        running = &q->flush_queue[q->flush_running_idx];
        BUG_ON(q->flush_pending_idx == q->flush_running_idx);
 
@@ -263,49 +263,14 @@ static void flush_end_io(struct request *flush_rq, int error)
         * kblockd.
         */
        if (queued || q->flush_queue_delayed) {
-               if (!q->mq_ops)
-                       blk_run_queue_async(q);
-               else
-               /*
-                * This can be optimized to only run queues with requests
-                * queued if necessary.
-                */
-                       blk_mq_run_queues(q, true);
+               WARN_ON(q->mq_ops);
+               blk_run_queue_async(q);
        }
        q->flush_queue_delayed = 0;
        if (q->mq_ops)
                spin_unlock_irqrestore(&q->mq_flush_lock, flags);
 }
 
-static void mq_flush_work(struct work_struct *work)
-{
-       struct request_queue *q;
-       struct request *rq;
-
-       q = container_of(work, struct request_queue, mq_flush_work);
-
-       /* We don't need set REQ_FLUSH_SEQ, it's for consistency */
-       rq = blk_mq_alloc_request(q, WRITE_FLUSH|REQ_FLUSH_SEQ,
-               __GFP_WAIT|GFP_ATOMIC, true);
-       rq->cmd_type = REQ_TYPE_FS;
-       rq->end_io = flush_end_io;
-
-       blk_mq_run_request(rq, true, false);
-}
-
-/*
- * We can't directly use q->flush_rq, because it doesn't have tag and is not in
- * hctx->rqs[]. so we must allocate a new request, since we can't sleep here,
- * so offload the work to workqueue.
- *
- * Note: we assume a flush request finished in any hardware queue will flush
- * the whole disk cache.
- */
-static void mq_run_flush(struct request_queue *q)
-{
-       kblockd_schedule_work(q, &q->mq_flush_work);
-}
-
 /**
  * blk_kick_flush - consider issuing flush request
  * @q: request_queue being kicked
@@ -340,19 +305,31 @@ static bool blk_kick_flush(struct request_queue *q)
         * different from running_idx, which means flush is in flight.
         */
        q->flush_pending_idx ^= 1;
+
        if (q->mq_ops) {
-               mq_run_flush(q);
-               return true;
+               struct blk_mq_ctx *ctx = first_rq->mq_ctx;
+               struct blk_mq_hw_ctx *hctx = q->mq_ops->map_queue(q, ctx->cpu);
+
+               blk_mq_rq_init(hctx, q->flush_rq);
+               q->flush_rq->mq_ctx = ctx;
+
+               /*
+                * Reuse the tag value from the fist waiting request,
+                * with blk-mq the tag is generated during request
+                * allocation and drivers can rely on it being inside
+                * the range they asked for.
+                */
+               q->flush_rq->tag = first_rq->tag;
+       } else {
+               blk_rq_init(q, q->flush_rq);
        }
 
-       blk_rq_init(q, &q->flush_rq);
-       q->flush_rq.cmd_type = REQ_TYPE_FS;
-       q->flush_rq.cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
-       q->flush_rq.rq_disk = first_rq->rq_disk;
-       q->flush_rq.end_io = flush_end_io;
+       q->flush_rq->cmd_type = REQ_TYPE_FS;
+       q->flush_rq->cmd_flags = WRITE_FLUSH | REQ_FLUSH_SEQ;
+       q->flush_rq->rq_disk = first_rq->rq_disk;
+       q->flush_rq->end_io = flush_end_io;
 
-       list_add_tail(&q->flush_rq.queuelist, &q->queue_head);
-       return true;
+       return blk_flush_queue_rq(q->flush_rq, false);
 }
 
 static void flush_data_end_io(struct request *rq, int error)
@@ -437,7 +414,7 @@ void blk_insert_flush(struct request *rq)
        if ((policy & REQ_FSEQ_DATA) &&
            !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
                if (q->mq_ops) {
-                       blk_mq_run_request(rq, false, true);
+                       blk_mq_insert_request(rq, false, false, true);
                } else
                        list_add_tail(&rq->queuelist, &q->queue_head);
                return;
@@ -558,5 +535,4 @@ EXPORT_SYMBOL(blkdev_issue_flush);
 void blk_mq_init_flush(struct request_queue *q)
 {
        spin_lock_init(&q->mq_flush_lock);
-       INIT_WORK(&q->mq_flush_work, mq_flush_work);
 }
index 2da76c999ef3f37bd965f9d91b48dac43196a208..97a733cf3d5f925d1eede00d0dbca63f3565fd38 100644 (file)
@@ -119,6 +119,14 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
 
                atomic_inc(&bb.done);
                submit_bio(type, bio);
+
+               /*
+                * We can loop for a long time in here, if someone does
+                * full device discards (like mkfs). Be nice and allow
+                * us to schedule out to avoid softlocking if preempt
+                * is disabled.
+                */
+               cond_resched();
        }
        blk_finish_plug(&plug);
 
index 8f8adaa95466ccc8335cde7e313b551b375ed9b9..6c583f9c5b65d002a6ca357c53b19799f822f512 100644 (file)
@@ -21,6 +21,16 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
        if (!bio)
                return 0;
 
+       /*
+        * This should probably be returning 0, but blk_add_request_payload()
+        * (Christoph!!!!)
+        */
+       if (bio->bi_rw & REQ_DISCARD)
+               return 1;
+
+       if (bio->bi_rw & REQ_WRITE_SAME)
+               return 1;
+
        fbio = bio;
        cluster = blk_queue_cluster(q);
        seg_size = 0;
@@ -161,30 +171,60 @@ new_segment:
        *bvprv = *bvec;
 }
 
-/*
- * map a request to scatterlist, return number of sg entries setup. Caller
- * must make sure sg can hold rq->nr_phys_segments entries
- */
-int blk_rq_map_sg(struct request_queue *q, struct request *rq,
-                 struct scatterlist *sglist)
+static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
+                            struct scatterlist *sglist,
+                            struct scatterlist **sg)
 {
        struct bio_vec bvec, bvprv = { NULL };
-       struct req_iterator iter;
-       struct scatterlist *sg;
+       struct bvec_iter iter;
        int nsegs, cluster;
 
        nsegs = 0;
        cluster = blk_queue_cluster(q);
 
-       /*
-        * for each bio in rq
-        */
-       sg = NULL;
-       rq_for_each_segment(bvec, rq, iter) {
-               __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
-                                    &nsegs, &cluster);
-       } /* segments in rq */
+       if (bio->bi_rw & REQ_DISCARD) {
+               /*
+                * This is a hack - drivers should be neither modifying the
+                * biovec, nor relying on bi_vcnt - but because of
+                * blk_add_request_payload(), a discard bio may or may not have
+                * a payload we need to set up here (thank you Christoph) and
+                * bi_vcnt is really the only way of telling if we need to.
+                */
+
+               if (bio->bi_vcnt)
+                       goto single_segment;
+
+               return 0;
+       }
+
+       if (bio->bi_rw & REQ_WRITE_SAME) {
+single_segment:
+               *sg = sglist;
+               bvec = bio_iovec(bio);
+               sg_set_page(*sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
+               return 1;
+       }
+
+       for_each_bio(bio)
+               bio_for_each_segment(bvec, bio, iter)
+                       __blk_segment_map_sg(q, &bvec, sglist, &bvprv, sg,
+                                            &nsegs, &cluster);
 
+       return nsegs;
+}
+
+/*
+ * map a request to scatterlist, return number of sg entries setup. Caller
+ * must make sure sg can hold rq->nr_phys_segments entries
+ */
+int blk_rq_map_sg(struct request_queue *q, struct request *rq,
+                 struct scatterlist *sglist)
+{
+       struct scatterlist *sg = NULL;
+       int nsegs = 0;
+
+       if (rq->bio)
+               nsegs = __blk_bios_map_sg(q, rq->bio, sglist, &sg);
 
        if (unlikely(rq->cmd_flags & REQ_COPY_USER) &&
            (blk_rq_bytes(rq) & q->dma_pad_mask)) {
@@ -230,20 +270,13 @@ EXPORT_SYMBOL(blk_rq_map_sg);
 int blk_bio_map_sg(struct request_queue *q, struct bio *bio,
                   struct scatterlist *sglist)
 {
-       struct bio_vec bvec, bvprv = { NULL };
-       struct scatterlist *sg;
-       int nsegs, cluster;
-       struct bvec_iter iter;
-
-       nsegs = 0;
-       cluster = blk_queue_cluster(q);
-
-       sg = NULL;
-       bio_for_each_segment(bvec, bio, iter) {
-               __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
-                                    &nsegs, &cluster);
-       } /* segments in bio */
+       struct scatterlist *sg = NULL;
+       int nsegs;
+       struct bio *next = bio->bi_next;
+       bio->bi_next = NULL;
 
+       nsegs = __blk_bios_map_sg(q, bio, sglist, &sg);
+       bio->bi_next = next;
        if (sg)
                sg_mark_end(sg);
 
index 3146befb56aaac7b925428d0afee89c9e083094a..136ef8643bbade3dd2d5d84e35183c749bc00399 100644 (file)
@@ -11,7 +11,7 @@
 #include "blk-mq.h"
 
 static LIST_HEAD(blk_mq_cpu_notify_list);
-static DEFINE_SPINLOCK(blk_mq_cpu_notify_lock);
+static DEFINE_RAW_SPINLOCK(blk_mq_cpu_notify_lock);
 
 static int blk_mq_main_cpu_notify(struct notifier_block *self,
                                  unsigned long action, void *hcpu)
@@ -19,12 +19,12 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self,
        unsigned int cpu = (unsigned long) hcpu;
        struct blk_mq_cpu_notifier *notify;
 
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
 
        list_for_each_entry(notify, &blk_mq_cpu_notify_list, list)
                notify->notify(notify->data, action, cpu);
 
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
        return NOTIFY_OK;
 }
 
@@ -32,16 +32,16 @@ void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
        BUG_ON(!notifier->notify);
 
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
        list_add_tail(&notifier->list, &blk_mq_cpu_notify_list);
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
 }
 
 void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
-       spin_lock(&blk_mq_cpu_notify_lock);
+       raw_spin_lock(&blk_mq_cpu_notify_lock);
        list_del(&notifier->list);
-       spin_unlock(&blk_mq_cpu_notify_lock);
+       raw_spin_unlock(&blk_mq_cpu_notify_lock);
 }
 
 void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
index 5d70edc9855f7febabb4ebcb7f37ef23585d4b91..83ae96c51a2762cf7386f096e348eace58525e37 100644 (file)
@@ -184,7 +184,7 @@ void blk_mq_free_tags(struct blk_mq_tags *tags)
 ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
 {
        char *orig_page = page;
-       int cpu;
+       unsigned int cpu;
 
        if (!tags)
                return 0;
index 57039fcd9c93e7c3e014842fbbcaf2fc6550edd1..883f7208901585ab1ee02891a3ad5b67599a4243 100644 (file)
@@ -73,8 +73,8 @@ static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx,
                set_bit(ctx->index_hw, hctx->ctx_map);
 }
 
-static struct request *blk_mq_alloc_rq(struct blk_mq_hw_ctx *hctx, gfp_t gfp,
-                                      bool reserved)
+static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
+                                             gfp_t gfp, bool reserved)
 {
        struct request *rq;
        unsigned int tag;
@@ -193,12 +193,6 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
        ctx->rq_dispatched[rw_is_sync(rw_flags)]++;
 }
 
-static struct request *__blk_mq_alloc_request(struct blk_mq_hw_ctx *hctx,
-                                             gfp_t gfp, bool reserved)
-{
-       return blk_mq_alloc_rq(hctx, gfp, reserved);
-}
-
 static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
                                                   int rw, gfp_t gfp,
                                                   bool reserved)
@@ -226,15 +220,14 @@ static struct request *blk_mq_alloc_request_pinned(struct request_queue *q,
        return rq;
 }
 
-struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
-               gfp_t gfp, bool reserved)
+struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp)
 {
        struct request *rq;
 
        if (blk_mq_queue_enter(q))
                return NULL;
 
-       rq = blk_mq_alloc_request_pinned(q, rw, gfp, reserved);
+       rq = blk_mq_alloc_request_pinned(q, rw, gfp, false);
        if (rq)
                blk_mq_put_ctx(rq->mq_ctx);
        return rq;
@@ -258,7 +251,7 @@ EXPORT_SYMBOL(blk_mq_alloc_reserved_request);
 /*
  * Re-init and set pdu, if we have it
  */
-static void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq)
+void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq)
 {
        blk_rq_init(hctx->queue, rq);
 
@@ -290,38 +283,10 @@ void blk_mq_free_request(struct request *rq)
        __blk_mq_free_request(hctx, ctx, rq);
 }
 
-static void blk_mq_bio_endio(struct request *rq, struct bio *bio, int error)
-{
-       if (error)
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-               error = -EIO;
-
-       if (unlikely(rq->cmd_flags & REQ_QUIET))
-               set_bit(BIO_QUIET, &bio->bi_flags);
-
-       /* don't actually finish bio if it's part of flush sequence */
-       if (!(rq->cmd_flags & REQ_FLUSH_SEQ))
-               bio_endio(bio, error);
-}
-
-void blk_mq_complete_request(struct request *rq, int error)
+bool blk_mq_end_io_partial(struct request *rq, int error, unsigned int nr_bytes)
 {
-       struct bio *bio = rq->bio;
-       unsigned int bytes = 0;
-
-       trace_block_rq_complete(rq->q, rq);
-
-       while (bio) {
-               struct bio *next = bio->bi_next;
-
-               bio->bi_next = NULL;
-               bytes += bio->bi_iter.bi_size;
-               blk_mq_bio_endio(rq, bio, error);
-               bio = next;
-       }
-
-       blk_account_io_completion(rq, bytes);
+       if (blk_update_request(rq, error, blk_rq_bytes(rq)))
+               return true;
 
        blk_account_io_done(rq);
 
@@ -329,49 +294,57 @@ void blk_mq_complete_request(struct request *rq, int error)
                rq->end_io(rq, error);
        else
                blk_mq_free_request(rq);
+       return false;
 }
+EXPORT_SYMBOL(blk_mq_end_io_partial);
 
-void __blk_mq_end_io(struct request *rq, int error)
-{
-       if (!blk_mark_rq_complete(rq))
-               blk_mq_complete_request(rq, error);
-}
-
-static void blk_mq_end_io_remote(void *data)
+static void __blk_mq_complete_request_remote(void *data)
 {
        struct request *rq = data;
 
-       __blk_mq_end_io(rq, rq->errors);
+       rq->q->softirq_done_fn(rq);
 }
 
-/*
- * End IO on this request on a multiqueue enabled driver. We'll either do
- * it directly inline, or punt to a local IPI handler on the matching
- * remote CPU.
- */
-void blk_mq_end_io(struct request *rq, int error)
+void __blk_mq_complete_request(struct request *rq)
 {
        struct blk_mq_ctx *ctx = rq->mq_ctx;
        int cpu;
 
-       if (!ctx->ipi_redirect)
-               return __blk_mq_end_io(rq, error);
+       if (!ctx->ipi_redirect) {
+               rq->q->softirq_done_fn(rq);
+               return;
+       }
 
        cpu = get_cpu();
        if (cpu != ctx->cpu && cpu_online(ctx->cpu)) {
-               rq->errors = error;
-               rq->csd.func = blk_mq_end_io_remote;
+               rq->csd.func = __blk_mq_complete_request_remote;
                rq->csd.info = rq;
                rq->csd.flags = 0;
                __smp_call_function_single(ctx->cpu, &rq->csd, 0);
        } else {
-               __blk_mq_end_io(rq, error);
+               rq->q->softirq_done_fn(rq);
        }
        put_cpu();
 }
-EXPORT_SYMBOL(blk_mq_end_io);
 
-static void blk_mq_start_request(struct request *rq)
+/**
+ * blk_mq_complete_request - end I/O on a request
+ * @rq:                the request being processed
+ *
+ * Description:
+ *     Ends all I/O on a request. It does not handle partial completions.
+ *     The actual completion happens out-of-order, through a IPI handler.
+ **/
+void blk_mq_complete_request(struct request *rq)
+{
+       if (unlikely(blk_should_fake_timeout(rq->q)))
+               return;
+       if (!blk_mark_rq_complete(rq))
+               __blk_mq_complete_request(rq);
+}
+EXPORT_SYMBOL(blk_mq_complete_request);
+
+static void blk_mq_start_request(struct request *rq, bool last)
 {
        struct request_queue *q = rq->q;
 
@@ -384,6 +357,25 @@ static void blk_mq_start_request(struct request *rq)
         */
        rq->deadline = jiffies + q->rq_timeout;
        set_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
+
+       if (q->dma_drain_size && blk_rq_bytes(rq)) {
+               /*
+                * Make sure space for the drain appears.  We know we can do
+                * this because max_hw_segments has been adjusted to be one
+                * fewer than the device can handle.
+                */
+               rq->nr_phys_segments++;
+       }
+
+       /*
+        * Flag the last request in the series so that drivers know when IO
+        * should be kicked off, if they don't do it on a per-request basis.
+        *
+        * Note: the flag isn't the only condition drivers should do kick off.
+        * If drive is busy, the last request might not have the bit set.
+        */
+       if (last)
+               rq->cmd_flags |= REQ_END;
 }
 
 static void blk_mq_requeue_request(struct request *rq)
@@ -392,6 +384,11 @@ static void blk_mq_requeue_request(struct request *rq)
 
        trace_block_rq_requeue(q, rq);
        clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
+
+       rq->cmd_flags &= ~REQ_END;
+
+       if (q->dma_drain_size && blk_rq_bytes(rq))
+               rq->nr_phys_segments--;
 }
 
 struct blk_mq_timeout_data {
@@ -559,19 +556,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
 
                rq = list_first_entry(&rq_list, struct request, queuelist);
                list_del_init(&rq->queuelist);
-               blk_mq_start_request(rq);
 
-               /*
-                * Last request in the series. Flag it as such, this
-                * enables drivers to know when IO should be kicked off,
-                * if they don't do it on a per-request basis.
-                *
-                * Note: the flag isn't the only condition drivers
-                * should do kick off. If drive is busy, the last
-                * request might not have the bit set.
-                */
-               if (list_empty(&rq_list))
-                       rq->cmd_flags |= REQ_END;
+               blk_mq_start_request(rq, list_empty(&rq_list));
 
                ret = q->mq_ops->queue_rq(hctx, rq);
                switch (ret) {
@@ -589,8 +575,8 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)
                        break;
                default:
                        pr_err("blk-mq: bad return on queue: %d\n", ret);
-                       rq->errors = -EIO;
                case BLK_MQ_RQ_QUEUE_ERROR:
+                       rq->errors = -EIO;
                        blk_mq_end_io(rq, rq->errors);
                        break;
                }
@@ -693,13 +679,16 @@ static void blk_mq_work_fn(struct work_struct *work)
 }
 
 static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
-                                   struct request *rq)
+                                   struct request *rq, bool at_head)
 {
        struct blk_mq_ctx *ctx = rq->mq_ctx;
 
        trace_block_rq_insert(hctx->queue, rq);
 
-       list_add_tail(&rq->queuelist, &ctx->rq_list);
+       if (at_head)
+               list_add(&rq->queuelist, &ctx->rq_list);
+       else
+               list_add_tail(&rq->queuelist, &ctx->rq_list);
        blk_mq_hctx_mark_pending(hctx, ctx);
 
        /*
@@ -708,61 +697,28 @@ static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx,
        blk_mq_add_timer(rq);
 }
 
-void blk_mq_insert_request(struct request_queue *q, struct request *rq,
-                          bool run_queue)
+void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue,
+               bool async)
 {
+       struct request_queue *q = rq->q;
        struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx, *current_ctx;
+       struct blk_mq_ctx *ctx = rq->mq_ctx, *current_ctx;
+
+       current_ctx = blk_mq_get_ctx(q);
+       if (!cpu_online(ctx->cpu))
+               rq->mq_ctx = ctx = current_ctx;
 
-       ctx = rq->mq_ctx;
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
-       if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
+       if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA) &&
+           !(rq->cmd_flags & (REQ_FLUSH_SEQ))) {
                blk_insert_flush(rq);
        } else {
-               current_ctx = blk_mq_get_ctx(q);
-
-               if (!cpu_online(ctx->cpu)) {
-                       ctx = current_ctx;
-                       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-                       rq->mq_ctx = ctx;
-               }
                spin_lock(&ctx->lock);
-               __blk_mq_insert_request(hctx, rq);
+               __blk_mq_insert_request(hctx, rq, at_head);
                spin_unlock(&ctx->lock);
-
-               blk_mq_put_ctx(current_ctx);
        }
 
-       if (run_queue)
-               __blk_mq_run_hw_queue(hctx);
-}
-EXPORT_SYMBOL(blk_mq_insert_request);
-
-/*
- * This is a special version of blk_mq_insert_request to bypass FLUSH request
- * check. Should only be used internally.
- */
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async)
-{
-       struct request_queue *q = rq->q;
-       struct blk_mq_hw_ctx *hctx;
-       struct blk_mq_ctx *ctx, *current_ctx;
-
-       current_ctx = blk_mq_get_ctx(q);
-
-       ctx = rq->mq_ctx;
-       if (!cpu_online(ctx->cpu)) {
-               ctx = current_ctx;
-               rq->mq_ctx = ctx;
-       }
-       hctx = q->mq_ops->map_queue(q, ctx->cpu);
-
-       /* ctx->cpu might be offline */
-       spin_lock(&ctx->lock);
-       __blk_mq_insert_request(hctx, rq);
-       spin_unlock(&ctx->lock);
-
        blk_mq_put_ctx(current_ctx);
 
        if (run_queue)
@@ -798,7 +754,7 @@ static void blk_mq_insert_requests(struct request_queue *q,
                rq = list_first_entry(list, struct request, queuelist);
                list_del_init(&rq->queuelist);
                rq->mq_ctx = ctx;
-               __blk_mq_insert_request(hctx, rq);
+               __blk_mq_insert_request(hctx, rq, false);
        }
        spin_unlock(&ctx->lock);
 
@@ -888,6 +844,11 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
 
        blk_queue_bounce(q, &bio);
 
+       if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
+               bio_endio(bio, -EIO);
+               return;
+       }
+
        if (use_plug && blk_attempt_plug_merge(q, bio, &request_count))
                return;
 
@@ -899,6 +860,8 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
        ctx = blk_mq_get_ctx(q);
        hctx = q->mq_ops->map_queue(q, ctx->cpu);
 
+       if (is_sync)
+               rw |= REQ_SYNC;
        trace_block_getrq(q, bio, rw);
        rq = __blk_mq_alloc_request(hctx, GFP_ATOMIC, false);
        if (likely(rq))
@@ -950,7 +913,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
                __blk_mq_free_request(hctx, ctx, rq);
        else {
                blk_mq_bio_to_request(rq, bio);
-               __blk_mq_insert_request(hctx, rq);
+               __blk_mq_insert_request(hctx, rq, false);
        }
 
        spin_unlock(&ctx->lock);
@@ -1309,15 +1272,6 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
                reg->queue_depth = BLK_MQ_MAX_DEPTH;
        }
 
-       /*
-        * Set aside a tag for flush requests.  It will only be used while
-        * another flush request is in progress but outside the driver.
-        *
-        * TODO: only allocate if flushes are supported
-        */
-       reg->queue_depth++;
-       reg->reserved_tags++;
-
        if (reg->queue_depth < (reg->reserved_tags + BLK_MQ_TAG_MIN))
                return ERR_PTR(-EINVAL);
 
@@ -1360,17 +1314,27 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
        q->mq_ops = reg->ops;
        q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT;
 
+       q->sg_reserved_size = INT_MAX;
+
        blk_queue_make_request(q, blk_mq_make_request);
        blk_queue_rq_timed_out(q, reg->ops->timeout);
        if (reg->timeout)
                blk_queue_rq_timeout(q, reg->timeout);
 
+       if (reg->ops->complete)
+               blk_queue_softirq_done(q, reg->ops->complete);
+
        blk_mq_init_flush(q);
        blk_mq_init_cpu_queues(q, reg->nr_hw_queues);
 
-       if (blk_mq_init_hw_queues(q, reg, driver_data))
+       q->flush_rq = kzalloc(round_up(sizeof(struct request) + reg->cmd_size,
+                               cache_line_size()), GFP_KERNEL);
+       if (!q->flush_rq)
                goto err_hw;
 
+       if (blk_mq_init_hw_queues(q, reg, driver_data))
+               goto err_flush_rq;
+
        blk_mq_map_swqueue(q);
 
        mutex_lock(&all_q_mutex);
@@ -1378,6 +1342,9 @@ struct request_queue *blk_mq_init_queue(struct blk_mq_reg *reg,
        mutex_unlock(&all_q_mutex);
 
        return q;
+
+err_flush_rq:
+       kfree(q->flush_rq);
 err_hw:
        kfree(q->mq_map);
 err_map:
index 5c3917984b005f13ea35254074744ec91f2e5bd3..72beba1f9d55efa827e8667535a7f2956dd2b924 100644 (file)
@@ -22,13 +22,12 @@ struct blk_mq_ctx {
        struct kobject          kobj;
 };
 
-void __blk_mq_end_io(struct request *rq, int error);
-void blk_mq_complete_request(struct request *rq, int error);
-void blk_mq_run_request(struct request *rq, bool run_queue, bool async);
+void __blk_mq_complete_request(struct request *rq);
 void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
 void blk_mq_init_flush(struct request_queue *q);
 void blk_mq_drain_queue(struct request_queue *q);
 void blk_mq_free_queue(struct request_queue *q);
+void blk_mq_rq_init(struct blk_mq_hw_ctx *hctx, struct request *rq);
 
 /*
  * CPU hotplug helpers
index 8095c4a21fc0f53e6e46ff191de283500dcc97de..7500f876dae40e0b124b90adab21c60c1e3676b6 100644 (file)
@@ -549,6 +549,8 @@ static void blk_release_queue(struct kobject *kobj)
        if (q->mq_ops)
                blk_mq_free_queue(q);
 
+       kfree(q->flush_rq);
+
        blk_trace_shutdown(q);
 
        bdi_destroy(&q->backing_dev_info);
index bba81c9348e1cca630fc9d2515f27633d997c03a..d96f7061c6fd8727de9eb9fc02fae7b07dd357c1 100644 (file)
@@ -91,7 +91,7 @@ static void blk_rq_timed_out(struct request *req)
        case BLK_EH_HANDLED:
                /* Can we use req->errors here? */
                if (q->mq_ops)
-                       blk_mq_complete_request(req, req->errors);
+                       __blk_mq_complete_request(req);
                else
                        __blk_complete_request(req);
                break;
index c90e1d8f7a2b39466d91a9e1881bd16a0f71b2b9..d23b415b8a28f90e0ff83c713e0c2677a1e00f96 100644 (file)
@@ -113,7 +113,7 @@ static inline struct request *__elv_next_request(struct request_queue *q)
                        q->flush_queue_delayed = 1;
                        return NULL;
                }
-               if (unlikely(blk_queue_dying(q)) ||
+               if (unlikely(blk_queue_bypass(q)) ||
                    !q->elevator->type->ops.elevator_dispatch_fn(q, 0))
                        return NULL;
        }
index e7515aa43d6bd62c3ec0e33fb6781d2a9f2f27a7..6f190bc2b8b784bf7e09425b77c560fa60f04b90 100644 (file)
@@ -243,6 +243,8 @@ static int acpi_ac_resume(struct device *dev)
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
        return 0;
 }
+#else
+#define acpi_ac_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume);
 
index 018a4288370630cb40203ecd43cc2809851288ae..797a6938d0515edb7ce7e5ce3f4f1648c538e515 100644 (file)
@@ -841,6 +841,8 @@ static int acpi_battery_resume(struct device *dev)
        acpi_battery_update(battery);
        return 0;
 }
+#else
+#define acpi_battery_resume NULL
 #endif
 
 static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
index 10e4964d051a9c295e6185db1cfebe20b0ce5a9d..afec4526c48aa04e2921a199396e8fb2ea7489be 100644 (file)
@@ -260,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
        },
        {
        .callback = dmi_disable_osi_win8,
-       .ident = "Dell Inspiron 15R SE",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
        .ident = "ThinkPad Edge E530",
        .matches = {
                     DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -322,56 +314,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
                     DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"),
                },
        },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ProBook 2013 models",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
-                    DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP EliteBook 2013 models",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
-                    DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ZBook 14",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ZBook 15",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP ZBook 17",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
-               },
-       },
-       {
-       .callback = dmi_disable_osi_win8,
-       .ident = "HP EliteBook 8780w",
-       .matches = {
-                    DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-                    DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
-               },
-       },
 
        /*
         * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.
index 11c11f6b8fa1453a4a28c3931f0cf8618750fecc..714e957a871a8034ed18be2104b8c107d0b4ced9 100644 (file)
@@ -80,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_button_resume(struct device *dev);
+#else
+#define acpi_button_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
 
index 0b6ae6eb5c4a8f3dad1a40ec4c2f9f6928322b09..368f9ddb8480777420b2d5633facfeb238db1e27 100644 (file)
@@ -79,9 +79,10 @@ static int container_device_attach(struct acpi_device *adev,
        ACPI_COMPANION_SET(dev, adev);
        dev->release = acpi_container_release;
        ret = device_register(dev);
-       if (ret)
+       if (ret) {
+               put_device(dev);
                return ret;
-
+       }
        adev->driver_data = dev;
        return 1;
 }
index c431c88faaffa1f46f4d1e1b4de042f3314a2b9f..5bfd769fc91fa5bfd0890a146a4eed13ac342ff0 100644 (file)
@@ -609,7 +609,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
 static void dock_notify(struct dock_station *ds, u32 event)
 {
        acpi_handle handle = ds->handle;
-       struct acpi_device *ad;
+       struct acpi_device *adev = NULL;
        int surprise_removal = 0;
 
        /*
@@ -632,7 +632,8 @@ static void dock_notify(struct dock_station *ds, u32 event)
        switch (event) {
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
-               if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
+               acpi_bus_get_device(handle, &adev);
+               if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
                        begin_dock(ds);
                        dock(ds);
                        if (!dock_present(ds)) {
@@ -712,13 +713,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl,
 static ssize_t show_docked(struct device *dev,
                           struct device_attribute *attr, char *buf)
 {
-       struct acpi_device *tmp;
-
        struct dock_station *dock_station = dev->platform_data;
+       struct acpi_device *adev = NULL;
 
-       if (!acpi_bus_get_device(dock_station->handle, &tmp))
-               return snprintf(buf, PAGE_SIZE, "1\n");
-       return snprintf(buf, PAGE_SIZE, "0\n");
+       acpi_bus_get_device(dock_station->handle, &adev);
+       return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev));
 }
 static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 
index 959d41acc108a847308773f754fdb4fff3b1fd26..d7d32c28829b17834507bf8683f2c2a5c77d0a0d 100644 (file)
@@ -67,6 +67,8 @@ enum ec_command {
 #define ACPI_EC_DELAY          500     /* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
 #define ACPI_EC_MSI_UDELAY     550     /* Wait 550us for MSI EC */
+#define ACPI_EC_CLEAR_MAX      100     /* Maximum number of events to query
+                                        * when trying to clear the EC */
 
 enum {
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
@@ -116,6 +118,7 @@ EXPORT_SYMBOL(first_ec);
 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
 static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
+static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
 
 /* --------------------------------------------------------------------------
                              Transaction Management
@@ -440,6 +443,29 @@ acpi_handle ec_get_handle(void)
 
 EXPORT_SYMBOL(ec_get_handle);
 
+static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data);
+
+/*
+ * Clears stale _Q events that might have accumulated in the EC.
+ * Run with locked ec mutex.
+ */
+static void acpi_ec_clear(struct acpi_ec *ec)
+{
+       int i, status;
+       u8 value = 0;
+
+       for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
+               status = acpi_ec_query_unlocked(ec, &value);
+               if (status || !value)
+                       break;
+       }
+
+       if (unlikely(i == ACPI_EC_CLEAR_MAX))
+               pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
+       else
+               pr_info("%d stale EC events cleared\n", i);
+}
+
 void acpi_ec_block_transactions(void)
 {
        struct acpi_ec *ec = first_ec;
@@ -463,6 +489,10 @@ void acpi_ec_unblock_transactions(void)
        mutex_lock(&ec->mutex);
        /* Allow transactions to be carried out again */
        clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+
+       if (EC_FLAGS_CLEAR_ON_RESUME)
+               acpi_ec_clear(ec);
+
        mutex_unlock(&ec->mutex);
 }
 
@@ -821,6 +851,13 @@ static int acpi_ec_add(struct acpi_device *device)
 
        /* EC is fully operational, allow queries */
        clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+
+       /* Clear stale _Q events if hardware might require that */
+       if (EC_FLAGS_CLEAR_ON_RESUME) {
+               mutex_lock(&ec->mutex);
+               acpi_ec_clear(ec);
+               mutex_unlock(&ec->mutex);
+       }
        return ret;
 }
 
@@ -922,6 +959,30 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
        return 0;
 }
 
+/*
+ * On some hardware it is necessary to clear events accumulated by the EC during
+ * sleep. These ECs stop reporting GPEs until they are manually polled, if too
+ * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=44161
+ *
+ * Ideally, the EC should also be instructed NOT to accumulate events during
+ * sleep (which Windows seems to do somehow), but the interface to control this
+ * behaviour is not known at this time.
+ *
+ * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
+ * however it is very likely that other Samsung models are affected.
+ *
+ * On systems which don't accumulate _Q events during sleep, this extra check
+ * should be harmless.
+ */
+static int ec_clear_on_resume(const struct dmi_system_id *id)
+{
+       pr_debug("Detected system needing EC poll on resume.\n");
+       EC_FLAGS_CLEAR_ON_RESUME = 1;
+       return 0;
+}
+
 static struct dmi_system_id ec_dmi_table[] __initdata = {
        {
        ec_skip_dsdt_scan, "Compal JFL92", {
@@ -965,6 +1026,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTek Computer Inc."),
        DMI_MATCH(DMI_PRODUCT_NAME, "L4R"),}, NULL},
+       {
+       ec_clear_on_resume, "Samsung hardware", {
+       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
        {},
 };
 
index 1fb62900f32a9c57d329fd3e5480bc0dc7c305b8..09e423f3d8ad30fbd16d2d2b2e2766e69e64de82 100644 (file)
@@ -55,6 +55,9 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids);
 #ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev);
 static int acpi_fan_resume(struct device *dev);
+#else
+#define acpi_fan_suspend NULL
+#define acpi_fan_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
 
index 52d45ea2bc4f63efcfb7e8912b087b1a568d49cc..361b40c10c3f522e28e2b334dd5f8976109bc772 100644 (file)
@@ -430,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
                                 pin_name(pin));
                }
 
+               kfree(entry);
                return 0;
        }
 
index 28baa05b8018dd6c6e6e1db93c1a5ceed74d4d74..84243c32e29c515381634b6e7b2cc6f4d219635b 100644 (file)
@@ -56,6 +56,12 @@ struct throttling_tstate {
        int target_state;               /* target T-state */
 };
 
+struct acpi_processor_throttling_arg {
+       struct acpi_processor *pr;
+       int target_state;
+       bool force;
+};
+
 #define THROTTLING_PRECHANGE       (1)
 #define THROTTLING_POSTCHANGE      (2)
 
@@ -1060,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
        return 0;
 }
 
+static long acpi_processor_throttling_fn(void *data)
+{
+       struct acpi_processor_throttling_arg *arg = data;
+       struct acpi_processor *pr = arg->pr;
+
+       return pr->throttling.acpi_processor_set_throttling(pr,
+                       arg->target_state, arg->force);
+}
+
 int acpi_processor_set_throttling(struct acpi_processor *pr,
                                                int state, bool force)
 {
-       cpumask_var_t saved_mask;
        int ret = 0;
        unsigned int i;
        struct acpi_processor *match_pr;
        struct acpi_processor_throttling *p_throttling;
+       struct acpi_processor_throttling_arg arg;
        struct throttling_tstate t_state;
-       cpumask_var_t online_throttling_cpus;
 
        if (!pr)
                return -EINVAL;
@@ -1080,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
        if ((state < 0) || (state > (pr->throttling.state_count - 1)))
                return -EINVAL;
 
-       if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL))
-               return -ENOMEM;
-
-       if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) {
-               free_cpumask_var(saved_mask);
-               return -ENOMEM;
-       }
-
        if (cpu_is_offline(pr->id)) {
                /*
                 * the cpu pointed by pr->id is offline. Unnecessary to change
@@ -1096,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
                return -ENODEV;
        }
 
-       cpumask_copy(saved_mask, &current->cpus_allowed);
        t_state.target_state = state;
        p_throttling = &(pr->throttling);
-       cpumask_and(online_throttling_cpus, cpu_online_mask,
-                   p_throttling->shared_cpu_map);
+
        /*
         * The throttling notifier will be called for every
         * affected cpu in order to get one proper T-state.
         * The notifier event is THROTTLING_PRECHANGE.
         */
-       for_each_cpu(i, online_throttling_cpus) {
+       for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
                t_state.cpu = i;
                acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
                                                        &t_state);
@@ -1118,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
         * it can be called only for the cpu pointed by pr.
         */
        if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
-               /* FIXME: use work_on_cpu() */
-               if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) {
-                       /* Can't migrate to the pr->id CPU. Exit */
-                       ret = -ENODEV;
-                       goto exit;
-               }
-               ret = p_throttling->acpi_processor_set_throttling(pr,
-                                               t_state.target_state, force);
+               arg.pr = pr;
+               arg.target_state = state;
+               arg.force = force;
+               ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg);
        } else {
                /*
                 * When the T-state coordination is SW_ALL or HW_ALL,
                 * it is necessary to set T-state for every affected
                 * cpus.
                 */
-               for_each_cpu(i, online_throttling_cpus) {
+               for_each_cpu_and(i, cpu_online_mask,
+                   p_throttling->shared_cpu_map) {
                        match_pr = per_cpu(processors, i);
                        /*
                         * If the pointer is invalid, we will report the
@@ -1153,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
                                        "on CPU %d\n", i));
                                continue;
                        }
-                       t_state.cpu = i;
-                       /* FIXME: use work_on_cpu() */
-                       if (set_cpus_allowed_ptr(current, cpumask_of(i)))
-                               continue;
-                       ret = match_pr->throttling.
-                               acpi_processor_set_throttling(
-                               match_pr, t_state.target_state, force);
+
+                       arg.pr = match_pr;
+                       arg.target_state = state;
+                       arg.force = force;
+                       ret = work_on_cpu(pr->id, acpi_processor_throttling_fn,
+                               &arg);
                }
        }
        /*
@@ -1168,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr,
         * affected cpu to update the T-states.
         * The notifier event is THROTTLING_POSTCHANGE
         */
-       for_each_cpu(i, online_throttling_cpus) {
+       for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) {
                t_state.cpu = i;
                acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
                                                        &t_state);
        }
-       /* restore the previous state */
-       /* FIXME: use work_on_cpu() */
-       set_cpus_allowed_ptr(current, saved_mask);
-exit:
-       free_cpumask_var(online_throttling_cpus);
-       free_cpumask_var(saved_mask);
+
        return ret;
 }
 
index b7201fc6f1e19c06c798889900c1e9c689494c8d..0bdacc5e26a3b9411b82a5fe4772c2c9f9b7d490 100644 (file)
@@ -77,18 +77,24 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
        switch (ares->type) {
        case ACPI_RESOURCE_TYPE_MEMORY24:
                memory24 = &ares->data.memory24;
+               if (!memory24->address_length)
+                       return false;
                acpi_dev_get_memresource(res, memory24->minimum,
                                         memory24->address_length,
                                         memory24->write_protect);
                break;
        case ACPI_RESOURCE_TYPE_MEMORY32:
                memory32 = &ares->data.memory32;
+               if (!memory32->address_length)
+                       return false;
                acpi_dev_get_memresource(res, memory32->minimum,
                                         memory32->address_length,
                                         memory32->write_protect);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
                fixed_memory32 = &ares->data.fixed_memory32;
+               if (!fixed_memory32->address_length)
+                       return false;
                acpi_dev_get_memresource(res, fixed_memory32->address,
                                         fixed_memory32->address_length,
                                         fixed_memory32->write_protect);
@@ -144,12 +150,16 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
        switch (ares->type) {
        case ACPI_RESOURCE_TYPE_IO:
                io = &ares->data.io;
+               if (!io->address_length)
+                       return false;
                acpi_dev_get_ioresource(res, io->minimum,
                                        io->address_length,
                                        io->io_decode);
                break;
        case ACPI_RESOURCE_TYPE_FIXED_IO:
                fixed_io = &ares->data.fixed_io;
+               if (!fixed_io->address_length)
+                       return false;
                acpi_dev_get_ioresource(res, fixed_io->address,
                                        fixed_io->address_length,
                                        ACPI_DECODE_10);
index d465ae6cdd004b9813cc333529c54ef29abcb16f..dbd48498b93863a1fa37ab0b23706f2dae89345d 100644 (file)
@@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev,
 {
        unsigned long x;
        struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
-       if (sscanf(buf, "%ld\n", &x) == 1)
+       if (sscanf(buf, "%lu\n", &x) == 1)
                battery->alarm_capacity = x /
                        (1000 * acpi_battery_scale(battery));
        if (battery->present)
@@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev)
        acpi_sbs_callback(sbs);
        return 0;
 }
+#else
+#define acpi_sbs_resume NULL
 #endif
 
 static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
index b718806657cdac29d9ccb3a1cad3fe6528865176..c40fb2e81bbc5d4ce9266174c0c2d7614755c644 100644 (file)
@@ -71,6 +71,17 @@ static int acpi_sleep_prepare(u32 acpi_state)
        return 0;
 }
 
+static bool acpi_sleep_state_supported(u8 sleep_state)
+{
+       acpi_status status;
+       u8 type_a, type_b;
+
+       status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
+       return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
+               || (acpi_gbl_FADT.sleep_control.address
+                       && acpi_gbl_FADT.sleep_status.address));
+}
+
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
 
@@ -604,15 +615,9 @@ static void acpi_sleep_suspend_setup(void)
 {
        int i;
 
-       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
-               acpi_status status;
-               u8 type_a, type_b;
-
-               status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-               if (ACPI_SUCCESS(status)) {
+       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
+               if (acpi_sleep_state_supported(i))
                        sleep_states[i] = 1;
-               }
-       }
 
        suspend_set_ops(old_suspend_ordering ?
                &acpi_suspend_ops_old : &acpi_suspend_ops);
@@ -740,11 +745,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
 
 static void acpi_sleep_hibernate_setup(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
-
-       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-       if (ACPI_FAILURE(status))
+       if (!acpi_sleep_state_supported(ACPI_STATE_S4))
                return;
 
        hibernation_set_ops(old_suspend_ordering ?
@@ -793,8 +794,6 @@ static void acpi_power_off(void)
 
 int __init acpi_sleep_init(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
        char supported[ACPI_S_STATE_COUNT * 3 + 1];
        char *pos = supported;
        int i;
@@ -806,8 +805,7 @@ int __init acpi_sleep_init(void)
        acpi_sleep_suspend_setup();
        acpi_sleep_hibernate_setup();
 
-       status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
                sleep_states[ACPI_STATE_S5] = 1;
                pm_power_off_prepare = acpi_power_off_prepare;
                pm_power_off = acpi_power_off;
index 8349a555b92b8aa6d6584f9c2c5c9ccf7a27737f..08626c851be7eef72c5a639522b708586736adc5 100644 (file)
@@ -102,6 +102,8 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_thermal_resume(struct device *dev);
+#else
+#define acpi_thermal_resume NULL
 #endif
 static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
 
index b727d105046d234ae8ef2a5669e53e61b82e7123..b6ba88ed31aeeb1854e48bb73b95fc59a4d58706 100644 (file)
@@ -81,11 +81,12 @@ static bool allow_duplicates;
 module_param(allow_duplicates, bool, 0644);
 
 /*
- * For Windows 8 systems: if set ture and the GPU driver has
- * registered a backlight interface, skip registering ACPI video's.
+ * For Windows 8 systems: used to decide if video module
+ * should skip registering backlight interface of its own.
  */
-static bool use_native_backlight = false;
-module_param(use_native_backlight, bool, 0644);
+static int use_native_backlight_param = -1;
+module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
+static bool use_native_backlight_dmi = false;
 
 static int register_count;
 static struct mutex video_list_lock;
@@ -231,9 +232,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
 static int acpi_video_switch_brightness(struct acpi_video_device *device,
                                         int event);
 
+static bool acpi_video_use_native_backlight(void)
+{
+       if (use_native_backlight_param != -1)
+               return use_native_backlight_param;
+       else
+               return use_native_backlight_dmi;
+}
+
 static bool acpi_video_verify_backlight_support(void)
 {
-       if (acpi_osi_is_win8() && use_native_backlight &&
+       if (acpi_osi_is_win8() && acpi_video_use_native_backlight() &&
            backlight_device_registered(BACKLIGHT_RAW))
                return false;
        return acpi_video_backlight_support();
@@ -398,6 +407,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d)
        return 0;
 }
 
+static int __init video_set_use_native_backlight(const struct dmi_system_id *d)
+{
+       use_native_backlight_dmi = true;
+       return 0;
+}
+
 static struct dmi_system_id video_dmi_table[] __initdata = {
        /*
         * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -442,6 +457,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
                },
        },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "ThinkPad T430s",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "ThinkPad X230",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "ThinkPad X1 Carbon",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Lenovo Yoga 13",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Dell Inspiron 7520",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Acer Aspire 5733Z",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"),
+               },
+       },
+       {
+        .callback = video_set_use_native_backlight,
+        .ident = "Acer Aspire V5-431",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ProBook 4340s",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ProBook 2013 models",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "),
+               DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP EliteBook 2013 models",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "),
+               DMI_MATCH(DMI_PRODUCT_NAME, " G1"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ZBook 14",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ZBook 15",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP ZBook 17",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"),
+               },
+       },
+       {
+       .callback = video_set_use_native_backlight,
+       .ident = "HP EliteBook 8780w",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
+               },
+       },
        {}
 };
 
@@ -685,6 +814,7 @@ acpi_video_init_brightness(struct acpi_video_device *device)
        union acpi_object *o;
        struct acpi_video_device_brightness *br = NULL;
        int result = -EINVAL;
+       u32 value;
 
        if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
@@ -715,7 +845,12 @@ acpi_video_init_brightness(struct acpi_video_device *device)
                        printk(KERN_ERR PREFIX "Invalid data\n");
                        continue;
                }
-               br->levels[count] = (u32) o->integer.value;
+               value = (u32) o->integer.value;
+               /* Skip duplicate entries */
+               if (count > 2 && br->levels[count - 1] == value)
+                       continue;
+
+               br->levels[count] = value;
 
                if (br->levels[count] > max_level)
                        max_level = br->levels[count];
index a697b77b8865a163cd23fe591db0242631ca742f..19080c8e2f2a9c6d5df7f5475d581f5348ed9e8e 100644 (file)
@@ -168,22 +168,6 @@ static struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"),
                },
        },
-       {
-       .callback = video_detect_force_vendor,
-       .ident = "HP EliteBook Revolve 810",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Revolve 810 G1"),
-               },
-       },
-       {
-       .callback = video_detect_force_vendor,
-       .ident = "Lenovo Yoga 13",
-       .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"),
-               },
-       },
        { },
 };
 
index 4e737728aee207a5d644d6fa0d39b0e3c402bd47..868429a47be41a2c50ff146389df25dfcb8f5b30 100644 (file)
@@ -247,6 +247,7 @@ config SATA_HIGHBANK
 
 config SATA_MV
        tristate "Marvell SATA support"
+       select GENERIC_PHY
        help
          This option enables support for the Marvell Serial ATA family.
          Currently supports 88SX[56]0[48][01] PCI(-X) chips,
index dc2756fb6f3369b95cdb015fb8b32f97ff64d887..c81d809c111b238e72f65d185add59f5bef4fade 100644 (file)
@@ -61,6 +61,7 @@ enum board_ids {
        /* board IDs by feature in alphabetical order */
        board_ahci,
        board_ahci_ign_iferr,
+       board_ahci_noncq,
        board_ahci_nosntf,
        board_ahci_yes_fbs,
 
@@ -121,6 +122,13 @@ static const struct ata_port_info ahci_port_info[] = {
                .udma_mask      = ATA_UDMA6,
                .port_ops       = &ahci_ops,
        },
+       [board_ahci_noncq] = {
+               AHCI_HFLAGS     (AHCI_HFLAG_NO_NCQ),
+               .flags          = AHCI_FLAG_COMMON,
+               .pio_mask       = ATA_PIO4,
+               .udma_mask      = ATA_UDMA6,
+               .port_ops       = &ahci_ops,
+       },
        [board_ahci_nosntf] = {
                AHCI_HFLAGS     (AHCI_HFLAG_NO_SNTF),
                .flags          = AHCI_FLAG_COMMON,
@@ -452,6 +460,12 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci },   /* ASM1061 */
        { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci },   /* ASM1062 */
 
+       /*
+        * Samsung SSDs found on some macbooks.  NCQ times out.
+        * https://bugzilla.kernel.org/show_bug.cgi?id=60731
+        */
+       { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq },
+
        /* Enmotus */
        { PCI_DEVICE(0x1c44, 0x8000), board_ahci },
 
@@ -1170,8 +1184,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
 
        nvec = rc;
        rc = pci_enable_msi_block(pdev, nvec);
-       if (rc)
+       if (rc < 0)
                goto intx;
+       else if (rc > 0)
+               goto single_msi;
 
        return nvec;
 
index 1a3dbd1b196ecb121b1ee9d34388ecd00c307b71..8cb2522d592ac87f7b144f1f41d244cd5df777dc 100644 (file)
@@ -4175,6 +4175,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* Seagate Momentus SpinPoint M8 seem to have FPMDA_AA issues */
        { "ST1000LM024 HN-M101MBB", "2AR10001", ATA_HORKAGE_BROKEN_FPDMA_AA },
+       { "ST1000LM024 HN-M101MBB", "2BA30001", ATA_HORKAGE_BROKEN_FPDMA_AA },
 
        /* Blacklist entries taken from Silicon Image 3124/3132
           Windows driver .inf file - also several Linux problem reports */
@@ -4224,7 +4225,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
 
        /* devices that don't properly handle queued TRIM commands */
        { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT???M500SSD1",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Crucial_CT???M500SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
 
        /*
         * Some WD SATA-I drives spin up and down erratically when the link
index 20fd337a57314a2928c9208bf706ffabed0c4dd5..7ccc084bf1dfb8f7b979f5e7ae777e030303d1b8 100644 (file)
@@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap)
                 * otherwise.  Don't try hard to recover it.
                 */
                ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
-       } else if (vendor == 0x197b && devid == 0x2352) {
-               /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */
+       } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
+               /*
+                * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
+                * 0x0325: jmicron JMB394.
+                */
                ata_for_each_link(link, ap, EDGE) {
                        /* SRST breaks detection and disks get misclassified
                         * LPM disabled to avoid potential problems
index 26386f0b89a8f4583c397ca9da154a9c499c6d2f..b0b18ec5465ffe32bae62d11f97d1b0cba8c313c 100644 (file)
@@ -119,7 +119,9 @@ static int pata_imx_probe(struct platform_device *pdev)
                return PTR_ERR(priv->clk);
        }
 
-       clk_prepare_enable(priv->clk);
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
 
        host = ata_host_alloc(&pdev->dev, 1);
        if (!host) {
@@ -212,7 +214,9 @@ static int pata_imx_resume(struct device *dev)
        struct ata_host *host = dev_get_drvdata(dev);
        struct pata_imx_priv *priv = host->private_data;
 
-       clk_prepare_enable(priv->clk);
+       int ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return ret;
 
        __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL);
 
index 20a7517bd3393d1a2adfcb6e4cb55afcd833e5f9..05c8a44adf8edea590ec983a7f843c1f5b6b1b55 100644 (file)
@@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev)
        if (!hpriv->port_phys)
                return -ENOMEM;
        host->private_data = hpriv;
-       hpriv->n_ports = n_ports;
        hpriv->board_idx = chip_soc;
 
        host->iomap = NULL;
@@ -4126,17 +4125,24 @@ static int mv_platform_probe(struct platform_device *pdev)
                        clk_prepare_enable(hpriv->port_clks[port]);
 
                sprintf(port_number, "port%d", port);
-               hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number);
+               hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev,
+                                                              port_number);
                if (IS_ERR(hpriv->port_phys[port])) {
                        rc = PTR_ERR(hpriv->port_phys[port]);
                        hpriv->port_phys[port] = NULL;
-                       if ((rc != -EPROBE_DEFER) && (rc != -ENODEV))
-                               dev_warn(&pdev->dev, "error getting phy");
+                       if (rc != -EPROBE_DEFER)
+                               dev_warn(&pdev->dev, "error getting phy %d", rc);
+
+                       /* Cleanup only the initialized ports */
+                       hpriv->n_ports = port;
                        goto err;
                } else
                        phy_power_on(hpriv->port_phys[port]);
        }
 
+       /* All the ports have been initialized */
+       hpriv->n_ports = n_ports;
+
        /*
         * (Re-)program MBUS remapping windows if we are asked to.
         */
@@ -4174,7 +4180,7 @@ err:
                clk_disable_unprepare(hpriv->clk);
                clk_put(hpriv->clk);
        }
-       for (port = 0; port < n_ports; port++) {
+       for (port = 0; port < hpriv->n_ports; port++) {
                if (!IS_ERR(hpriv->port_clks[port])) {
                        clk_disable_unprepare(hpriv->port_clks[port]);
                        clk_put(hpriv->port_clks[port]);
index d67fc351343ca841f7ea95b68e401f52f58953c2..b7695e804635b87c0d7c787be1d900facaa68963 100644 (file)
@@ -157,6 +157,7 @@ static const struct sil_drivelist {
        { "ST380011ASL",        SIL_QUIRK_MOD15WRITE },
        { "ST3120022ASL",       SIL_QUIRK_MOD15WRITE },
        { "ST3160021ASL",       SIL_QUIRK_MOD15WRITE },
+       { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE },
        { "Maxtor 4D060H3",     SIL_QUIRK_UDMA5MAX },
        { }
 };
index 62a76076b5482a3bacab4a9cf2a5ff2c269efddb..f1a9198dfe5a4966cbe7f433b357005501eb002a 100644 (file)
@@ -1925,7 +1925,7 @@ static int ucode_init(loader_block *lb, amb_dev *dev)
   const struct firmware *fw;
   unsigned long start_address;
   const struct ihex_binrec *rec;
-  const char *errmsg = 0;
+  const char *errmsg = NULL;
   int res;
 
   res = request_ihex_firmware(&fw, "atmsar11.fw", &dev->pci_dev->dev);
index b41c9481b67b94bf8331c9401b18123eb47ffaef..82f2ae0d7cc488a337772aaf8d7a19b3373bcd94 100644 (file)
@@ -736,8 +736,8 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
       
                        skb = td->skb;
                        if (skb == FS_VCC (ATM_SKB(skb)->vcc)->last_skb) {
-                               wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait);
                                FS_VCC (ATM_SKB(skb)->vcc)->last_skb = NULL;
+                               wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait);
                        }
                        td->dev->ntxpckts--;
 
@@ -1123,7 +1123,7 @@ static void fs_close(struct atm_vcc *atm_vcc)
                   this sleep_on, we'll lose any reference to these packets. Memory leak!
                   On the other hand, it's awfully convenient that we can abort a "close" that
                   is taking too long. Maybe just use non-interruptible sleep on? -- REW */
-               interruptible_sleep_on (& vcc->close_wait);
+               wait_event_interruptible(vcc->close_wait, !vcc->last_skb);
        }
 
        txtp = &atm_vcc->qos.txtp;
@@ -2000,7 +2000,7 @@ static void firestream_remove_one(struct pci_dev *pdev)
 
                fs_dprintk (FS_DEBUG_CLEANUP, "Freeing irq%d.\n", dev->irq);
                free_irq (dev->irq, dev);
-               del_timer (&dev->timer);
+               del_timer_sync (&dev->timer);
 
                atm_dev_deregister(dev->atm_dev);
                free_queue (dev, &dev->hp_txq);
index 45d506363aba8f90c117bfa5c31d4ca046eb4630..909c95bd7be260ec970dc42f1299113333793b4e 100644 (file)
@@ -368,9 +368,9 @@ EXPORT_SYMBOL(idt77105_init);
 
 static void __exit idt77105_exit(void)
 {
-        /* turn off timers */
-        del_timer(&stats_timer);
-        del_timer(&restart_timer);
+       /* turn off timers */
+       del_timer_sync(&stats_timer);
+       del_timer_sync(&restart_timer);
 }
 
 module_exit(idt77105_exit);
index 9587e959ce1af0cefca7d814ad161aa1c709c9bb..9988ac98b6d83ee58fa2774f1c4ced4559dcee74 100644 (file)
@@ -639,9 +639,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
        card->hbnr.init = NUM_HB;
        card->hbnr.max = MAX_HB;
 
-       card->sm_handle = 0x00000000;
+       card->sm_handle = NULL;
        card->sm_addr = 0x00000000;
-       card->lg_handle = 0x00000000;
+       card->lg_handle = NULL;
        card->lg_addr = 0x00000000;
 
        card->efbie = 1;        /* To prevent push_rxbufs from enabling the interrupt */
@@ -979,7 +979,7 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
                                addr2 = card->sm_addr;
                                handle2 = card->sm_handle;
                                card->sm_addr = 0x00000000;
-                               card->sm_handle = 0x00000000;
+                               card->sm_handle = NULL;
                        } else {        /* (!sm_addr) */
 
                                card->sm_addr = addr1;
@@ -993,7 +993,7 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
                                addr2 = card->lg_addr;
                                handle2 = card->lg_handle;
                                card->lg_addr = 0x00000000;
-                               card->lg_handle = 0x00000000;
+                               card->lg_handle = NULL;
                        } else {        /* (!lg_addr) */
 
                                card->lg_addr = addr1;
@@ -1739,10 +1739,10 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
                }
 
                scq->full = 1;
-               spin_unlock_irqrestore(&scq->lock, flags);
-               interruptible_sleep_on_timeout(&scq->scqfull_waitq,
-                                              SCQFULL_TIMEOUT);
-               spin_lock_irqsave(&scq->lock, flags);
+               wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq,
+                                                         scq->tail != scq->next,
+                                                         scq->lock,
+                                                         SCQFULL_TIMEOUT);
 
                if (scq->full) {
                        spin_unlock_irqrestore(&scq->lock, flags);
@@ -1789,10 +1789,10 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
                        scq->full = 1;
                        if (has_run++)
                                break;
-                       spin_unlock_irqrestore(&scq->lock, flags);
-                       interruptible_sleep_on_timeout(&scq->scqfull_waitq,
-                                                      SCQFULL_TIMEOUT);
-                       spin_lock_irqsave(&scq->lock, flags);
+                       wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq,
+                                                                 scq->tail != scq->next,
+                                                                 scq->lock,
+                                                                 SCQFULL_TIMEOUT);
                }
 
                if (!scq->full) {
index e3fb496c71630a643a1dea0b472fab3238fa755e..943cf0d6abaf8b959e2a879ca901fedaea693b1e 100644 (file)
@@ -760,7 +760,7 @@ static irqreturn_t solos_irq(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
-void solos_bh(unsigned long card_arg)
+static void solos_bh(unsigned long card_arg)
 {
        struct solos_card *card = (void *)card_arg;
        uint32_t card_flags;
index c53efe6c6d8eb49becd64f875857fc8d4888e955..c4778995cd728047d83a284d2e9248bbde89389f 100644 (file)
@@ -133,9 +133,16 @@ static int try_to_bring_up_master(struct master *master,
                        goto out;
                }
 
+               if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
                /* Found all components */
                ret = master->ops->bind(master->dev);
                if (ret < 0) {
+                       devres_release_group(master->dev, NULL);
+                       dev_info(master->dev, "master bind failed: %d\n", ret);
                        master_remove_components(master);
                        goto out;
                }
@@ -166,6 +173,7 @@ static void take_down_master(struct master *master)
 {
        if (master->bound) {
                master->ops->unbind(master->dev);
+               devres_release_group(master->dev, NULL);
                master->bound = false;
        }
 
index 1e16cbd61da27877bf372cc90f1323d950676db2..61d6d62cc0d35ff17d6e9736d9704ad3848e22a1 100644 (file)
@@ -616,36 +616,35 @@ static int dma_buf_describe(struct seq_file *s)
        if (ret)
                return ret;
 
-       seq_printf(s, "\nDma-buf Objects:\n");
-       seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n");
+       seq_puts(s, "\nDma-buf Objects:\n");
+       seq_puts(s, "size\tflags\tmode\tcount\texp_name\n");
 
        list_for_each_entry(buf_obj, &db_list.head, list_node) {
                ret = mutex_lock_interruptible(&buf_obj->lock);
 
                if (ret) {
-                       seq_printf(s,
-                                 "\tERROR locking buffer object: skipping\n");
+                       seq_puts(s,
+                                "\tERROR locking buffer object: skipping\n");
                        continue;
                }
 
-               seq_printf(s, "\t");
-
-               seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n",
-                               buf_obj->exp_name, buf_obj->size,
+               seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n",
+                               buf_obj->size,
                                buf_obj->file->f_flags, buf_obj->file->f_mode,
-                               (long)(buf_obj->file->f_count.counter));
+                               (long)(buf_obj->file->f_count.counter),
+                               buf_obj->exp_name);
 
-               seq_printf(s, "\t\tAttached Devices:\n");
+               seq_puts(s, "\tAttached Devices:\n");
                attach_count = 0;
 
                list_for_each_entry(attach_obj, &buf_obj->attachments, node) {
-                       seq_printf(s, "\t\t");
+                       seq_puts(s, "\t");
 
-                       seq_printf(s, "%s\n", attach_obj->dev->init_name);
+                       seq_printf(s, "%s\n", dev_name(attach_obj->dev));
                        attach_count++;
                }
 
-               seq_printf(s, "\n\t\tTotal %d devices attached\n",
+               seq_printf(s, "Total %d devices attached\n\n",
                                attach_count);
 
                count++;
index 8a97ddfa61222db79506dcecebc619ab5a333865..c30df50e4440c3af5639af58dd567c37e8bf40e6 100644 (file)
@@ -1580,6 +1580,7 @@ static int fw_pm_notify(struct notifier_block *notify_block,
        switch (mode) {
        case PM_HIBERNATION_PREPARE:
        case PM_SUSPEND_PREPARE:
+       case PM_RESTORE_PREPARE:
                kill_requests_without_uevent();
                device_cache_fw_images();
                break;
index 8184451b57c04999bd23c286080e14ca7f069031..422b7d84f686b90147f97565210687d343a3d9eb 100644 (file)
@@ -874,7 +874,7 @@ bio_pageinc(struct bio *bio)
                /* Non-zero page count for non-head members of
                 * compound pages is no longer allowed by the kernel.
                 */
-               page = compound_trans_head(bv.bv_page);
+               page = compound_head(bv.bv_page);
                atomic_inc(&page->_count);
        }
 }
@@ -887,7 +887,7 @@ bio_pagedec(struct bio *bio)
        struct bvec_iter iter;
 
        bio_for_each_segment(bv, bio, iter) {
-               page = compound_trans_head(bv.bv_page);
+               page = compound_head(bv.bv_page);
                atomic_dec(&page->_count);
        }
 }
index 516026954be62d325a9e9d7c5541e5fbf51c7569..d777bb7cea93fd4338149fd9b91335305cce055b 100644 (file)
@@ -4498,7 +4498,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        }
        dev_info(&pdev->dev, "NUMA node %d (closest: %d,%d, probe on %d:%d)\n",
                my_node, pcibus_to_node(pdev->bus), dev_to_node(&pdev->dev),
-               cpu_to_node(smp_processor_id()), smp_processor_id());
+               cpu_to_node(raw_smp_processor_id()), raw_smp_processor_id());
 
        dd = kzalloc_node(sizeof(struct driver_data), GFP_KERNEL, my_node);
        if (dd == NULL) {
index b52e9a6d6aad6d602bf3a9d6f73c9b4c277c7e17..54174cb32febe10a45eddd8e837d8267bfe594a1 100644 (file)
@@ -53,7 +53,7 @@
 #define MTIP_FTL_REBUILD_TIMEOUT_MS    2400000
 
 /* unaligned IO handling */
-#define MTIP_MAX_UNALIGNED_SLOTS       8
+#define MTIP_MAX_UNALIGNED_SLOTS       2
 
 /* Macro to extract the tag bit number from a tag value. */
 #define MTIP_TAG_BIT(tag)      (tag & 0x1F)
index 3107282a9741f96665a2805b08217d3209c27bf7..091b9ea14feb5856ceada49671197dfac567376c 100644 (file)
@@ -60,7 +60,9 @@ enum {
        NULL_IRQ_NONE           = 0,
        NULL_IRQ_SOFTIRQ        = 1,
        NULL_IRQ_TIMER          = 2,
+};
 
+enum {
        NULL_Q_BIO              = 0,
        NULL_Q_RQ               = 1,
        NULL_Q_MQ               = 2,
@@ -172,18 +174,20 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait)
 
 static void end_cmd(struct nullb_cmd *cmd)
 {
-       if (cmd->rq) {
-               if (queue_mode == NULL_Q_MQ)
-                       blk_mq_end_io(cmd->rq, 0);
-               else {
-                       INIT_LIST_HEAD(&cmd->rq->queuelist);
-                       blk_end_request_all(cmd->rq, 0);
-               }
-       } else if (cmd->bio)
+       switch (queue_mode)  {
+       case NULL_Q_MQ:
+               blk_mq_end_io(cmd->rq, 0);
+               return;
+       case NULL_Q_RQ:
+               INIT_LIST_HEAD(&cmd->rq->queuelist);
+               blk_end_request_all(cmd->rq, 0);
+               break;
+       case NULL_Q_BIO:
                bio_endio(cmd->bio, 0);
+               break;
+       }
 
-       if (queue_mode != NULL_Q_MQ)
-               free_cmd(cmd);
+       free_cmd(cmd);
 }
 
 static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
@@ -195,6 +199,7 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
        cq = &per_cpu(completion_queues, smp_processor_id());
 
        while ((entry = llist_del_all(&cq->list)) != NULL) {
+               entry = llist_reverse_order(entry);
                do {
                        cmd = container_of(entry, struct nullb_cmd, ll_list);
                        end_cmd(cmd);
@@ -221,61 +226,31 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd)
 
 static void null_softirq_done_fn(struct request *rq)
 {
-       blk_end_request_all(rq, 0);
-}
-
-#ifdef CONFIG_SMP
-
-static void null_ipi_cmd_end_io(void *data)
-{
-       struct completion_queue *cq;
-       struct llist_node *entry, *next;
-       struct nullb_cmd *cmd;
-
-       cq = &per_cpu(completion_queues, smp_processor_id());
-
-       entry = llist_del_all(&cq->list);
-
-       while (entry) {
-               next = entry->next;
-               cmd = llist_entry(entry, struct nullb_cmd, ll_list);
-               end_cmd(cmd);
-               entry = next;
-       }
-}
-
-static void null_cmd_end_ipi(struct nullb_cmd *cmd)
-{
-       struct call_single_data *data = &cmd->csd;
-       int cpu = get_cpu();
-       struct completion_queue *cq = &per_cpu(completion_queues, cpu);
-
-       cmd->ll_list.next = NULL;
-
-       if (llist_add(&cmd->ll_list, &cq->list)) {
-               data->func = null_ipi_cmd_end_io;
-               data->flags = 0;
-               __smp_call_function_single(cpu, data, 0);
-       }
-
-       put_cpu();
+       end_cmd(rq->special);
 }
 
-#endif /* CONFIG_SMP */
-
 static inline void null_handle_cmd(struct nullb_cmd *cmd)
 {
        /* Complete IO by inline, softirq or timer */
        switch (irqmode) {
-       case NULL_IRQ_NONE:
-               end_cmd(cmd);
-               break;
        case NULL_IRQ_SOFTIRQ:
-#ifdef CONFIG_SMP
-               null_cmd_end_ipi(cmd);
-#else
+               switch (queue_mode)  {
+               case NULL_Q_MQ:
+                       blk_mq_complete_request(cmd->rq);
+                       break;
+               case NULL_Q_RQ:
+                       blk_complete_request(cmd->rq);
+                       break;
+               case NULL_Q_BIO:
+                       /*
+                        * XXX: no proper submitting cpu information available.
+                        */
+                       end_cmd(cmd);
+                       break;
+               }
+               break;
+       case NULL_IRQ_NONE:
                end_cmd(cmd);
-#endif
                break;
        case NULL_IRQ_TIMER:
                null_cmd_end_timer(cmd);
@@ -411,6 +386,7 @@ static struct blk_mq_ops null_mq_ops = {
        .queue_rq       = null_queue_rq,
        .map_queue      = blk_mq_map_queue,
        .init_hctx      = null_init_hctx,
+       .complete       = null_softirq_done_fn,
 };
 
 static struct blk_mq_reg null_mq_reg = {
@@ -609,13 +585,6 @@ static int __init null_init(void)
 {
        unsigned int i;
 
-#if !defined(CONFIG_SMP)
-       if (irqmode == NULL_IRQ_SOFTIRQ) {
-               pr_warn("null_blk: softirq completions not available.\n");
-               pr_warn("null_blk: using direct completions.\n");
-               irqmode = NULL_IRQ_NONE;
-       }
-#endif
        if (bs > PAGE_SIZE) {
                pr_warn("null_blk: invalid block size\n");
                pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE);
index 6a680d4de7f1c3dcfa7999e45efc98b4b14d99fc..b1cb3f4c4db45543c653fd86ce28e75b67522430 100644 (file)
@@ -110,9 +110,9 @@ static int __virtblk_add_req(struct virtqueue *vq,
        return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC);
 }
 
-static inline void virtblk_request_done(struct virtblk_req *vbr)
+static inline void virtblk_request_done(struct request *req)
 {
-       struct request *req = vbr->req;
+       struct virtblk_req *vbr = req->special;
        int error = virtblk_result(vbr);
 
        if (req->cmd_type == REQ_TYPE_BLOCK_PC) {
@@ -138,7 +138,7 @@ static void virtblk_done(struct virtqueue *vq)
        do {
                virtqueue_disable_cb(vq);
                while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) {
-                       virtblk_request_done(vbr);
+                       blk_mq_complete_request(vbr->req);
                        req_done = true;
                }
                if (unlikely(virtqueue_is_broken(vq)))
@@ -479,6 +479,7 @@ static struct blk_mq_ops virtio_mq_ops = {
        .map_queue      = blk_mq_map_queue,
        .alloc_hctx     = blk_mq_alloc_single_hw_queue,
        .free_hctx      = blk_mq_free_single_hw_queue,
+       .complete       = virtblk_request_done,
 };
 
 static struct blk_mq_reg virtio_mq_reg = {
index 4b97b86da9265b4ca5dcb3a7ab562dbf1eb5bac0..64c60edcdfbc5546cd84538986b5d26625f9f248 100644 (file)
@@ -299,7 +299,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
        BUG_ON(num != 0);
 }
 
-static void unmap_purged_grants(struct work_struct *work)
+void xen_blkbk_unmap_purged_grants(struct work_struct *work)
 {
        struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
@@ -375,7 +375,7 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
 
        pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean);
 
-       INIT_LIST_HEAD(&blkif->persistent_purge_list);
+       BUG_ON(!list_empty(&blkif->persistent_purge_list));
        root = &blkif->persistent_gnts;
 purge_list:
        foreach_grant_safe(persistent_gnt, n, root, node) {
@@ -420,7 +420,6 @@ finished:
        blkif->vbd.overflow_max_grants = 0;
 
        /* We can defer this work */
-       INIT_WORK(&blkif->persistent_purge_work, unmap_purged_grants);
        schedule_work(&blkif->persistent_purge_work);
        pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total);
        return;
@@ -625,9 +624,23 @@ purge_gnt_list:
                        print_stats(blkif);
        }
 
-       /* Since we are shutting down remove all pages from the buffer */
-       shrink_free_pagepool(blkif, 0 /* All */);
+       /* Drain pending purge work */
+       flush_work(&blkif->persistent_purge_work);
 
+       if (log_stats)
+               print_stats(blkif);
+
+       blkif->xenblkd = NULL;
+       xen_blkif_put(blkif);
+
+       return 0;
+}
+
+/*
+ * Remove persistent grants and empty the pool of free pages
+ */
+void xen_blkbk_free_caches(struct xen_blkif *blkif)
+{
        /* Free all persistent grant pages */
        if (!RB_EMPTY_ROOT(&blkif->persistent_gnts))
                free_persistent_gnts(blkif, &blkif->persistent_gnts,
@@ -636,13 +649,8 @@ purge_gnt_list:
        BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
        blkif->persistent_gnt_c = 0;
 
-       if (log_stats)
-               print_stats(blkif);
-
-       blkif->xenblkd = NULL;
-       xen_blkif_put(blkif);
-
-       return 0;
+       /* Since we are shutting down remove all pages from the buffer */
+       shrink_free_pagepool(blkif, 0 /* All */);
 }
 
 /*
@@ -838,7 +846,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
        struct grant_page **pages = pending_req->indirect_pages;
        struct xen_blkif *blkif = pending_req->blkif;
        int indirect_grefs, rc, n, nseg, i;
-       struct blkif_request_segment_aligned *segments = NULL;
+       struct blkif_request_segment *segments = NULL;
 
        nseg = pending_req->nr_pages;
        indirect_grefs = INDIRECT_PAGES(nseg);
@@ -934,9 +942,7 @@ static void xen_blk_drain_io(struct xen_blkif *blkif)
 {
        atomic_set(&blkif->drain, 1);
        do {
-               /* The initial value is one, and one refcnt taken at the
-                * start of the xen_blkif_schedule thread. */
-               if (atomic_read(&blkif->refcnt) <= 2)
+               if (atomic_read(&blkif->inflight) == 0)
                        break;
                wait_for_completion_interruptible_timeout(
                                &blkif->drain_complete, HZ);
@@ -976,17 +982,30 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
         * the proper response on the ring.
         */
        if (atomic_dec_and_test(&pending_req->pendcnt)) {
-               xen_blkbk_unmap(pending_req->blkif,
+               struct xen_blkif *blkif = pending_req->blkif;
+
+               xen_blkbk_unmap(blkif,
                                pending_req->segments,
                                pending_req->nr_pages);
-               make_response(pending_req->blkif, pending_req->id,
+               make_response(blkif, pending_req->id,
                              pending_req->operation, pending_req->status);
-               xen_blkif_put(pending_req->blkif);
-               if (atomic_read(&pending_req->blkif->refcnt) <= 2) {
-                       if (atomic_read(&pending_req->blkif->drain))
-                               complete(&pending_req->blkif->drain_complete);
+               free_req(blkif, pending_req);
+               /*
+                * Make sure the request is freed before releasing blkif,
+                * or there could be a race between free_req and the
+                * cleanup done in xen_blkif_free during shutdown.
+                *
+                * NB: The fact that we might try to wake up pending_free_wq
+                * before drain_complete (in case there's a drain going on)
+                * it's not a problem with our current implementation
+                * because we can assure there's no thread waiting on
+                * pending_free_wq if there's a drain going on, but it has
+                * to be taken into account if the current model is changed.
+                */
+               if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) {
+                       complete(&blkif->drain_complete);
                }
-               free_req(pending_req->blkif, pending_req);
+               xen_blkif_put(blkif);
        }
 }
 
@@ -1240,6 +1259,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
         * below (in "!bio") if we are handling a BLKIF_OP_DISCARD.
         */
        xen_blkif_get(blkif);
+       atomic_inc(&blkif->inflight);
 
        for (i = 0; i < nseg; i++) {
                while ((bio == NULL) ||
index 8d8807563d9967afd28b70dcb0cd072bed35e8ec..be052773ad03c186666af7602e1c7c1b0c4d6329 100644 (file)
@@ -57,7 +57,7 @@
 #define MAX_INDIRECT_SEGMENTS 256
 
 #define SEGS_PER_INDIRECT_FRAME \
-       (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+       (PAGE_SIZE/sizeof(struct blkif_request_segment))
 #define MAX_INDIRECT_PAGES \
        ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
 #define INDIRECT_PAGES(_segs) \
@@ -278,6 +278,7 @@ struct xen_blkif {
        /* for barrier (drain) requests */
        struct completion       drain_complete;
        atomic_t                drain;
+       atomic_t                inflight;
        /* One thread per one blkif. */
        struct task_struct      *xenblkd;
        unsigned int            waiting_reqs;
@@ -376,6 +377,7 @@ int xen_blkif_xenbus_init(void);
 irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
 int xen_blkif_schedule(void *arg);
 int xen_blkif_purge_persistent(void *arg);
+void xen_blkbk_free_caches(struct xen_blkif *blkif);
 
 int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
                              struct backend_info *be, int state);
@@ -383,6 +385,7 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
 int xen_blkbk_barrier(struct xenbus_transaction xbt,
                      struct backend_info *be, int state);
 struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
+void xen_blkbk_unmap_purged_grants(struct work_struct *work);
 
 static inline void blkif_get_x86_32_req(struct blkif_request *dst,
                                        struct blkif_x86_32_request *src)
index c2014a0aa206b2ec1b1ee328e84bde4407026616..9a547e6b6ebf02ab9bba0a48167f0b0b1b0915b2 100644 (file)
@@ -125,8 +125,11 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
        blkif->persistent_gnts.rb_node = NULL;
        spin_lock_init(&blkif->free_pages_lock);
        INIT_LIST_HEAD(&blkif->free_pages);
+       INIT_LIST_HEAD(&blkif->persistent_purge_list);
        blkif->free_pages_num = 0;
        atomic_set(&blkif->persistent_gnt_in_use, 0);
+       atomic_set(&blkif->inflight, 0);
+       INIT_WORK(&blkif->persistent_purge_work, xen_blkbk_unmap_purged_grants);
 
        INIT_LIST_HEAD(&blkif->pending_free);
 
@@ -259,6 +262,17 @@ static void xen_blkif_free(struct xen_blkif *blkif)
        if (!atomic_dec_and_test(&blkif->refcnt))
                BUG();
 
+       /* Remove all persistent grants and the cache of ballooned pages. */
+       xen_blkbk_free_caches(blkif);
+
+       /* Make sure everything is drained before shutting down */
+       BUG_ON(blkif->persistent_gnt_c != 0);
+       BUG_ON(atomic_read(&blkif->persistent_gnt_in_use) != 0);
+       BUG_ON(blkif->free_pages_num != 0);
+       BUG_ON(!list_empty(&blkif->persistent_purge_list));
+       BUG_ON(!list_empty(&blkif->free_pages));
+       BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts));
+
        /* Check that there is no request in use */
        list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) {
                list_del(&req->free_list);
index 8dcfb54f160302e0e1d91c232387f758b2f8e0f6..efe1b4761735a79faa30867ad625fdd51e043081 100644 (file)
@@ -162,7 +162,7 @@ static DEFINE_SPINLOCK(minor_lock);
 #define DEV_NAME       "xvd"   /* name in /dev */
 
 #define SEGS_PER_INDIRECT_FRAME \
-       (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned))
+       (PAGE_SIZE/sizeof(struct blkif_request_segment))
 #define INDIRECT_GREFS(_segs) \
        ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
 
@@ -393,7 +393,7 @@ static int blkif_queue_request(struct request *req)
        unsigned long id;
        unsigned int fsect, lsect;
        int i, ref, n;
-       struct blkif_request_segment_aligned *segments = NULL;
+       struct blkif_request_segment *segments = NULL;
 
        /*
         * Used to store if we are able to queue the request by just using
@@ -550,7 +550,7 @@ static int blkif_queue_request(struct request *req)
                        } else {
                                n = i % SEGS_PER_INDIRECT_FRAME;
                                segments[n] =
-                                       (struct blkif_request_segment_aligned) {
+                                       (struct blkif_request_segment) {
                                                        .gref       = ref,
                                                        .first_sect = fsect,
                                                        .last_sect  = lsect };
@@ -1904,13 +1904,16 @@ static void blkback_changed(struct xenbus_device *dev,
        case XenbusStateReconfiguring:
        case XenbusStateReconfigured:
        case XenbusStateUnknown:
-       case XenbusStateClosed:
                break;
 
        case XenbusStateConnected:
                blkfront_connect(info);
                break;
 
+       case XenbusStateClosed:
+               if (dev->state == XenbusStateClosed)
+                       break;
+               /* Missed the backend's Closing state -- fallthrough */
        case XenbusStateClosing:
                blkfront_closing(info);
                break;
index 011e55d820b1811a3379a65a4ef754fcc785f3ef..51c557cfd92b37cf6b7aecdfa50d212fdacc05ee 100644 (file)
@@ -612,6 +612,8 @@ static ssize_t disksize_store(struct device *dev,
 
        disksize = PAGE_ALIGN(disksize);
        meta = zram_meta_alloc(disksize);
+       if (!meta)
+               return -ENOMEM;
        down_write(&zram->init_lock);
        if (zram->init_done) {
                up_write(&zram->init_lock);
index fa3243d71c76d0b9f14dde9066a2bff60a18165c..1386749b48ffd6e2711316a9083e913c560eabb6 100644 (file)
@@ -499,6 +499,7 @@ config RAW_DRIVER
 config MAX_RAW_DEVS
        int "Maximum number of RAW devices to support (1-65536)"
        depends on RAW_DRIVER
+       range 1 65536
        default "256"
        help
          The maximum number of RAW devices that are supported.
index f3223aac4df11c41959a744bee67af2d2df232e5..6e8d65e9b1d3c196ea2d2bd76b78530dd0387920 100644 (file)
@@ -190,7 +190,7 @@ static int bind_get(int number, dev_t *dev)
        struct raw_device_data *rawdev;
        struct block_device *bdev;
 
-       if (number <= 0 || number >= MAX_RAW_MINORS)
+       if (number <= 0 || number >= max_raw_minors)
                return -EINVAL;
 
        rawdev = &raw_devices[number];
index bd313f7816a8d9461deba6889b99415b87010467..c1af80bcdf2082c8d0d7b32e28eb9122c59ac53f 100644 (file)
@@ -242,7 +242,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
 
        irq = irq_of_parse_and_map(np, 0);
        if (!irq)
-               return;
+               goto out_free_characteristics;
 
        clk = at91_clk_register_master(pmc, irq, name, num_parents,
                                       parent_names, layout,
index 6a934a5296bd4ca2867146dc06272ea1003e238e..05e04ce0f1488f7301ad5153f687860bf872f8bc 100644 (file)
@@ -494,6 +494,9 @@ static const struct file_operations nomadik_src_clk_debugfs_ops = {
 
 static int __init nomadik_src_clk_init_debugfs(void)
 {
+       /* Vital for multiplatform */
+       if (!src_base)
+               return -ENODEV;
        src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
        src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
        debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
index 5517944495d893cc3c8dd60569b58e67e9289765..c42e608af6bbe0980717a74e69a143cdc742f1b1 100644 (file)
@@ -2226,24 +2226,25 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
  */
 int __clk_get(struct clk *clk)
 {
-       if (clk && !try_module_get(clk->owner))
-               return 0;
+       if (clk) {
+               if (!try_module_get(clk->owner))
+                       return 0;
 
-       kref_get(&clk->ref);
+               kref_get(&clk->ref);
+       }
        return 1;
 }
 
 void __clk_put(struct clk *clk)
 {
-       if (WARN_ON_ONCE(IS_ERR(clk)))
+       if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
                return;
 
        clk_prepare_lock();
        kref_put(&clk->ref, __clk_release);
        clk_prepare_unlock();
 
-       if (clk)
-               module_put(clk->owner);
+       module_put(clk->owner);
 }
 
 /***        clk rate change notifiers        ***/
index 17a598398a53df461e110ca5c16d29e7bc92e6f5..86f1e362eafb8e29c02fae393620d39d32278529 100644 (file)
@@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev,
 
        init.name = name;
        init.ops = &clk_psc_ops;
+       init.flags = 0;
        init.parent_names = (parent_name ? &parent_name : NULL);
        init.num_parents = (parent_name ? 1 : 0);
 
index 81a202d12a7ad89ab56909fce6782baa7fb94ec2..bef198a83863aaa79e21ca1c4e1401238cae31b7 100644 (file)
@@ -141,13 +141,6 @@ static const struct coreclk_soc_desc a370_coreclks = {
        .num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
 };
 
-static void __init a370_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &a370_coreclks);
-}
-CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock",
-              a370_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
        { }
 };
 
-static void __init a370_clk_gating_init(struct device_node *np)
+static void __init a370_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, a370_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock");
+
+       mvebu_coreclk_setup(np, &a370_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, a370_gating_desc);
 }
-CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock",
-              a370_clk_gating_init);
+CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init);
+
index 9922c4475aa8b3f7d01c2881c8a757b94f9027af..b3094315a3c0faa89926dcf7442d5034f39b4f15 100644 (file)
@@ -158,13 +158,6 @@ static const struct coreclk_soc_desc axp_coreclks = {
        .num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
 };
 
-static void __init axp_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &axp_coreclks);
-}
-CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock",
-              axp_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
        { }
 };
 
-static void __init axp_clk_gating_init(struct device_node *np)
+static void __init axp_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, axp_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock");
+
+       mvebu_coreclk_setup(np, &axp_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, axp_gating_desc);
 }
-CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock",
-              axp_clk_gating_init);
+CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init);
index 38aee1e3f242b237079aaeb775aa2fd8dae89453..b8c2424ac9261dea5c36553b09f5262bba359299 100644 (file)
@@ -154,12 +154,6 @@ static const struct coreclk_soc_desc dove_coreclks = {
        .num_ratios = ARRAY_SIZE(dove_coreclk_ratios),
 };
 
-static void __init dove_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &dove_coreclks);
-}
-CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = {
        { }
 };
 
-static void __init dove_clk_gating_init(struct device_node *np)
+static void __init dove_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, dove_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
+
+       mvebu_coreclk_setup(np, &dove_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, dove_gating_desc);
 }
-CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock",
-              dove_clk_gating_init);
+CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init);
index 2636a55f29f9403df92aec0c11e5a504fc7f9deb..ddb666a86500964201db0ad6d3a3724511302b59 100644 (file)
@@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
-static void __init kirkwood_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &kirkwood_coreclks);
-}
-CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock",
-              kirkwood_coreclk_init);
-
 static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .get_tclk_freq = kirkwood_get_tclk_freq,
        .get_cpu_freq = mv88f6180_get_cpu_freq,
@@ -208,13 +201,6 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = {
        .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
 };
 
-static void __init mv88f6180_coreclk_init(struct device_node *np)
-{
-       mvebu_coreclk_setup(np, &mv88f6180_coreclks);
-}
-CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock",
-              mv88f6180_coreclk_init);
-
 /*
  * Clock Gating Control
  */
@@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
        { }
 };
 
-static void __init kirkwood_clk_gating_init(struct device_node *np)
+static void __init kirkwood_clk_init(struct device_node *np)
 {
-       mvebu_clk_gating_setup(np, kirkwood_gating_desc);
+       struct device_node *cgnp =
+               of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock");
+
+
+       if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock"))
+               mvebu_coreclk_setup(np, &mv88f6180_coreclks);
+       else
+               mvebu_coreclk_setup(np, &kirkwood_coreclks);
+
+       if (cgnp)
+               mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc);
 }
-CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock",
-              kirkwood_clk_gating_init);
+CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock",
+              kirkwood_clk_init);
+CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock",
+              kirkwood_clk_init);
index a59ec217a12437785ea1c689b28744bfcd19ac3d..99c27b1c625b8e3eaf514895a0a13ebf8b94fdef 100644 (file)
@@ -26,6 +26,8 @@ struct rcar_gen2_cpg {
        void __iomem *reg;
 };
 
+#define CPG_FRQCRB                     0x00000004
+#define CPG_FRQCRB_KICK                        BIT(31)
 #define CPG_SDCKCR                     0x00000074
 #define CPG_PLL0CR                     0x000000d8
 #define CPG_FRQCRC                     0x000000e0
@@ -45,6 +47,7 @@ struct rcar_gen2_cpg {
 struct cpg_z_clk {
        struct clk_hw hw;
        void __iomem *reg;
+       void __iomem *kick_reg;
 };
 
 #define to_z_clk(_hw)  container_of(_hw, struct cpg_z_clk, hw)
@@ -83,17 +86,45 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct cpg_z_clk *zclk = to_z_clk(hw);
        unsigned int mult;
-       u32 val;
+       u32 val, kick;
+       unsigned int i;
 
        mult = div_u64((u64)rate * 32, parent_rate);
        mult = clamp(mult, 1U, 32U);
 
+       if (clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
+               return -EBUSY;
+
        val = clk_readl(zclk->reg);
        val &= ~CPG_FRQCRC_ZFC_MASK;
        val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;
        clk_writel(val, zclk->reg);
 
-       return 0;
+       /*
+        * Set KICK bit in FRQCRB to update hardware setting and wait for
+        * clock change completion.
+        */
+       kick = clk_readl(zclk->kick_reg);
+       kick |= CPG_FRQCRB_KICK;
+       clk_writel(kick, zclk->kick_reg);
+
+       /*
+        * Note: There is no HW information about the worst case latency.
+        *
+        * Using experimental measurements, it seems that no more than
+        * ~10 iterations are needed, independently of the CPU rate.
+        * Since this value might be dependant of external xtal rate, pll1
+        * rate or even the other emulation clocks rate, use 1000 as a
+        * "super" safe value.
+        */
+       for (i = 1000; i; i--) {
+               if (!(clk_readl(zclk->kick_reg) & CPG_FRQCRB_KICK))
+                       return 0;
+
+               cpu_relax();
+       }
+
+       return -ETIMEDOUT;
 }
 
 static const struct clk_ops cpg_z_clk_ops = {
@@ -120,6 +151,7 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
        init.num_parents = 1;
 
        zclk->reg = cpg->reg + CPG_FRQCRC;
+       zclk->kick_reg = cpg->reg + CPG_FRQCRB;
        zclk->hw.init = &init;
 
        clk = clk_register(NULL, &zclk->hw);
@@ -186,7 +218,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                             const char *name)
 {
        const struct clk_div_table *table = NULL;
-       const char *parent_name = "main";
+       const char *parent_name;
        unsigned int shift;
        unsigned int mult = 1;
        unsigned int div = 1;
@@ -201,23 +233,31 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
                 * the multiplier value.
                 */
                u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+               parent_name = "main";
                mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
        } else if (!strcmp(name, "pll1")) {
+               parent_name = "main";
                mult = config->pll1_mult / 2;
        } else if (!strcmp(name, "pll3")) {
+               parent_name = "main";
                mult = config->pll3_mult;
        } else if (!strcmp(name, "lb")) {
+               parent_name = "pll1_div2";
                div = cpg_mode & BIT(18) ? 36 : 24;
        } else if (!strcmp(name, "qspi")) {
+               parent_name = "pll1_div2";
                div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2)
-                   ? 16 : 20;
+                   ? 8 : 10;
        } else if (!strcmp(name, "sdh")) {
+               parent_name = "pll1_div2";
                table = cpg_sdh_div_table;
                shift = 8;
        } else if (!strcmp(name, "sd0")) {
+               parent_name = "pll1_div2";
                table = cpg_sd01_div_table;
                shift = 4;
        } else if (!strcmp(name, "sd1")) {
+               parent_name = "pll1_div2";
                table = cpg_sd01_div_table;
                shift = 0;
        } else if (!strcmp(name, "z")) {
index 4d75b1f37e3a4b74ee4606ce33d54b8a771beb6a..290f9c1a37498ccf16ae0b09804ca15e722a2da2 100644 (file)
@@ -59,7 +59,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
                return 0;
 
        if (divider_ux1 > get_max_div(divider))
-               return -EINVAL;
+               return get_max_div(divider);
 
        return divider_ux1;
 }
index cf0c323f2c36ec453deed1c5374fbbce4df543b2..c39613c519af85aa5faf14cc02857219cde56a3b 100644 (file)
@@ -180,9 +180,13 @@ enum clk_id {
        tegra_clk_sbc6_8,
        tegra_clk_sclk,
        tegra_clk_sdmmc1,
+       tegra_clk_sdmmc1_8,
        tegra_clk_sdmmc2,
+       tegra_clk_sdmmc2_8,
        tegra_clk_sdmmc3,
+       tegra_clk_sdmmc3_8,
        tegra_clk_sdmmc4,
+       tegra_clk_sdmmc4_8,
        tegra_clk_se,
        tegra_clk_soc_therm,
        tegra_clk_sor0,
index 5c35885f4a7cee9a4ecb9309f93c345befe28a2e..1fa5c3f33b2033a5e4a32716706d2221d548adf1 100644 (file)
@@ -371,9 +371,7 @@ static const char *mux_pllp3_pllc_clkm[] = {
 static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = {
        "pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m"
 };
-static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = {
-       [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6,
-};
+#define mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx NULL
 
 static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = {
        "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4",
@@ -465,6 +463,10 @@ static struct tegra_periph_init_data periph_clks[] = {
        MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
        MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
        MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
+       MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
+       MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
+       MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
+       MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
        MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
        MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
        MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -492,7 +494,7 @@ static struct tegra_periph_init_data periph_clks[] = {
        UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
        UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
        UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
-       UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte),
+       UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
        XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
        XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
        XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
index 05dce4aa2c11e2a0d3e73cb84f4dc6231537b08d..feb3201c85ce5df6d8786eaf2e4a0408e5890ec0 100644 (file)
@@ -120,7 +120,7 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
                                        ARRAY_SIZE(cclk_lp_parents),
                                        CLK_SET_RATE_PARENT,
                                        clk_base + CCLKLP_BURST_POLICY,
-                                       0, 4, 8, 9, NULL);
+                                       TEGRA_DIVIDER_2, 4, 8, 9, NULL);
                *dt_clk = clk;
        }
 
index 90d9d25f2228195308f328a9d7c05c1a5bbe5a40..80431f0fb2688f84557383b20ea39513ed2ffcc4 100644 (file)
@@ -682,12 +682,12 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
        [tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true },
        [tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true },
        [tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true },
-       [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
+       [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true },
        [tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true },
        [tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true },
        [tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true },
-       [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
-       [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
+       [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true },
+       [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true },
        [tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true },
        [tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true },
        [tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true },
@@ -723,7 +723,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
        [tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true },
        [tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true },
        [tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true },
-       [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
+       [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true },
        [tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true },
        [tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true },
        [tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true },
index aff86b5bc7455c190fbf5ebaf2be08c204262e26..166e02f16c8a25f28f4441584dc6e8babc448f3b 100644 (file)
@@ -516,11 +516,11 @@ static struct div_nmp pllp_nmp = {
 };
 
 static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
-       {12000000, 216000000, 432, 12, 1, 8},
-       {13000000, 216000000, 432, 13, 1, 8},
-       {16800000, 216000000, 360, 14, 1, 8},
-       {19200000, 216000000, 360, 16, 1, 8},
-       {26000000, 216000000, 432, 26, 1, 8},
+       {12000000, 408000000, 408, 12, 0, 8},
+       {13000000, 408000000, 408, 13, 0, 8},
+       {16800000, 408000000, 340, 14, 0, 8},
+       {19200000, 408000000, 340, 16, 0, 8},
+       {26000000, 408000000, 408, 26, 0, 8},
        {0, 0, 0, 0, 0, 0},
 };
 
@@ -570,6 +570,15 @@ static struct tegra_clk_pll_params pll_a_params = {
        .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
 };
 
+static struct div_nmp plld_nmp = {
+       .divm_shift = 0,
+       .divm_width = 5,
+       .divn_shift = 8,
+       .divn_width = 11,
+       .divp_shift = 20,
+       .divp_width = 3,
+};
+
 static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
        {12000000, 216000000, 864, 12, 4, 12},
        {13000000, 216000000, 864, 13, 4, 12},
@@ -603,19 +612,18 @@ static struct tegra_clk_pll_params pll_d_params = {
        .lock_mask = PLL_BASE_LOCK,
        .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
        .lock_delay = 1000,
-       .div_nmp = &pllp_nmp,
+       .div_nmp = &plld_nmp,
        .freq_table = pll_d_freq_table,
        .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
                 TEGRA_PLL_USE_LOCK,
 };
 
 static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
-       { 12000000, 148500000,  99, 1, 8},
-       { 12000000, 594000000,  99, 1, 1},
-       { 13000000, 594000000,  91, 1, 1},      /* actual: 591.5 MHz */
-       { 16800000, 594000000,  71, 1, 1},      /* actual: 596.4 MHz */
-       { 19200000, 594000000,  62, 1, 1},      /* actual: 595.2 MHz */
-       { 26000000, 594000000,  91, 2, 1},      /* actual: 591.5 MHz */
+       { 12000000, 594000000,  99, 1, 2},
+       { 13000000, 594000000,  91, 1, 2},      /* actual: 591.5 MHz */
+       { 16800000, 594000000,  71, 1, 2},      /* actual: 596.4 MHz */
+       { 19200000, 594000000,  62, 1, 2},      /* actual: 595.2 MHz */
+       { 26000000, 594000000,  91, 2, 2},      /* actual: 591.5 MHz */
        { 0, 0, 0, 0, 0, 0 },
 };
 
@@ -753,21 +761,19 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true },
        [tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true },
        [tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true },
-       [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
+       [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true },
        [tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true },
        [tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true },
        [tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true },
-       [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
-       [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
+       [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true },
+       [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true },
        [tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true },
        [tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true },
-       [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true },
        [tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true },
        [tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true },
-       [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true },
        [tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true },
        [tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true },
-       [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
+       [tegra_clk_host1x_8] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true },
        [tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true },
        [tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true },
        [tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true },
@@ -794,7 +800,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
        [tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true },
        [tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true },
        [tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true },
-       [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
+       [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true },
        [tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true },
        [tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true },
        [tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true },
@@ -1286,9 +1292,9 @@ static void __init tegra124_pll_init(void __iomem *clk_base,
        clk_register_clkdev(clk, "pll_d2", NULL);
        clks[TEGRA124_CLK_PLL_D2] = clk;
 
-       /* PLLD2_OUT0 ?? */
+       /* PLLD2_OUT0 */
        clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2",
-                                       CLK_SET_RATE_PARENT, 1, 2);
+                                       CLK_SET_RATE_PARENT, 1, 1);
        clk_register_clkdev(clk, "pll_d2_out0", NULL);
        clks[TEGRA124_CLK_PLL_D2_OUT0] = clk;
 
index dbace152b2faa9e4f1699b8369d935683900df89..dace2b1b5ae66dafab4fe4639e6291872491119d 100644 (file)
@@ -574,6 +574,8 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
        [tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true },
        [tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true },
        [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true },
+       [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true },
+       [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true },
 };
 
 static unsigned long tegra20_clk_measure_input_freq(void)
index 974b2db2fe1087b05499a8dc2aaaa53338c985e4..0595dc6c453e6ee4a97cfb4dd30865f76c351366 100644 (file)
@@ -99,31 +99,6 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw)
        return;
 }
 
-static void __init kona_timers_init(struct device_node *node)
-{
-       u32 freq;
-       struct clk *external_clk;
-
-       external_clk = of_clk_get_by_name(node, NULL);
-
-       if (!IS_ERR(external_clk)) {
-               arch_timer_rate = clk_get_rate(external_clk);
-               clk_prepare_enable(external_clk);
-       } else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
-               arch_timer_rate = freq;
-       } else {
-               panic("unable to determine clock-frequency");
-       }
-
-       /* Setup IRQ numbers */
-       timers.tmr_irq = irq_of_parse_and_map(node, 0);
-
-       /* Setup IO addresses */
-       timers.tmr_regs = of_iomap(node, 0);
-
-       kona_timer_disable_and_clear(timers.tmr_regs);
-}
-
 static int kona_timer_set_next_event(unsigned long clc,
                                  struct clock_event_device *unused)
 {
@@ -198,7 +173,34 @@ static struct irqaction kona_timer_irq = {
 
 static void __init kona_timer_init(struct device_node *node)
 {
-       kona_timers_init(node);
+       u32 freq;
+       struct clk *external_clk;
+
+       if (!of_device_is_available(node)) {
+               pr_info("Kona Timer v1 marked as disabled in device tree\n");
+               return;
+       }
+
+       external_clk = of_clk_get_by_name(node, NULL);
+
+       if (!IS_ERR(external_clk)) {
+               arch_timer_rate = clk_get_rate(external_clk);
+               clk_prepare_enable(external_clk);
+       } else if (!of_property_read_u32(node, "clock-frequency", &freq)) {
+               arch_timer_rate = freq;
+       } else {
+               pr_err("Kona Timer v1 unable to determine clock-frequency");
+               return;
+       }
+
+       /* Setup IRQ numbers */
+       timers.tmr_irq = irq_of_parse_and_map(node, 0);
+
+       /* Setup IO addresses */
+       timers.tmr_regs = of_iomap(node, 0);
+
+       kona_timer_disable_and_clear(timers.tmr_regs);
+
        kona_timer_clockevents_init();
        setup_irq(timers.tmr_irq, &kona_timer_irq);
        kona_timer_set_next_event((arch_timer_rate / HZ), NULL);
index 02821b06a39e33be4cb403b202286deb530ff399..a918bc481c52c46a83f2e1ff1a50a96dc4180082 100644 (file)
@@ -54,7 +54,7 @@ static inline void pit_irq_acknowledge(void)
 
 static u64 pit_read_sched_clock(void)
 {
-       return __raw_readl(clksrc_base + PITCVAL);
+       return ~__raw_readl(clksrc_base + PITCVAL);
 }
 
 static int __init pit_clocksource_init(unsigned long rate)
index a36749f1e44a869418e1bcab6481334948618391..9b0ea0a6e26ebd4b5f07360d923d1ad509c41d46 100644 (file)
@@ -139,7 +139,6 @@ static int cn_call_callback(struct sk_buff *skb)
        spin_unlock_bh(&dev->cbdev->queue_lock);
 
        if (cbq != NULL) {
-               err = 0;
                cbq->callback(msg, nsp);
                kfree_skb(skb);
                cn_queue_release_callback(cbq);
index 08ca8c9f41cdeb27f6e4bb4879b2912798e1a72e..199b52b7c3e1ad6e9d00102905a215137901b71d 100644 (file)
@@ -1109,12 +1109,27 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                goto err_set_policy_cpu;
        }
 
+       /* related cpus should atleast have policy->cpus */
+       cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
+
+       /*
+        * affected cpus must always be the one, which are online. We aren't
+        * managing offline cpus here.
+        */
+       cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
+
+       if (!frozen) {
+               policy->user_policy.min = policy->min;
+               policy->user_policy.max = policy->max;
+       }
+
+       down_write(&policy->rwsem);
        write_lock_irqsave(&cpufreq_driver_lock, flags);
        for_each_cpu(j, policy->cpus)
                per_cpu(cpufreq_cpu_data, j) = policy;
        write_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
-       if (cpufreq_driver->get) {
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
                policy->cur = cpufreq_driver->get(policy->cpu);
                if (!policy->cur) {
                        pr_err("%s: ->get() failed\n", __func__);
@@ -1162,20 +1177,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                }
        }
 
-       /* related cpus should atleast have policy->cpus */
-       cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
-
-       /*
-        * affected cpus must always be the one, which are online. We aren't
-        * managing offline cpus here.
-        */
-       cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
-
-       if (!frozen) {
-               policy->user_policy.min = policy->min;
-               policy->user_policy.max = policy->max;
-       }
-
        blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
                                     CPUFREQ_START, policy);
 
@@ -1206,6 +1207,7 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                policy->user_policy.policy = policy->policy;
                policy->user_policy.governor = policy->governor;
        }
+       up_write(&policy->rwsem);
 
        kobject_uevent(&policy->kobj, KOBJ_ADD);
        up_read(&cpufreq_rwsem);
@@ -1323,8 +1325,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
        up_read(&policy->rwsem);
 
        if (cpu != policy->cpu) {
-               if (!frozen)
-                       sysfs_remove_link(&dev->kobj, "cpufreq");
+               sysfs_remove_link(&dev->kobj, "cpufreq");
        } else if (cpus > 1) {
                new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu);
                if (new_cpu >= 0) {
@@ -1547,23 +1548,16 @@ static unsigned int __cpufreq_get(unsigned int cpu)
  */
 unsigned int cpufreq_get(unsigned int cpu)
 {
-       struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
+       struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
        unsigned int ret_freq = 0;
 
-       if (cpufreq_disabled() || !cpufreq_driver)
-               return -ENOENT;
-
-       BUG_ON(!policy);
-
-       if (!down_read_trylock(&cpufreq_rwsem))
-               return 0;
-
-       down_read(&policy->rwsem);
-
-       ret_freq = __cpufreq_get(cpu);
+       if (policy) {
+               down_read(&policy->rwsem);
+               ret_freq = __cpufreq_get(cpu);
+               up_read(&policy->rwsem);
 
-       up_read(&policy->rwsem);
-       up_read(&cpufreq_rwsem);
+               cpufreq_cpu_put(policy);
+       }
 
        return ret_freq;
 }
@@ -2149,7 +2143,7 @@ int cpufreq_update_policy(unsigned int cpu)
         * BIOS might change freq behind our back
         * -> ask driver for current freq and notify governors about a change
         */
-       if (cpufreq_driver->get) {
+       if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
                new_policy.cur = cpufreq_driver->get(cpu);
                if (!policy->cur) {
                        pr_debug("Driver did not initialize current freq");
index 79606f473f481b516069f66ce3c8a17ee60b053c..2cd36b9297f3de01a4b5f2ed246d738e123d7991 100644 (file)
 
 #define SAMPLE_COUNT           3
 
-#define BYT_RATIOS     0x66a
-#define BYT_VIDS        0x66b
+#define BYT_RATIOS             0x66a
+#define BYT_VIDS               0x66b
+#define BYT_TURBO_RATIOS       0x66c
 
-#define FRAC_BITS 8
+
+#define FRAC_BITS 6
 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
 #define fp_toint(X) ((X) >> FRAC_BITS)
+#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS)
 
 static inline int32_t mul_fp(int32_t x, int32_t y)
 {
@@ -51,8 +54,6 @@ static inline int32_t div_fp(int32_t x, int32_t y)
        return div_s64((int64_t)x << FRAC_BITS, (int64_t)y);
 }
 
-static u64 energy_divisor;
-
 struct sample {
        int32_t core_pct_busy;
        u64 aperf;
@@ -359,7 +360,7 @@ static int byt_get_min_pstate(void)
 {
        u64 value;
        rdmsrl(BYT_RATIOS, value);
-       return value & 0xFF;
+       return (value >> 8) & 0xFF;
 }
 
 static int byt_get_max_pstate(void)
@@ -369,6 +370,13 @@ static int byt_get_max_pstate(void)
        return (value >> 16) & 0xFF;
 }
 
+static int byt_get_turbo_pstate(void)
+{
+       u64 value;
+       rdmsrl(BYT_TURBO_RATIOS, value);
+       return value & 0x3F;
+}
+
 static void byt_set_pstate(struct cpudata *cpudata, int pstate)
 {
        u64 val;
@@ -471,7 +479,7 @@ static struct cpu_defaults byt_params = {
        .funcs = {
                .get_max = byt_get_max_pstate,
                .get_min = byt_get_min_pstate,
-               .get_turbo = byt_get_max_pstate,
+               .get_turbo = byt_get_turbo_pstate,
                .set = byt_set_pstate,
                .get_vid = byt_get_vid,
        },
@@ -549,18 +557,20 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
 static inline void intel_pstate_calc_busy(struct cpudata *cpu,
                                        struct sample *sample)
 {
-       u64 core_pct;
-       u64 c0_pct;
+       int32_t core_pct;
+       int32_t c0_pct;
+
+       core_pct = div_fp(int_tofp((sample->aperf)),
+                       int_tofp((sample->mperf)));
+       core_pct = mul_fp(core_pct, int_tofp(100));
+       FP_ROUNDUP(core_pct);
 
-       core_pct = div64_u64(sample->aperf * 100, sample->mperf);
+       c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc));
 
-       c0_pct = div64_u64(sample->mperf * 100, sample->tsc);
        sample->freq = fp_toint(
-               mul_fp(int_tofp(cpu->pstate.max_pstate),
-                       int_tofp(core_pct * 1000)));
+               mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
 
-       sample->core_pct_busy = mul_fp(int_tofp(core_pct),
-                               div_fp(int_tofp(c0_pct + 1), int_tofp(100)));
+       sample->core_pct_busy = mul_fp(core_pct, c0_pct);
 }
 
 static inline void intel_pstate_sample(struct cpudata *cpu)
@@ -572,6 +582,10 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
        rdmsrl(MSR_IA32_MPERF, mperf);
        tsc = native_read_tsc();
 
+       aperf = aperf >> FRAC_BITS;
+       mperf = mperf >> FRAC_BITS;
+       tsc = tsc >> FRAC_BITS;
+
        cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT;
        cpu->samples[cpu->sample_ptr].aperf = aperf;
        cpu->samples[cpu->sample_ptr].mperf = mperf;
@@ -603,7 +617,8 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
        core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy;
        max_pstate = int_tofp(cpu->pstate.max_pstate);
        current_pstate = int_tofp(cpu->pstate.current_pstate);
-       return mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+       core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
+       return FP_ROUNDUP(core_busy);
 }
 
 static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
@@ -630,12 +645,10 @@ static void intel_pstate_timer_func(unsigned long __data)
 {
        struct cpudata *cpu = (struct cpudata *) __data;
        struct sample *sample;
-       u64 energy;
 
        intel_pstate_sample(cpu);
 
        sample = &cpu->samples[cpu->sample_ptr];
-       rdmsrl(MSR_PKG_ENERGY_STATUS, energy);
 
        intel_pstate_adjust_busy_pstate(cpu);
 
@@ -644,7 +657,6 @@ static void intel_pstate_timer_func(unsigned long __data)
                        cpu->pstate.current_pstate,
                        sample->mperf,
                        sample->aperf,
-                       div64_u64(energy, energy_divisor),
                        sample->freq);
 
        intel_pstate_set_sample_time(cpu);
@@ -926,7 +938,6 @@ static int __init intel_pstate_init(void)
        int cpu, rc = 0;
        const struct x86_cpu_id *id;
        struct cpu_defaults *cpu_info;
-       u64 units;
 
        if (no_load)
                return -ENODEV;
@@ -960,9 +971,6 @@ static int __init intel_pstate_init(void)
        if (rc)
                goto out;
 
-       rdmsrl(MSR_RAPL_POWER_UNIT, units);
-       energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */
-
        intel_pstate_debug_expose_params();
        intel_pstate_sysfs_expose_params();
 
index e10b646634d77ff3a4bcf0c54d154a91c7c35805..6684e0342792517577fde32d56542b3ad84d15af 100644 (file)
@@ -1076,7 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
 {
        struct powernow_k8_data *data;
        struct init_on_cpu init_on_cpu;
-       int rc;
+       int rc, cpu;
 
        smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1);
        if (rc)
@@ -1140,7 +1140,9 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
        pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
                 data->currfid, data->currvid);
 
-       per_cpu(powernow_data, pol->cpu) = data;
+       /* Point all the CPUs in this policy to the same data */
+       for_each_cpu(cpu, pol->cpus)
+               per_cpu(powernow_data, cpu) = data;
 
        return 0;
 
@@ -1155,6 +1157,7 @@ err_out:
 static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
 {
        struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu);
+       int cpu;
 
        if (!data)
                return -EINVAL;
@@ -1165,7 +1168,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol)
 
        kfree(data->powernow_table);
        kfree(data);
-       per_cpu(powernow_data, pol->cpu) = NULL;
+       for_each_cpu(cpu, pol->cpus)
+               per_cpu(powernow_data, cpu) = NULL;
 
        return 0;
 }
index 6c4c000671c50d88885bb39618c5ae9e4ceabe42..1e5481d88a262c655aec0d381574341531f5f4ae 100644 (file)
@@ -158,6 +158,15 @@ static inline unsigned long nx842_get_scatterlist_size(
        return sl->entry_nr * sizeof(struct nx842_slentry);
 }
 
+static inline unsigned long nx842_get_pa(void *addr)
+{
+       if (is_vmalloc_addr(addr))
+               return page_to_phys(vmalloc_to_page(addr))
+                      + offset_in_page(addr);
+       else
+               return __pa(addr);
+}
+
 static int nx842_build_scatterlist(unsigned long buf, int len,
                        struct nx842_scatterlist *sl)
 {
@@ -168,7 +177,7 @@ static int nx842_build_scatterlist(unsigned long buf, int len,
 
        entry = sl->entries;
        while (len) {
-               entry->ptr = __pa(buf);
+               entry->ptr = nx842_get_pa((void *)buf);
                nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE);
                if (nextpage < buf + len) {
                        /* we aren't at the end yet */
@@ -370,8 +379,8 @@ int nx842_compress(const unsigned char *in, unsigned int inlen,
        op.flags = NX842_OP_COMPRESS;
        csbcpb = &workmem->csbcpb;
        memset(csbcpb, 0, sizeof(*csbcpb));
-       op.csbcpb = __pa(csbcpb);
-       op.out = __pa(slout.entries);
+       op.csbcpb = nx842_get_pa(csbcpb);
+       op.out = nx842_get_pa(slout.entries);
 
        for (i = 0; i < hdr->blocks_nr; i++) {
                /*
@@ -401,13 +410,13 @@ int nx842_compress(const unsigned char *in, unsigned int inlen,
                 */
                if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
                        /* Create direct DDE */
-                       op.in = __pa(inbuf);
+                       op.in = nx842_get_pa((void *)inbuf);
                        op.inlen = max_sync_size;
 
                } else {
                        /* Create indirect DDE (scatterlist) */
                        nx842_build_scatterlist(inbuf, max_sync_size, &slin);
-                       op.in = __pa(slin.entries);
+                       op.in = nx842_get_pa(slin.entries);
                        op.inlen = -nx842_get_scatterlist_size(&slin);
                }
 
@@ -565,7 +574,7 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen,
        op.flags = NX842_OP_DECOMPRESS;
        csbcpb = &workmem->csbcpb;
        memset(csbcpb, 0, sizeof(*csbcpb));
-       op.csbcpb = __pa(csbcpb);
+       op.csbcpb = nx842_get_pa(csbcpb);
 
        /*
         * max_sync_size may have changed since compression,
@@ -597,12 +606,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen,
                if (likely((inbuf & NX842_HW_PAGE_MASK) ==
                        ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) {
                        /* Create direct DDE */
-                       op.in = __pa(inbuf);
+                       op.in = nx842_get_pa((void *)inbuf);
                        op.inlen = hdr->sizes[i];
                } else {
                        /* Create indirect DDE (scatterlist) */
                        nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin);
-                       op.in = __pa(slin.entries);
+                       op.in = nx842_get_pa(slin.entries);
                        op.inlen = -nx842_get_scatterlist_size(&slin);
                }
 
@@ -613,12 +622,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen,
                 */
                if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
                        /* Create direct DDE */
-                       op.out = __pa(outbuf);
+                       op.out = nx842_get_pa((void *)outbuf);
                        op.outlen = max_sync_size;
                } else {
                        /* Create indirect DDE (scatterlist) */
                        nx842_build_scatterlist(outbuf, max_sync_size, &slout);
-                       op.out = __pa(slout.entries);
+                       op.out = nx842_get_pa(slout.entries);
                        op.outlen = -nx842_get_scatterlist_size(&slout);
                }
 
index 9bed1a2a67a12e44cde304995b6895e3f8296c2a..605b016bcea49dcea25d9515b2cec276ae974372 100644 (file)
@@ -346,6 +346,7 @@ config MOXART_DMA
        tristate "MOXART DMA support"
        depends on ARCH_MOXART
        select DMA_ENGINE
+       select DMA_OF
        select DMA_VIRTUAL_CHANNELS
        help
          Enable support for the MOXA ART SoC DMA controller.
index 4e7918339b1263a2720c3da11d271714dd9669ad..19041cefabb1c0ce8649ed8cf5ea41707fa7824f 100644 (file)
@@ -449,6 +449,7 @@ static const struct of_device_id sdma_dt_ids[] = {
        { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
        { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
        { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
+       { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdma_dt_ids);
index 87529181efccb9851467cc04be04bd91fecb15b3..4e3549a161324f29159775312b3c9d8075914359 100644 (file)
@@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
        attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
        for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
                chan = ioat_chan_by_index(instance, bit);
-               tasklet_schedule(&chan->cleanup_task);
+               if (test_bit(IOAT_RUN, &chan->state))
+                       tasklet_schedule(&chan->cleanup_task);
        }
 
        writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
@@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
 {
        struct ioat_chan_common *chan = data;
 
-       tasklet_schedule(&chan->cleanup_task);
+       if (test_bit(IOAT_RUN, &chan->state))
+               tasklet_schedule(&chan->cleanup_task);
 
        return IRQ_HANDLED;
 }
@@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c
        chan->timer.function = device->timer_fn;
        chan->timer.data = data;
        tasklet_init(&chan->cleanup_task, device->cleanup_fn, data);
-       tasklet_disable(&chan->cleanup_task);
 }
 
 /**
@@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c)
        writel(((u64) chan->completion_dma) >> 32,
               chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
 
-       tasklet_enable(&chan->cleanup_task);
+       set_bit(IOAT_RUN, &chan->state);
        ioat1_dma_start_null_desc(ioat);  /* give chain to dma device */
        dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n",
                __func__, ioat->desccount);
        return ioat->desccount;
 }
 
+void ioat_stop(struct ioat_chan_common *chan)
+{
+       struct ioatdma_device *device = chan->device;
+       struct pci_dev *pdev = device->pdev;
+       int chan_id = chan_num(chan);
+       struct msix_entry *msix;
+
+       /* 1/ stop irq from firing tasklets
+        * 2/ stop the tasklet from re-arming irqs
+        */
+       clear_bit(IOAT_RUN, &chan->state);
+
+       /* flush inflight interrupts */
+       switch (device->irq_mode) {
+       case IOAT_MSIX:
+               msix = &device->msix_entries[chan_id];
+               synchronize_irq(msix->vector);
+               break;
+       case IOAT_MSI:
+       case IOAT_INTX:
+               synchronize_irq(pdev->irq);
+               break;
+       default:
+               break;
+       }
+
+       /* flush inflight timers */
+       del_timer_sync(&chan->timer);
+
+       /* flush inflight tasklet runs */
+       tasklet_kill(&chan->cleanup_task);
+
+       /* final cleanup now that everything is quiesced and can't re-arm */
+       device->cleanup_fn((unsigned long) &chan->common);
+}
+
 /**
  * ioat1_dma_free_chan_resources - release all the descriptors
  * @chan: the channel to be cleaned
@@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c)
        if (ioat->desccount == 0)
                return;
 
-       tasklet_disable(&chan->cleanup_task);
-       del_timer_sync(&chan->timer);
-       ioat1_cleanup(ioat);
+       ioat_stop(chan);
 
        /* Delay 100ms after reset to allow internal DMA logic to quiesce
         * before removing DMA descriptor resources.
@@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest,
 static void ioat1_cleanup_event(unsigned long data)
 {
        struct ioat_dma_chan *ioat = to_ioat_chan((void *) data);
+       struct ioat_chan_common *chan = &ioat->base;
 
        ioat1_cleanup(ioat);
+       if (!test_bit(IOAT_RUN, &chan->state))
+               return;
        writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
index 11fb877ddca9a9b0888d23952dea8fb48245b617..e982f00a984399a3838f7b47ef2e21a2aab84495 100644 (file)
@@ -356,6 +356,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
 void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
 void ioat_kobject_del(struct ioatdma_device *device);
 int ioat_dma_setup_interrupts(struct ioatdma_device *device);
+void ioat_stop(struct ioat_chan_common *chan);
 extern const struct sysfs_ops ioat_sysfs_ops;
 extern struct ioat_sysfs_entry ioat_version_attr;
 extern struct ioat_sysfs_entry ioat_cap_attr;
index 5d3affe7e976165ec5576ac8c6551dd438af7786..8d1058085eeb85beb3fb2d6ab88c57160ef0cf15 100644 (file)
@@ -190,8 +190,11 @@ static void ioat2_cleanup(struct ioat2_dma_chan *ioat)
 void ioat2_cleanup_event(unsigned long data)
 {
        struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+       struct ioat_chan_common *chan = &ioat->base;
 
        ioat2_cleanup(ioat);
+       if (!test_bit(IOAT_RUN, &chan->state))
+               return;
        writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
@@ -553,10 +556,10 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
        ioat->issued = 0;
        ioat->tail = 0;
        ioat->alloc_order = order;
+       set_bit(IOAT_RUN, &chan->state);
        spin_unlock_bh(&ioat->prep_lock);
        spin_unlock_bh(&chan->cleanup_lock);
 
-       tasklet_enable(&chan->cleanup_task);
        ioat2_start_null_desc(ioat);
 
        /* check that we got off the ground */
@@ -566,7 +569,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c)
        } while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status));
 
        if (is_ioat_active(status) || is_ioat_idle(status)) {
-               set_bit(IOAT_RUN, &chan->state);
                return 1 << ioat->alloc_order;
        } else {
                u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET);
@@ -809,11 +811,8 @@ void ioat2_free_chan_resources(struct dma_chan *c)
        if (!ioat->ring)
                return;
 
-       tasklet_disable(&chan->cleanup_task);
-       del_timer_sync(&chan->timer);
-       device->cleanup_fn((unsigned long) c);
+       ioat_stop(chan);
        device->reset_hw(chan);
-       clear_bit(IOAT_RUN, &chan->state);
 
        spin_lock_bh(&chan->cleanup_lock);
        spin_lock_bh(&ioat->prep_lock);
index 820817e97e626a498561a9e5f0f3a61f22ffc9fa..b9b38a1cf92fbdc4147e70af93508f0d9caf6867 100644 (file)
@@ -464,8 +464,11 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat)
 static void ioat3_cleanup_event(unsigned long data)
 {
        struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data);
+       struct ioat_chan_common *chan = &ioat->base;
 
        ioat3_cleanup(ioat);
+       if (!test_bit(IOAT_RUN, &chan->state))
+               return;
        writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
index 53fb0c8365b0b27f29a893a3072103c9fb2360e9..766b68ed505c4d2b3964bfb1f0de6ab5ae1ff3a9 100644 (file)
@@ -497,8 +497,8 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
                if (!mv_can_chain(grp_start))
                        goto submit_done;
 
-               dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %x\n",
-                       old_chain_tail->async_tx.phys);
+               dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n",
+                       &old_chain_tail->async_tx.phys);
 
                /* fix up the hardware chain */
                mv_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys);
@@ -527,7 +527,8 @@ submit_done:
 /* returns the number of allocated descriptors */
 static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
 {
-       char *hw_desc;
+       void *virt_desc;
+       dma_addr_t dma_desc;
        int idx;
        struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
        struct mv_xor_desc_slot *slot = NULL;
@@ -542,17 +543,16 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
                                " %d descriptor slots", idx);
                        break;
                }
-               hw_desc = (char *) mv_chan->dma_desc_pool_virt;
-               slot->hw_desc = (void *) &hw_desc[idx * MV_XOR_SLOT_SIZE];
+               virt_desc = mv_chan->dma_desc_pool_virt;
+               slot->hw_desc = virt_desc + idx * MV_XOR_SLOT_SIZE;
 
                dma_async_tx_descriptor_init(&slot->async_tx, chan);
                slot->async_tx.tx_submit = mv_xor_tx_submit;
                INIT_LIST_HEAD(&slot->chain_node);
                INIT_LIST_HEAD(&slot->slot_node);
                INIT_LIST_HEAD(&slot->tx_list);
-               hw_desc = (char *) mv_chan->dma_desc_pool;
-               slot->async_tx.phys =
-                       (dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE];
+               dma_desc = mv_chan->dma_desc_pool;
+               slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE;
                slot->idx = idx++;
 
                spin_lock_bh(&mv_chan->lock);
@@ -582,8 +582,8 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        int slot_cnt;
 
        dev_dbg(mv_chan_to_devp(mv_chan),
-               "%s dest: %x src %x len: %u flags: %ld\n",
-               __func__, dest, src, len, flags);
+               "%s dest: %pad src %pad len: %u flags: %ld\n",
+               __func__, &dest, &src, len, flags);
        if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
                return NULL;
 
@@ -626,8 +626,8 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
        BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
 
        dev_dbg(mv_chan_to_devp(mv_chan),
-               "%s src_cnt: %d len: dest %x %u flags: %ld\n",
-               __func__, src_cnt, len, dest, flags);
+               "%s src_cnt: %d len: %u dest %pad flags: %ld\n",
+               __func__, src_cnt, len, &dest, flags);
 
        spin_lock_bh(&mv_chan->lock);
        slot_cnt = mv_chan_xor_slot_count(len, src_cnt);
index 00a2de957b234da060fe5e03592b171f50fa53d1..bf18c786ed40fbaae2a487246df5da85457fbec1 100644 (file)
@@ -1641,6 +1641,7 @@ static void dma_tasklet(unsigned long data)
        struct d40_chan *d40c = (struct d40_chan *) data;
        struct d40_desc *d40d;
        unsigned long flags;
+       bool callback_active;
        dma_async_tx_callback callback;
        void *callback_param;
 
@@ -1668,6 +1669,7 @@ static void dma_tasklet(unsigned long data)
        }
 
        /* Callback to client */
+       callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT);
        callback = d40d->txd.callback;
        callback_param = d40d->txd.callback_param;
 
@@ -1690,7 +1692,7 @@ static void dma_tasklet(unsigned long data)
 
        spin_unlock_irqrestore(&d40c->lock, flags);
 
-       if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT))
+       if (callback_active && callback)
                callback(callback_param);
 
        return;
index e8c9ef03495be4a450944ec996cbe85bb11156e3..33edd67663443123ab73dc91ee18550c1a9b62fb 100644 (file)
@@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req)
  *
  *             called with the mem_ctls_mutex held
  */
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
+                               bool init)
 {
        edac_dbg(0, "\n");
 
@@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
        if (mci->op_state != OP_RUNNING_POLL)
                return;
 
-       INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+       if (init)
+               INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+
        mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
 }
 
@@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
  *     user space has updated our poll period value, need to
  *     reset our workq delays
  */
-void edac_mc_reset_delay_period(int value)
+void edac_mc_reset_delay_period(unsigned long value)
 {
        struct mem_ctl_info *mci;
        struct list_head *item;
@@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value)
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
 
-               edac_mc_workq_setup(mci, (unsigned long) value);
+               edac_mc_workq_setup(mci, value, false);
        }
 
        mutex_unlock(&mem_ctls_mutex);
@@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
                /* This instance is NOW RUNNING */
                mci->op_state = OP_RUNNING_POLL;
 
-               edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+               edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
        } else {
                mci->op_state = OP_RUNNING_INTERRUPT;
        }
index 51c0362acf5c456db84eb0786722c284849b30b9..b335c6ab5efe02e0ef9b5742e8691e617b5a30af 100644 (file)
@@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void)
 
 static int edac_set_poll_msec(const char *val, struct kernel_param *kp)
 {
-       long l;
+       unsigned long l;
        int ret;
 
        if (!val)
                return -EINVAL;
 
-       ret = kstrtol(val, 0, &l);
+       ret = kstrtoul(val, 0, &l);
        if (ret)
                return ret;
-       if ((int)l != l)
+
+       if (l < 1000)
                return -EINVAL;
-       *((int *)kp->arg) = l;
+
+       *((unsigned long *)kp->arg) = l;
 
        /* notify edac_mc engine to reset the poll period */
        edac_mc_reset_delay_period(l);
index 3d139c6e7fe325719b7ddaf4b38127f5895f8bb8..f2118bfcf8dfbd861d24754320ac0a0439cfb9ed 100644 (file)
@@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
 extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
                                           *edac_dev, unsigned long value);
-extern void edac_mc_reset_delay_period(int value);
+extern void edac_mc_reset_delay_period(unsigned long value);
 
 extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
 
index d63f4798f7d09127872f97ed925a5af64a75f81f..57e96a3350f0595ab002a5ff1285d85b44dd6e3f 100644 (file)
@@ -943,33 +943,35 @@ static int i7300_get_devices(struct mem_ctl_info *mci)
 
        /* Attempt to 'get' the MCH register we want */
        pdev = NULL;
-       while (!pvt->pci_dev_16_1_fsb_addr_map ||
-              !pvt->pci_dev_16_2_fsb_err_regs) {
-               pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-                                     PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev);
-               if (!pdev) {
-                       /* End of list, leave */
-                       i7300_printk(KERN_ERR,
-                               "'system address,Process Bus' "
-                               "device not found:"
-                               "vendor 0x%x device 0x%x ERR funcs "
-                               "(broken BIOS?)\n",
-                               PCI_VENDOR_ID_INTEL,
-                               PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
-                       goto error;
-               }
-
+       while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                     PCI_DEVICE_ID_INTEL_I7300_MCH_ERR,
+                                     pdev))) {
                /* Store device 16 funcs 1 and 2 */
                switch (PCI_FUNC(pdev->devfn)) {
                case 1:
-                       pvt->pci_dev_16_1_fsb_addr_map = pdev;
+                       if (!pvt->pci_dev_16_1_fsb_addr_map)
+                               pvt->pci_dev_16_1_fsb_addr_map =
+                                                       pci_dev_get(pdev);
                        break;
                case 2:
-                       pvt->pci_dev_16_2_fsb_err_regs = pdev;
+                       if (!pvt->pci_dev_16_2_fsb_err_regs)
+                               pvt->pci_dev_16_2_fsb_err_regs =
+                                                       pci_dev_get(pdev);
                        break;
                }
        }
 
+       if (!pvt->pci_dev_16_1_fsb_addr_map ||
+           !pvt->pci_dev_16_2_fsb_err_regs) {
+               /* At least one device was not found */
+               i7300_printk(KERN_ERR,
+                       "'system address,Process Bus' device not found:"
+                       "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n",
+                       PCI_VENDOR_ID_INTEL,
+                       PCI_DEVICE_ID_INTEL_I7300_MCH_ERR);
+               goto error;
+       }
+
        edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
                 pci_name(pvt->pci_dev_16_0_fsb_ctlr),
                 pvt->pci_dev_16_0_fsb_ctlr->vendor,
index 87533ca7752e0105683210913f83731a9b988aab..d871275196f6f04b6542e4941ee433e41fcfdf64 100644 (file)
@@ -1334,14 +1334,19 @@ static int i7core_get_onedevice(struct pci_dev **prev,
         * is at addr 8086:2c40, instead of 8086:2c41. So, we need
         * to probe for the alternate address in case of failure
         */
-       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
+       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) {
+               pci_dev_get(*prev);     /* pci_get_device will put it */
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+       }
 
-       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
+       if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE &&
+           !pdev) {
+               pci_dev_get(*prev);     /* pci_get_device will put it */
                pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                      PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
                                      *prev);
+       }
 
        if (!pdev) {
                if (*prev) {
index c20602f601ee22732635aa3fa04fe94e44ed6020..98a14f6143a7087accee9c5d2b127c99c300b81d 100644 (file)
@@ -222,27 +222,19 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
        struct snd_soc_dapm_context *dapm = arizona->dapm;
        int ret;
 
-       mutex_lock(&dapm->card->dapm_mutex);
-
        ret = snd_soc_dapm_force_enable_pin(dapm, widget);
        if (ret != 0)
                dev_warn(arizona->dev, "Failed to enable %s: %d\n",
                         widget, ret);
 
-       mutex_unlock(&dapm->card->dapm_mutex);
-
        snd_soc_dapm_sync(dapm);
 
        if (!arizona->pdata.micd_force_micbias) {
-               mutex_lock(&dapm->card->dapm_mutex);
-
                ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
                if (ret != 0)
                        dev_warn(arizona->dev, "Failed to disable %s: %d\n",
                                 widget, ret);
 
-               mutex_unlock(&dapm->card->dapm_mutex);
-
                snd_soc_dapm_sync(dapm);
        }
 }
@@ -304,16 +296,12 @@ static void arizona_stop_mic(struct arizona_extcon_info *info)
                                 ARIZONA_MICD_ENA, 0,
                                 &change);
 
-       mutex_lock(&dapm->card->dapm_mutex);
-
        ret = snd_soc_dapm_disable_pin(dapm, widget);
        if (ret != 0)
                dev_warn(arizona->dev,
                         "Failed to disable %s: %d\n",
                         widget, ret);
 
-       mutex_unlock(&dapm->card->dapm_mutex);
-
        snd_soc_dapm_sync(dapm);
 
        if (info->micd_reva) {
index de4aa409abe2988d8dc5b421e969ab5256fb4009..2c6d5e118ac129e5ab9c24f09557b27e3248f3ea 100644 (file)
@@ -916,7 +916,7 @@ static int lookup_existing_device(struct device *dev, void *data)
                old->config_rom_retries = 0;
                fw_notice(card, "rediscovered device %s\n", dev_name(dev));
 
-               PREPARE_DELAYED_WORK(&old->work, fw_device_update);
+               old->workfn = fw_device_update;
                fw_schedule_device_work(old, 0);
 
                if (current_node == card->root_node)
@@ -1075,7 +1075,7 @@ static void fw_device_init(struct work_struct *work)
        if (atomic_cmpxchg(&device->state,
                           FW_DEVICE_INITIALIZING,
                           FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
-               PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+               device->workfn = fw_device_shutdown;
                fw_schedule_device_work(device, SHUTDOWN_DELAY);
        } else {
                fw_notice(card, "created device %s: GUID %08x%08x, S%d00\n",
@@ -1196,13 +1196,20 @@ static void fw_device_refresh(struct work_struct *work)
                  dev_name(&device->device), fw_rcode_string(ret));
  gone:
        atomic_set(&device->state, FW_DEVICE_GONE);
-       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+       device->workfn = fw_device_shutdown;
        fw_schedule_device_work(device, SHUTDOWN_DELAY);
  out:
        if (node_id == card->root_node->node_id)
                fw_schedule_bm_work(card, 0);
 }
 
+static void fw_device_workfn(struct work_struct *work)
+{
+       struct fw_device *device = container_of(to_delayed_work(work),
+                                               struct fw_device, work);
+       device->workfn(work);
+}
+
 void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
 {
        struct fw_device *device;
@@ -1252,7 +1259,8 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                 * power-up after getting plugged in.  We schedule the
                 * first config rom scan half a second after bus reset.
                 */
-               INIT_DELAYED_WORK(&device->work, fw_device_init);
+               device->workfn = fw_device_init;
+               INIT_DELAYED_WORK(&device->work, fw_device_workfn);
                fw_schedule_device_work(device, INITIAL_DELAY);
                break;
 
@@ -1268,7 +1276,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                if (atomic_cmpxchg(&device->state,
                            FW_DEVICE_RUNNING,
                            FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
+                       device->workfn = fw_device_refresh;
                        fw_schedule_device_work(device,
                                device->is_local ? 0 : INITIAL_DELAY);
                }
@@ -1283,7 +1291,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                smp_wmb();  /* update node_id before generation */
                device->generation = card->generation;
                if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+                       device->workfn = fw_device_update;
                        fw_schedule_device_work(device, 0);
                }
                break;
@@ -1308,7 +1316,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device = node->data;
                if (atomic_xchg(&device->state,
                                FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
-                       PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+                       device->workfn = fw_device_shutdown;
                        fw_schedule_device_work(device,
                                list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
                }
index 6b895986dc225115573add201958e60897934853..4af0a7bad7f21561cc4e7a29031c238a34f0135d 100644 (file)
@@ -929,8 +929,6 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
        if (rcode == RCODE_COMPLETE) {
                fwnet_transmit_packet_done(ptask);
        } else {
-               fwnet_transmit_packet_failed(ptask);
-
                if (printk_timed_ratelimit(&j,  1000) || rcode != last_rcode) {
                        dev_err(&ptask->dev->netdev->dev,
                                "fwnet_write_complete failed: %x (skipped %d)\n",
@@ -938,8 +936,10 @@ static void fwnet_write_complete(struct fw_card *card, int rcode,
 
                        errors_skipped = 0;
                        last_rcode = rcode;
-               } else
+               } else {
                        errors_skipped++;
+               }
+               fwnet_transmit_packet_failed(ptask);
        }
 }
 
index 6f74d8d3f70015a089f02948294454863cb6bcd7..8db66321956068701cde997e0bc25e167e781eb3 100644 (file)
@@ -290,7 +290,6 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
 #define QUIRK_NO_MSI                   0x10
 #define QUIRK_TI_SLLZ059               0x20
 #define QUIRK_IR_WAKE                  0x40
-#define QUIRK_PHY_LCTRL_TIMEOUT                0x80
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
@@ -303,10 +302,7 @@ static const struct {
                QUIRK_BE_HEADERS},
 
        {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6,
-               QUIRK_PHY_LCTRL_TIMEOUT | QUIRK_NO_MSI},
-
-       {PCI_VENDOR_ID_ATT, PCI_ANY_ID, PCI_ANY_ID,
-               QUIRK_PHY_LCTRL_TIMEOUT},
+               QUIRK_NO_MSI},
 
        {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID,
                QUIRK_RESET_PACKET},
@@ -353,7 +349,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
        ", disable MSI = "              __stringify(QUIRK_NO_MSI)
        ", TI SLLZ059 erratum = "       __stringify(QUIRK_TI_SLLZ059)
        ", IR wake unreliable = "       __stringify(QUIRK_IR_WAKE)
-       ", phy LCtrl timeout = "        __stringify(QUIRK_PHY_LCTRL_TIMEOUT)
        ")");
 
 #define OHCI_PARAM_DEBUG_AT_AR         1
@@ -2299,9 +2294,6 @@ static int ohci_enable(struct fw_card *card,
         * TI TSB82AA2 + TSB81BA3(A) cards signal LPS enabled early but
         * cannot actually use the phy at that time.  These need tens of
         * millisecods pause between LPS write and first phy access too.
-        *
-        * But do not wait for 50msec on Agere/LSI cards.  Their phy
-        * arbitration state machine may time out during such a long wait.
         */
 
        reg_write(ohci, OHCI1394_HCControlSet,
@@ -2309,11 +2301,8 @@ static int ohci_enable(struct fw_card *card,
                  OHCI1394_HCControl_postedWriteEnable);
        flush_writes(ohci);
 
-       if (!(ohci->quirks & QUIRK_PHY_LCTRL_TIMEOUT))
+       for (lps = 0, i = 0; !lps && i < 3; i++) {
                msleep(50);
-
-       for (lps = 0, i = 0; !lps && i < 150; i++) {
-               msleep(1);
                lps = reg_read(ohci, OHCI1394_HCControlSet) &
                      OHCI1394_HCControl_LPS;
        }
index 281029daf98c7ea291886d46ecf05378bfa98718..7aef911fdc716d4874b7152b3c0d6e27bc8c1642 100644 (file)
@@ -146,6 +146,7 @@ struct sbp2_logical_unit {
         */
        int generation;
        int retries;
+       work_func_t workfn;
        struct delayed_work work;
        bool has_sdev;
        bool blocked;
@@ -864,7 +865,7 @@ static void sbp2_login(struct work_struct *work)
        /* set appropriate retry limit(s) in BUSY_TIMEOUT register */
        sbp2_set_busy_timeout(lu);
 
-       PREPARE_DELAYED_WORK(&lu->work, sbp2_reconnect);
+       lu->workfn = sbp2_reconnect;
        sbp2_agent_reset(lu);
 
        /* This was a re-login. */
@@ -918,7 +919,7 @@ static void sbp2_login(struct work_struct *work)
         * If a bus reset happened, sbp2_update will have requeued
         * lu->work already.  Reset the work from reconnect to login.
         */
-       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+       lu->workfn = sbp2_login;
 }
 
 static void sbp2_reconnect(struct work_struct *work)
@@ -952,7 +953,7 @@ static void sbp2_reconnect(struct work_struct *work)
                    lu->retries++ >= 5) {
                        dev_err(tgt_dev(tgt), "failed to reconnect\n");
                        lu->retries = 0;
-                       PREPARE_DELAYED_WORK(&lu->work, sbp2_login);
+                       lu->workfn = sbp2_login;
                }
                sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5));
 
@@ -972,6 +973,13 @@ static void sbp2_reconnect(struct work_struct *work)
        sbp2_conditionally_unblock(lu);
 }
 
+static void sbp2_lu_workfn(struct work_struct *work)
+{
+       struct sbp2_logical_unit *lu = container_of(to_delayed_work(work),
+                                               struct sbp2_logical_unit, work);
+       lu->workfn(work);
+}
+
 static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
 {
        struct sbp2_logical_unit *lu;
@@ -998,7 +1006,8 @@ static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
        lu->blocked  = false;
        ++tgt->dont_block;
        INIT_LIST_HEAD(&lu->orb_list);
-       INIT_DELAYED_WORK(&lu->work, sbp2_login);
+       lu->workfn = sbp2_login;
+       INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn);
 
        list_add_tail(&lu->link, &tgt->lu_list);
        return 0;
index ee5b47904130bdaab802fb3ddb6bce0f5f73c215..9bb2cbd5c9f265e421ded04a69b72f37141a2663 100644 (file)
@@ -27,7 +27,7 @@ FMC_PARAM_BUSID(fwe_drv);
 /* The "file=" is like the generic "gateware=" used elsewhere */
 static char *fwe_file[FMC_MAX_CARDS];
 static int fwe_file_n;
-module_param_array_named(file, fwe_file, charp, &fwe_file_n, 444);
+module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444);
 
 static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw,
        int write)
index 697338772b64802fae727a8b6788756e28d15939..903f24d28ba065f5fdaceff34cbf55cf287c26f0 100644 (file)
@@ -403,6 +403,7 @@ config GPIO_GRGPIO
 
 config GPIO_TB10X
        bool
+       select GENERIC_IRQ_CHIP
        select OF_GPIO
 
 comment "I2C GPIO expanders:"
index 233d088ac59fd69e389c8b759fab75bb5af231eb..f32357e2d78d89cf5b645512279122eb87c78ccc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2013 Broadcom Corporation
+ * Copyright (C) 2012-2014 Broadcom Corporation
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -657,6 +657,6 @@ static struct platform_driver bcm_kona_gpio_driver = {
 
 module_platform_driver(bcm_kona_gpio_driver);
 
-MODULE_AUTHOR("Broadcom");
+MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>");
 MODULE_DESCRIPTION("Broadcom Kona GPIO Driver");
 MODULE_LICENSE("GPL v2");
index d3550274b8f7e64c293bc8d53ef7cd51598ed5f6..3c2ba2ad0ada7a0fa21d38021baeedf4a9a50583 100644 (file)
@@ -97,3 +97,4 @@ module_platform_driver(clps711x_gpio_driver);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
 MODULE_DESCRIPTION("CLPS711X GPIO driver");
+MODULE_ALIAS("platform:clps711x-gpio");
index d1b50ef5fab86928346ac741e7cbfc1c40d64ea0..e585163f1ad55202ecebd56d882992f8765e72fd 100644 (file)
@@ -394,8 +394,8 @@ static const struct irq_domain_ops intel_gpio_irq_ops = {
 
 static int intel_gpio_runtime_idle(struct device *dev)
 {
-       pm_schedule_suspend(dev, 500);
-       return -EBUSY;
+       int err = pm_schedule_suspend(dev, 500);
+       return err ?: -EBUSY;
 }
 
 static const struct dev_pm_ops intel_gpio_pm_ops = {
index 1d136eceda62db25575d0f4b86e2848ff26256a5..7081304d6797b4d27c6dab1309e4c0169a19dcd2 100644 (file)
@@ -40,6 +40,8 @@
 #error GPIO32 option is not enabled for your xtensa core variant
 #endif
 
+#if XCHAL_HAVE_CP
+
 static inline unsigned long enable_cp(unsigned long *cpenable)
 {
        unsigned long flags;
@@ -57,6 +59,20 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable)
        local_irq_restore(flags);
 }
 
+#else
+
+static inline unsigned long enable_cp(unsigned long *cpenable)
+{
+       *cpenable = 0; /* avoid uninitialized value warning */
+       return 0;
+}
+
+static inline void disable_cp(unsigned long flags, unsigned long cpenable)
+{
+}
+
+#endif /* XCHAL_HAVE_CP */
+
 static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset)
 {
        return 1; /* input only */
index acf3a36c9ebc453737b1a849aa6715f41b241d68..32982da82694be753d1072c90136d842a8a866ec 100644 (file)
@@ -68,15 +68,7 @@ void __armada_drm_queue_unref_work(struct drm_device *dev,
 {
        struct armada_private *priv = dev->dev_private;
 
-       /*
-        * Yes, we really must jump through these hoops just to store a
-        * _pointer_ to something into the kfifo.  This is utterly insane
-        * and idiotic, because it kfifo requires the _data_ pointed to by
-        * the pointer const, not the pointer itself.  Not only that, but
-        * you have to pass a pointer _to_ the pointer you want stored.
-        */
-       const struct drm_framebuffer *silly_api_alert = fb;
-       WARN_ON(!kfifo_put(&priv->fb_unref, &silly_api_alert));
+       WARN_ON(!kfifo_put(&priv->fb_unref, fb));
        schedule_work(&priv->fb_unref_work);
 }
 
index c8fcf12019f09c1eaffff1d72ea72c74714325e2..5f8b0c2b9a4461d2e07b1d7a3abb25f69837fc90 100644 (file)
@@ -2,6 +2,7 @@ config DRM_BOCHS
        tristate "DRM Support for bochs dispi vga interface (qemu stdvga)"
        depends on DRM && PCI
        select DRM_KMS_HELPER
+       select DRM_KMS_FB_HELPER
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index dffc836144cc96266a616902aa457b46c0ef1b33..f4dc9b7a3831f32d43f0e53cd8ed9791cac665ad 100644 (file)
@@ -296,6 +296,18 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
        case DRM_CAP_ASYNC_PAGE_FLIP:
                req->value = dev->mode_config.async_page_flip;
                break;
+       case DRM_CAP_CURSOR_WIDTH:
+               if (dev->mode_config.cursor_width)
+                       req->value = dev->mode_config.cursor_width;
+               else
+                       req->value = 64;
+               break;
+       case DRM_CAP_CURSOR_HEIGHT:
+               if (dev->mode_config.cursor_height)
+                       req->value = dev->mode_config.cursor_height;
+               else
+                       req->value = 64;
+               break;
        default:
                return -EINVAL;
        }
index 5736aaa7e86cb069d30fd458b5842fd42defae17..f7af69bcf3f452aff52647d830e3f1497ad21dca 100644 (file)
@@ -468,8 +468,8 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
        } else {
                list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
                                         legacy_dev_list) {
-                       drm_put_dev(dev);
                        list_del(&dev->legacy_dev_list);
+                       drm_put_dev(dev);
                }
        }
        DRM_INFO("Module unloaded\n");
index f227f544aa36f2104df33bbeacb5a8dc1e18bbd2..6e1a1a20cf6b4ab94a0f06f43d6470416dfcc879 100644 (file)
@@ -51,7 +51,7 @@ config DRM_EXYNOS_G2D
 
 config DRM_EXYNOS_IPP
        bool "Exynos DRM IPP"
-       depends on DRM_EXYNOS && !ARCH_MULTIPLATFORM
+       depends on DRM_EXYNOS
        help
          Choose this option if you want to use IPP feature for DRM.
 
@@ -69,6 +69,6 @@ config DRM_EXYNOS_ROTATOR
 
 config DRM_EXYNOS_GSC
        bool "Exynos DRM GSC"
-       depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5
+       depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM
        help
          Choose this option if you want to use Exynos GSC for DRM.
index 9d096a0c5f8d5f6bf0583d37f5efe433085504e4..c204b4e3356e80db01b736595d854075065768c0 100644 (file)
@@ -171,22 +171,28 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
        file->driver_priv = file_priv;
 
        ret = exynos_drm_subdrv_open(dev, file);
-       if (ret) {
-               kfree(file_priv);
-               file->driver_priv = NULL;
-       }
+       if (ret)
+               goto err_file_priv_free;
 
        anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
                                        NULL, 0);
        if (IS_ERR(anon_filp)) {
-               kfree(file_priv);
-               return PTR_ERR(anon_filp);
+               ret = PTR_ERR(anon_filp);
+               goto err_subdrv_close;
        }
 
        anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
        file_priv->anon_filp = anon_filp;
 
        return ret;
+
+err_subdrv_close:
+       exynos_drm_subdrv_close(dev, file);
+
+err_file_priv_free:
+       kfree(file_priv);
+       file->driver_priv = NULL;
+       return ret;
 }
 
 static void exynos_drm_preclose(struct drm_device *dev,
index 380aec28840b7e5ec4245e71207f0586f05efe75..6c1885eedfdfbd381d463763bf4d605e54e1c922 100644 (file)
@@ -607,7 +607,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
                reg_type = REG_TYPE_NONE;
                DRM_ERROR("Unknown register offset![%d]\n", reg_offset);
                break;
-       };
+       }
 
        return reg_type;
 }
index d519a4e5fe4022bd9101ede7a1e0edd2a4883dba..09312b8774709478f43ea8690f802651fa85feb4 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/types.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
-#include <plat/map-base.h>
 
 #include <drm/drmP.h>
 #include <drm/exynos_drm.h>
@@ -826,7 +825,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
                DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
 
                /*
-                * quf == NULL condition means all event deletion.
+                * qbuf == NULL condition means all event deletion.
                 * stop operations want to delete all event list.
                 * another case delete only same buf id.
                 */
index a0e10aeb0e674bf6472e4f5dee45a8f1322790cc..c021ddc1ffb4b4e982ac01874953dbb7239ddc31 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
+#include <linux/hdmi.h>
 
 #include <drm/exynos_drm.h>
 
 #define HDMI_AUI_VERSION       0x01
 #define HDMI_AUI_LENGTH        0x0A
 
-/* HDMI infoframe to configure HDMI out packet header, AUI and AVI */
-enum HDMI_PACKET_TYPE {
-       /* refer to Table 5-8 Packet Type in HDMI specification v1.4a */
-       /* InfoFrame packet type */
-       HDMI_PACKET_TYPE_INFOFRAME = 0x80,
-       /* Vendor-Specific InfoFrame */
-       HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1,
-       /* Auxiliary Video information InfoFrame */
-       HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2,
-       /* Audio information InfoFrame */
-       HDMI_PACKET_TYPE_AUI = HDMI_PACKET_TYPE_INFOFRAME + 4
-};
-
 enum hdmi_type {
        HDMI_TYPE13,
        HDMI_TYPE14,
@@ -379,12 +367,6 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
        },
 };
 
-struct hdmi_infoframe {
-       enum HDMI_PACKET_TYPE type;
-       u8 ver;
-       u8 len;
-};
-
 static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id)
 {
        return readl(hdata->regs + reg_id);
@@ -682,7 +664,7 @@ static u8 hdmi_chksum(struct hdmi_context *hdata,
 }
 
 static void hdmi_reg_infoframe(struct hdmi_context *hdata,
-                       struct hdmi_infoframe *infoframe)
+                       union hdmi_infoframe *infoframe)
 {
        u32 hdr_sum;
        u8 chksum;
@@ -700,13 +682,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
                return;
        }
 
-       switch (infoframe->type) {
-       case HDMI_PACKET_TYPE_AVI:
+       switch (infoframe->any.type) {
+       case HDMI_INFOFRAME_TYPE_AVI:
                hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC);
-               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->type);
-               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, infoframe->ver);
-               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->len);
-               hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type);
+               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1,
+                               infoframe->any.version);
+               hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length);
+               hdr_sum = infoframe->any.type + infoframe->any.version +
+                         infoframe->any.length;
 
                /* Output format zero hardcoded ,RGB YBCR selection */
                hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 |
@@ -722,18 +706,20 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
                hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
 
                chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
-                                       infoframe->len, hdr_sum);
+                                       infoframe->any.length, hdr_sum);
                DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum);
                hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum);
                break;
-       case HDMI_PACKET_TYPE_AUI:
+       case HDMI_INFOFRAME_TYPE_AUDIO:
                hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02);
-               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->type);
-               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, infoframe->ver);
-               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->len);
-               hdr_sum = infoframe->type + infoframe->ver + infoframe->len;
+               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type);
+               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1,
+                               infoframe->any.version);
+               hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length);
+               hdr_sum = infoframe->any.type + infoframe->any.version +
+                         infoframe->any.length;
                chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1),
-                                       infoframe->len, hdr_sum);
+                                       infoframe->any.length, hdr_sum);
                DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum);
                hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum);
                break;
@@ -985,7 +971,7 @@ static void hdmi_conf_reset(struct hdmi_context *hdata)
 
 static void hdmi_conf_init(struct hdmi_context *hdata)
 {
-       struct hdmi_infoframe infoframe;
+       union hdmi_infoframe infoframe;
 
        /* disable HPD interrupts from HDMI IP block, use GPIO instead */
        hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
@@ -1021,14 +1007,14 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
                hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02);
                hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04);
        } else {
-               infoframe.type = HDMI_PACKET_TYPE_AVI;
-               infoframe.ver = HDMI_AVI_VERSION;
-               infoframe.len = HDMI_AVI_LENGTH;
+               infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI;
+               infoframe.any.version = HDMI_AVI_VERSION;
+               infoframe.any.length = HDMI_AVI_LENGTH;
                hdmi_reg_infoframe(hdata, &infoframe);
 
-               infoframe.type = HDMI_PACKET_TYPE_AUI;
-               infoframe.ver = HDMI_AUI_VERSION;
-               infoframe.len = HDMI_AUI_LENGTH;
+               infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO;
+               infoframe.any.version = HDMI_AUI_VERSION;
+               infoframe.any.length = HDMI_AUI_LENGTH;
                hdmi_reg_infoframe(hdata, &infoframe);
 
                /* enable AVI packet every vsync, fixes purple line problem */
index 400b0c4a10fba3138bbb2fc4cc260058be62cffc..faa77f543a077da2c624e47638693b6566b146ff 100644 (file)
@@ -208,7 +208,7 @@ struct tda998x_priv {
 # define PLL_SERIAL_1_SRL_IZ(x)   (((x) & 3) << 1)
 # define PLL_SERIAL_1_SRL_MAN_IZ  (1 << 6)
 #define REG_PLL_SERIAL_2          REG(0x02, 0x01)     /* read/write */
-# define PLL_SERIAL_2_SRL_NOSC(x) (((x) & 3) << 0)
+# define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0)
 # define PLL_SERIAL_2_SRL_PR(x)   (((x) & 0xf) << 4)
 #define REG_PLL_SERIAL_3          REG(0x02, 0x02)     /* read/write */
 # define PLL_SERIAL_3_SRL_CCIR    (1 << 0)
@@ -528,10 +528,10 @@ tda998x_write_aif(struct drm_encoder *encoder, struct tda998x_encoder_params *p)
 {
        uint8_t buf[PB(5) + 1];
 
+       memset(buf, 0, sizeof(buf));
        buf[HB(0)] = 0x84;
        buf[HB(1)] = 0x01;
        buf[HB(2)] = 10;
-       buf[PB(0)] = 0;
        buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */
        buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */
        buf[PB(4)] = p->audio_frame[4];
@@ -824,6 +824,11 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        div = 148500 / mode->clock;
+       if (div != 0) {
+               div--;
+               if (div > 3)
+                       div = 3;
+       }
 
        /* mute the audio FIFO: */
        reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
@@ -913,7 +918,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
 
        if (priv->rev == TDA19988) {
                /* let incoming pixels fill the active space (if any) */
-               reg_write(encoder, REG_ENABLE_SPACE, 0x01);
+               reg_write(encoder, REG_ENABLE_SPACE, 0x00);
        }
 
        /* must be last register set: */
@@ -1094,6 +1099,8 @@ tda998x_encoder_destroy(struct drm_encoder *encoder)
 {
        struct tda998x_priv *priv = to_tda998x_priv(encoder);
        drm_i2c_encoder_destroy(encoder);
+       if (priv->cec)
+               i2c_unregister_device(priv->cec);
        kfree(priv);
 }
 
@@ -1142,8 +1149,12 @@ tda998x_encoder_init(struct i2c_client *client,
        priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);
        priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
 
-       priv->current_page = 0;
+       priv->current_page = 0xff;
        priv->cec = i2c_new_dummy(client->adapter, 0x34);
+       if (!priv->cec) {
+               kfree(priv);
+               return -ENODEV;
+       }
        priv->dpms = DRM_MODE_DPMS_OFF;
 
        encoder_slave->slave_priv = priv;
index 04f1f02c4019f57873caeb0c70fea14e0816ddeb..ec7bb0fc71bcfc8c19c2231c9bb0e3165f89e047 100644 (file)
@@ -403,7 +403,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 void intel_detect_pch(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct pci_dev *pch;
+       struct pci_dev *pch = NULL;
 
        /* In all current cases, num_pipes is equivalent to the PCH_NOP setting
         * (which really amounts to a PCH but no South Display).
@@ -424,12 +424,9 @@ void intel_detect_pch(struct drm_device *dev)
         * all the ISA bridge devices and check for the first match, instead
         * of only checking the first one.
         */
-       pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
-       while (pch) {
-               struct pci_dev *curr = pch;
+       while ((pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, pch))) {
                if (pch->vendor == PCI_VENDOR_ID_INTEL) {
-                       unsigned short id;
-                       id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
+                       unsigned short id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
                        dev_priv->pch_id = id;
 
                        if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
@@ -461,18 +458,16 @@ void intel_detect_pch(struct drm_device *dev)
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
                                WARN_ON(!IS_HASWELL(dev));
                                WARN_ON(!IS_ULT(dev));
-                       } else {
-                               goto check_next;
-                       }
-                       pci_dev_put(pch);
+                       } else
+                               continue;
+
                        break;
                }
-check_next:
-               pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
-               pci_dev_put(curr);
        }
        if (!pch)
-               DRM_DEBUG_KMS("No PCH found?\n");
+               DRM_DEBUG_KMS("No PCH found.\n");
+
+       pci_dev_put(pch);
 }
 
 bool i915_semaphore_is_enabled(struct drm_device *dev)
index 4a2bf8e3f739bff7b2b9f6e018100ec98e8b9c0e..df77e20e3c3d00ee9173d4c160274f0e837c26de 100644 (file)
@@ -1831,6 +1831,14 @@ struct drm_i915_file_private {
 
 /* Early gen2 have a totally busted CS tlb and require pinned batches. */
 #define HAS_BROKEN_CS_TLB(dev)         (IS_I830(dev) || IS_845G(dev))
+/*
+ * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts
+ * even when in MSI mode. This results in spurious interrupt warnings if the
+ * legacy irq no. is shared with another device. The kernel then disables that
+ * interrupt source and so prevents the other device from working properly.
+ */
+#define HAS_AUX_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
+#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
 
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
index 40a2b36b276baa774028b56ae60b6ae6c59e919d..d278be110805ba50965f1e071213720434cb9e78 100644 (file)
@@ -842,7 +842,7 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
                                       dev_priv->gtt.base.start / PAGE_SIZE,
                                       dev_priv->gtt.base.total / PAGE_SIZE,
-                                      false);
+                                      true);
 }
 
 void i915_gem_restore_gtt_mappings(struct drm_device *dev)
index 1a24e84f231578ae772d40ad75adda4c356b8d68..28d24caa49f3f7720c63e208c4831c79f5433d8d 100644 (file)
@@ -82,9 +82,22 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
        r = devm_request_mem_region(dev->dev, base, dev_priv->gtt.stolen_size,
                                    "Graphics Stolen Memory");
        if (r == NULL) {
-               DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
-                         base, base + (uint32_t)dev_priv->gtt.stolen_size);
-               base = 0;
+               /*
+                * One more attempt but this time requesting region from
+                * base + 1, as we have seen that this resolves the region
+                * conflict with the PCI Bus.
+                * This is a BIOS w/a: Some BIOS wrap stolen in the root
+                * PCI bus, but have an off-by-one error. Hence retry the
+                * reservation starting from 1 instead of 0.
+                */
+               r = devm_request_mem_region(dev->dev, base + 1,
+                                           dev_priv->gtt.stolen_size - 1,
+                                           "Graphics Stolen Memory");
+               if (r == NULL) {
+                       DRM_ERROR("conflict detected with stolen region: [0x%08x - 0x%08x]\n",
+                                 base, base + (uint32_t)dev_priv->gtt.stolen_size);
+                       base = 0;
+               }
        }
 
        return base;
@@ -201,6 +214,13 @@ int i915_gem_init_stolen(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int bios_reserved = 0;
 
+#ifdef CONFIG_INTEL_IOMMU
+       if (intel_iommu_gfx_mapped) {
+               DRM_INFO("DMAR active, disabling use of stolen memory\n");
+               return 0;
+       }
+#endif
+
        if (dev_priv->gtt.stolen_size == 0)
                return 0;
 
index d7fd2fd2f0a5e1ba6ed25f9a4dce0c20dc03b9e3..990cf8f43efda908ecb1565cb5e8a786efe68306 100644 (file)
@@ -146,7 +146,10 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
                va_list tmp;
 
                va_copy(tmp, args);
-               if (!__i915_error_seek(e, vsnprintf(NULL, 0, f, tmp)))
+               len = vsnprintf(NULL, 0, f, tmp);
+               va_end(tmp);
+
+               if (!__i915_error_seek(e, len))
                        return;
        }
 
index 17d8fcb1b6f7ac113b4c0c035088979b1c8083b4..d554169ac59274fbcaeaa2978078d0c71b822a33 100644 (file)
@@ -567,8 +567,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
 
                vbl_start = mode->crtc_vblank_start * mode->crtc_htotal;
        } else {
-               enum transcoder cpu_transcoder =
-                       intel_pipe_to_cpu_transcoder(dev_priv, pipe);
+               enum transcoder cpu_transcoder = (enum transcoder) pipe;
                u32 htotal;
 
                htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1;
@@ -619,33 +618,25 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 
 /* raw reads, only for fast reads of display block, no need for forcewake etc. */
 #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
-#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
 
 static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t status;
-
-       if (INTEL_INFO(dev)->gen < 7) {
-               status = pipe == PIPE_A ?
-                       DE_PIPEA_VBLANK :
-                       DE_PIPEB_VBLANK;
+       int reg;
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               status = GEN8_PIPE_VBLANK;
+               reg = GEN8_DE_PIPE_ISR(pipe);
+       } else if (INTEL_INFO(dev)->gen >= 7) {
+               status = DE_PIPE_VBLANK_IVB(pipe);
+               reg = DEISR;
        } else {
-               switch (pipe) {
-               default:
-               case PIPE_A:
-                       status = DE_PIPEA_VBLANK_IVB;
-                       break;
-               case PIPE_B:
-                       status = DE_PIPEB_VBLANK_IVB;
-                       break;
-               case PIPE_C:
-                       status = DE_PIPEC_VBLANK_IVB;
-                       break;
-               }
+               status = DE_PIPE_VBLANK(pipe);
+               reg = DEISR;
        }
 
-       return __raw_i915_read32(dev_priv, DEISR) & status;
+       return __raw_i915_read32(dev_priv, reg) & status;
 }
 
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
@@ -703,7 +694,28 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                else
                        position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
-               if (HAS_PCH_SPLIT(dev)) {
+               if (HAS_DDI(dev)) {
+                       /*
+                        * On HSW HDMI outputs there seems to be a 2 line
+                        * difference, whereas eDP has the normal 1 line
+                        * difference that earlier platforms have. External
+                        * DP is unknown. For now just check for the 2 line
+                        * difference case on all output types on HSW+.
+                        *
+                        * This might misinterpret the scanline counter being
+                        * one line too far along on eDP, but that's less
+                        * dangerous than the alternative since that would lead
+                        * the vblank timestamp code astray when it sees a
+                        * scanline count before vblank_start during a vblank
+                        * interrupt.
+                        */
+                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
+                       if ((in_vbl && (position == vbl_start - 2 ||
+                                       position == vbl_start - 1)) ||
+                           (!in_vbl && (position == vbl_end - 2 ||
+                                        position == vbl_end - 1)))
+                               position = (position + 2) % vtotal;
+               } else if (HAS_PCH_SPLIT(dev)) {
                        /*
                         * The scanline counter increments at the leading edge
                         * of hsync, ie. it completely misses the active portion
@@ -2770,10 +2782,9 @@ static void ibx_irq_postinstall(struct drm_device *dev)
                return;
 
        if (HAS_PCH_IBX(dev)) {
-               mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
-                      SDE_TRANSA_FIFO_UNDER | SDE_POISON;
+               mask = SDE_GMBUS | SDE_AUX_MASK | SDE_POISON;
        } else {
-               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
+               mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
 
                I915_WRITE(SERR_INT, I915_READ(SERR_INT));
        }
@@ -2833,20 +2844,19 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
                                DE_PCH_EVENT_IVB | DE_PLANEC_FLIP_DONE_IVB |
                                DE_PLANEB_FLIP_DONE_IVB |
-                               DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB |
-                               DE_ERR_INT_IVB);
+                               DE_PLANEA_FLIP_DONE_IVB | DE_AUX_CHANNEL_A_IVB);
                extra_mask = (DE_PIPEC_VBLANK_IVB | DE_PIPEB_VBLANK_IVB |
-                             DE_PIPEA_VBLANK_IVB);
+                             DE_PIPEA_VBLANK_IVB | DE_ERR_INT_IVB);
 
                I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
        } else {
                display_mask = (DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
                                DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
                                DE_AUX_CHANNEL_A |
-                               DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN |
                                DE_PIPEB_CRC_DONE | DE_PIPEA_CRC_DONE |
                                DE_POISON);
-               extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT;
+               extra_mask = DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT |
+                               DE_PIPEB_FIFO_UNDERRUN | DE_PIPEA_FIFO_UNDERRUN;
        }
 
        dev_priv->irq_mask = ~display_mask;
@@ -2962,9 +2972,9 @@ static void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv)
        struct drm_device *dev = dev_priv->dev;
        uint32_t de_pipe_masked = GEN8_PIPE_FLIP_DONE |
                GEN8_PIPE_CDCLK_CRC_DONE |
-               GEN8_PIPE_FIFO_UNDERRUN |
                GEN8_DE_PIPE_IRQ_FAULT_ERRORS;
-       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK;
+       uint32_t de_pipe_enables = de_pipe_masked | GEN8_PIPE_VBLANK |
+               GEN8_PIPE_FIFO_UNDERRUN;
        int pipe;
        dev_priv->de_irq_mask[PIPE_A] = ~de_pipe_masked;
        dev_priv->de_irq_mask[PIPE_B] = ~de_pipe_masked;
index e06b9e017d6ba918b87557de301df47076852434..234ac5f7bc5aba1013f2ad62650baa05c1d1559a 100644 (file)
@@ -1244,6 +1244,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+               ironlake_edp_panel_vdd_on(intel_dp);
                ironlake_edp_panel_off(intel_dp);
        }
 
index 9fa24347963a38d360e365cfa20bf7cefed8beaa..9b8a7c7ea7fc1925610b4dcb11ca9f768057fd41 100644 (file)
@@ -1092,12 +1092,12 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        bool cur_state;
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-               cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
-       else if (IS_845G(dev) || IS_I865G(dev))
+       if (IS_845G(dev) || IS_I865G(dev))
                cur_state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
-       else
+       else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
                cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+       else
+               cur_state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
 
        WARN(cur_state != state,
             "cursor on pipe %c assertion failure (expected %s, current %s)\n",
@@ -8586,6 +8586,20 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
        if (ring->id == RCS)
                len += 6;
 
+       /*
+        * BSpec MI_DISPLAY_FLIP for IVB:
+        * "The full packet must be contained within the same cache line."
+        *
+        * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same
+        * cacheline, if we ever start emitting more commands before
+        * the MI_DISPLAY_FLIP we may need to first emit everything else,
+        * then do the cacheline alignment, and finally emit the
+        * MI_DISPLAY_FLIP.
+        */
+       ret = intel_ring_cacheline_align(ring);
+       if (ret)
+               goto err_unpin;
+
        ret = intel_ring_begin(ring, len);
        if (ret)
                goto err_unpin;
index 5ede4e8e290df5cc2f3e1b7046ec409b9f50d538..2688f6d64bb9f3e6883e5a8a9216a38fd794d880 100644 (file)
@@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        int i, ret, recv_bytes;
        uint32_t status;
        int try, precharge, clock = 0;
-       bool has_aux_irq = true;
+       bool has_aux_irq = HAS_AUX_IRQ(dev);
        uint32_t timeout;
 
        /* dp aux is extremely sensitive to irq latency, hence request the
@@ -537,6 +537,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
        uint8_t msg[20];
        int msg_bytes;
        uint8_t ack;
+       int retry;
 
        if (WARN_ON(send_bytes > 16))
                return -E2BIG;
@@ -548,19 +549,21 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
        msg[3] = send_bytes - 1;
        memcpy(&msg[4], send, send_bytes);
        msg_bytes = send_bytes + 4;
-       for (;;) {
+       for (retry = 0; retry < 7; retry++) {
                ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);
                if (ret < 0)
                        return ret;
                ack >>= 4;
                if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
-                       break;
+                       return send_bytes;
                else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
-                       udelay(100);
+                       usleep_range(400, 500);
                else
                        return -EIO;
        }
-       return send_bytes;
+
+       DRM_ERROR("too many retries, giving up\n");
+       return -EIO;
 }
 
 /* Write a single byte to the aux channel in native mode */
@@ -582,6 +585,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
        int reply_bytes;
        uint8_t ack;
        int ret;
+       int retry;
 
        if (WARN_ON(recv_bytes > 19))
                return -E2BIG;
@@ -595,7 +599,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
        msg_bytes = 4;
        reply_bytes = recv_bytes + 1;
 
-       for (;;) {
+       for (retry = 0; retry < 7; retry++) {
                ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes,
                                      reply, reply_bytes);
                if (ret == 0)
@@ -608,10 +612,13 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
                        return ret - 1;
                }
                else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
-                       udelay(100);
+                       usleep_range(400, 500);
                else
                        return -EIO;
        }
+
+       DRM_ERROR("too many retries, giving up\n");
+       return -EIO;
 }
 
 static int
@@ -1242,17 +1249,24 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power off\n");
 
+       WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
+
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
         * panels get very unhappy and cease to work. */
-       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
 
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
 
+       intel_dp->want_panel_vdd = false;
+
        ironlake_wait_panel_off(intel_dp);
+
+       /* We got a reference when we enabled the VDD. */
+       intel_runtime_pm_put(dev_priv);
 }
 
 void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
@@ -1632,7 +1646,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)
                val |= EDP_PSR_LINK_DISABLE;
 
        I915_WRITE(EDP_PSR_CTL(dev), val |
-                  IS_BROADWELL(dev) ? 0 : link_entry_time |
+                  (IS_BROADWELL(dev) ? 0 : link_entry_time) |
                   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |
                   idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |
                   EDP_PSR_ENABLE);
@@ -1777,6 +1791,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)
 
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
+       ironlake_edp_panel_vdd_on(intel_dp);
        ironlake_edp_backlight_off(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        ironlake_edp_panel_off(intel_dp);
@@ -1869,10 +1884,12 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
 
        mutex_unlock(&dev_priv->dpio_lock);
 
-       /* init power sequencer on this pipe and port */
-       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                     &power_seq);
+       if (is_edp(intel_dp)) {
+               /* init power sequencer on this pipe and port */
+               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+               intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+                                                             &power_seq);
+       }
 
        intel_enable_dp(encoder);
 
index 6db0d9d17f47e7b5ce5c43a7aa7795de71ea6346..ee3181ebcc9236078835ee18a48fe86c97525ff9 100644 (file)
@@ -845,7 +845,7 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
 {
        struct drm_device *dev = intel_hdmi_to_dev(hdmi);
 
-       if (IS_G4X(dev))
+       if (!hdmi->has_hdmi_sink || IS_G4X(dev))
                return 165000;
        else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
                return 300000;
@@ -899,8 +899,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * outputs. We also need to check that the higher clock still fits
         * within limits.
         */
-       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
-           && HAS_PCH_SPLIT(dev)) {
+       if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
+           clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
index b1dc33f478991755ec114fe66fbad7bc40fec4c0..d33b61d0dd3331b6bd073806d0482b19aeb0eb08 100644 (file)
@@ -258,13 +258,6 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
        algo->data = bus;
 }
 
-/*
- * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI
- * mode. This results in spurious interrupt warnings if the legacy irq no. is
- * shared with another device. The kernel then disables that interrupt source
- * and so prevents the other device from working properly.
- */
-#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5)
 static int
 gmbus_wait_hw_status(struct drm_i915_private *dev_priv,
                     u32 gmbus2_status,
index 4e960ec7419fb6802398b9b118b3b3a513199350..acde2945eb8a73e075c2fa60493f4b22e89bb666 100644 (file)
@@ -226,6 +226,8 @@ struct opregion_asle {
 #define ACPI_DIGITAL_OUTPUT (3<<8)
 #define ACPI_LVDS_OUTPUT (4<<8)
 
+#define MAX_DSLP       1500
+
 #ifdef CONFIG_ACPI
 static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
 {
@@ -260,10 +262,11 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out)
                /* The spec says 2ms should be the default, but it's too small
                 * for some machines. */
                dslp = 50;
-       } else if (dslp > 500) {
+       } else if (dslp > MAX_DSLP) {
                /* Hey bios, trust must be earned. */
-               WARN_ONCE(1, "excessive driver sleep timeout (DSPL) %u\n", dslp);
-               dslp = 500;
+               DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, "
+                             "using %u ms instead\n", dslp, MAX_DSLP);
+               dslp = MAX_DSLP;
        }
 
        /* The spec tells us to do this, but we are the only user... */
index 350de359123af9cbd42354c182424f356281aa16..079ea38f14d9b4b54092a1ebeca4cd77dac27cec 100644 (file)
@@ -698,7 +698,7 @@ static void i9xx_enable_backlight(struct intel_connector *connector)
                freq /= 0xff;
 
        ctl = freq << 17;
-       if (IS_GEN2(dev) && panel->backlight.combination_mode)
+       if (panel->backlight.combination_mode)
                ctl |= BLM_LEGACY_MODE;
        if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
                ctl |= BLM_POLARITY_PNV;
@@ -979,7 +979,7 @@ static int i9xx_setup_backlight(struct intel_connector *connector)
 
        ctl = I915_READ(BLC_PWM_CTL);
 
-       if (IS_GEN2(dev))
+       if (IS_GEN2(dev) || IS_I915GM(dev) || IS_I945GM(dev))
                panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
 
        if (IS_PINEVIEW(dev))
index d77cc81900f92100ba2f61d7130bc9b0b60454b5..e1fc35a726564cc9f3526231780672d09d151838 100644 (file)
@@ -3493,6 +3493,8 @@ static void valleyview_setup_pctx(struct drm_device *dev)
        u32 pcbr;
        int pctx_size = 24*1024;
 
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
        pcbr = I915_READ(VLV_PCBR);
        if (pcbr) {
                /* BIOS set it up already, grab the pre-alloc'd space */
@@ -3542,8 +3544,6 @@ static void valleyview_enable_rps(struct drm_device *dev)
                I915_WRITE(GTFIFODBG, gtfifodbg);
        }
 
-       valleyview_setup_pctx(dev);
-
        /* If VLV, Forcewake all wells, else re-direct to regular path */
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
@@ -4395,6 +4395,8 @@ void intel_enable_gt_powersave(struct drm_device *dev)
                ironlake_enable_rc6(dev);
                intel_init_emon(dev);
        } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+               if (IS_VALLEYVIEW(dev))
+                       valleyview_setup_pctx(dev);
                /*
                 * PCU communication is slow and this doesn't need to be
                 * done at any specific time, so do this out of our fast path
index b7f1742caf878250c3fb6dc98b5bdbe63ae4a601..31b36c5ac8941e844cd9f995b0c4e575219fc8ea 100644 (file)
@@ -1653,6 +1653,27 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
        return 0;
 }
 
+/* Align the ring tail to a cacheline boundary */
+int intel_ring_cacheline_align(struct intel_ring_buffer *ring)
+{
+       int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t);
+       int ret;
+
+       if (num_dwords == 0)
+               return 0;
+
+       ret = intel_ring_begin(ring, num_dwords);
+       if (ret)
+               return ret;
+
+       while (num_dwords--)
+               intel_ring_emit(ring, MI_NOOP);
+
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
 void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
index 71a73f4fe252fdb90b4c24d8947e936b37ad0f5b..0b243ce337147d51f7e9cb4b09d774f4cc33e856 100644 (file)
@@ -233,6 +233,7 @@ intel_write_status_page(struct intel_ring_buffer *ring,
 void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
 
 int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
+int __must_check intel_ring_cacheline_align(struct intel_ring_buffer *ring);
 static inline void intel_ring_emit(struct intel_ring_buffer *ring,
                                   u32 data)
 {
index 1964f4f0d452377c87d2e2db4bd218a1f0451ff5..84c5b13b33c9ed2649a58d2a9d499d6d22ba0a21 100644 (file)
@@ -39,6 +39,7 @@ struct mdp4_crtc {
                spinlock_t lock;
                bool stale;
                uint32_t width, height;
+               uint32_t x, y;
 
                /* next cursor to scan-out: */
                uint32_t next_iova;
@@ -57,9 +58,16 @@ struct mdp4_crtc {
 #define PENDING_FLIP   0x2
        atomic_t pending;
 
-       /* the fb that we currently hold a scanout ref to: */
+       /* the fb that we logically (from PoV of KMS API) hold a ref
+        * to.  Which we may not yet be scanning out (we may still
+        * be scanning out previous in case of page_flip while waiting
+        * for gpu rendering to complete:
+        */
        struct drm_framebuffer *fb;
 
+       /* the fb that we currently hold a scanout ref to: */
+       struct drm_framebuffer *scanout_fb;
+
        /* for unref'ing framebuffers after scanout completes: */
        struct drm_flip_work unref_fb_work;
 
@@ -77,24 +85,73 @@ static struct mdp4_kms *get_kms(struct drm_crtc *crtc)
        return to_mdp4_kms(to_mdp_kms(priv->kms));
 }
 
-static void update_fb(struct drm_crtc *crtc, bool async,
-               struct drm_framebuffer *new_fb)
+static void request_pending(struct drm_crtc *crtc, uint32_t pending)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct drm_framebuffer *old_fb = mdp4_crtc->fb;
 
-       if (old_fb)
-               drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb);
+       atomic_or(pending, &mdp4_crtc->pending);
+       mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
+}
+
+static void crtc_flush(struct drm_crtc *crtc)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+       struct mdp4_kms *mdp4_kms = get_kms(crtc);
+       uint32_t i, flush = 0;
+
+       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
+               struct drm_plane *plane = mdp4_crtc->planes[i];
+               if (plane) {
+                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+                       flush |= pipe2flush(pipe_id);
+               }
+       }
+       flush |= ovlp2flush(mdp4_crtc->ovlp);
+
+       DBG("%s: flush=%08x", mdp4_crtc->name, flush);
+
+       mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
+}
+
+static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+       struct drm_framebuffer *old_fb = mdp4_crtc->fb;
 
        /* grab reference to incoming scanout fb: */
        drm_framebuffer_reference(new_fb);
        mdp4_crtc->base.fb = new_fb;
        mdp4_crtc->fb = new_fb;
 
-       if (!async) {
-               /* enable vblank to pick up the old_fb */
-               mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
-       }
+       if (old_fb)
+               drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb);
+}
+
+/* unlike update_fb(), take a ref to the new scanout fb *before* updating
+ * plane, then call this.  Needed to ensure we don't unref the buffer that
+ * is actually still being scanned out.
+ *
+ * Note that this whole thing goes away with atomic.. since we can defer
+ * calling into driver until rendering is done.
+ */
+static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+       /* flush updates, to make sure hw is updated to new scanout fb,
+        * so that we can safely queue unref to current fb (ie. next
+        * vblank we know hw is done w/ previous scanout_fb).
+        */
+       crtc_flush(crtc);
+
+       if (mdp4_crtc->scanout_fb)
+               drm_flip_work_queue(&mdp4_crtc->unref_fb_work,
+                               mdp4_crtc->scanout_fb);
+
+       mdp4_crtc->scanout_fb = fb;
+
+       /* enable vblank to complete flip: */
+       request_pending(crtc, PENDING_FLIP);
 }
 
 /* if file!=NULL, this is preclose potential cancel-flip path */
@@ -120,34 +177,6 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
 
-static void crtc_flush(struct drm_crtc *crtc)
-{
-       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct mdp4_kms *mdp4_kms = get_kms(crtc);
-       uint32_t i, flush = 0;
-
-       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
-               struct drm_plane *plane = mdp4_crtc->planes[i];
-               if (plane) {
-                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
-                       flush |= pipe2flush(pipe_id);
-               }
-       }
-       flush |= ovlp2flush(mdp4_crtc->ovlp);
-
-       DBG("%s: flush=%08x", mdp4_crtc->name, flush);
-
-       mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush);
-}
-
-static void request_pending(struct drm_crtc *crtc, uint32_t pending)
-{
-       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-
-       atomic_or(pending, &mdp4_crtc->pending);
-       mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
-}
-
 static void pageflip_cb(struct msm_fence_cb *cb)
 {
        struct mdp4_crtc *mdp4_crtc =
@@ -158,11 +187,9 @@ static void pageflip_cb(struct msm_fence_cb *cb)
        if (!fb)
                return;
 
+       drm_framebuffer_reference(fb);
        mdp4_plane_set_scanout(mdp4_crtc->plane, fb);
-       crtc_flush(crtc);
-
-       /* enable vblank to complete flip: */
-       request_pending(crtc, PENDING_FLIP);
+       update_scanout(crtc, fb);
 }
 
 static void unref_fb_worker(struct drm_flip_work *work, void *val)
@@ -320,6 +347,20 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
                        mode->vsync_end, mode->vtotal,
                        mode->type, mode->flags);
 
+       /* grab extra ref for update_scanout() */
+       drm_framebuffer_reference(crtc->fb);
+
+       ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
+                       0, 0, mode->hdisplay, mode->vdisplay,
+                       x << 16, y << 16,
+                       mode->hdisplay << 16, mode->vdisplay << 16);
+       if (ret) {
+               drm_framebuffer_unreference(crtc->fb);
+               dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
+                               mdp4_crtc->name, ret);
+               return ret;
+       }
+
        mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma),
                        MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) |
                        MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay));
@@ -341,24 +382,15 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
 
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
 
-       update_fb(crtc, false, crtc->fb);
-
-       ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
-                       0, 0, mode->hdisplay, mode->vdisplay,
-                       x << 16, y << 16,
-                       mode->hdisplay << 16, mode->vdisplay << 16);
-       if (ret) {
-               dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
-                               mdp4_crtc->name, ret);
-               return ret;
-       }
-
        if (dma == DMA_E) {
                mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000);
                mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000);
                mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
        }
 
+       update_fb(crtc, crtc->fb);
+       update_scanout(crtc, crtc->fb);
+
        return 0;
 }
 
@@ -385,13 +417,24 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct drm_plane *plane = mdp4_crtc->plane;
        struct drm_display_mode *mode = &crtc->mode;
+       int ret;
 
-       update_fb(crtc, false, crtc->fb);
+       /* grab extra ref for update_scanout() */
+       drm_framebuffer_reference(crtc->fb);
 
-       return mdp4_plane_mode_set(plane, crtc, crtc->fb,
+       ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
+       if (ret) {
+               drm_framebuffer_unreference(crtc->fb);
+               return ret;
+       }
+
+       update_fb(crtc, crtc->fb);
+       update_scanout(crtc, crtc->fb);
+
+       return 0;
 }
 
 static void mdp4_crtc_load_lut(struct drm_crtc *crtc)
@@ -419,7 +462,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc,
        mdp4_crtc->event = event;
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       update_fb(crtc, true, new_fb);
+       update_fb(crtc, new_fb);
 
        return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb);
 }
@@ -442,12 +485,12 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc,
 static void update_cursor(struct drm_crtc *crtc)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+       struct mdp4_kms *mdp4_kms = get_kms(crtc);
        enum mdp4_dma dma = mdp4_crtc->dma;
        unsigned long flags;
 
        spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
        if (mdp4_crtc->cursor.stale) {
-               struct mdp4_kms *mdp4_kms = get_kms(crtc);
                struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo;
                struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo;
                uint32_t iova = mdp4_crtc->cursor.next_iova;
@@ -479,6 +522,11 @@ static void update_cursor(struct drm_crtc *crtc)
                mdp4_crtc->cursor.scanout_bo = next_bo;
                mdp4_crtc->cursor.stale = false;
        }
+
+       mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
+                       MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) |
+                       MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y));
+
        spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
 }
 
@@ -530,6 +578,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc,
                drm_gem_object_unreference_unlocked(old_bo);
        }
 
+       crtc_flush(crtc);
        request_pending(crtc, PENDING_CURSOR);
 
        return 0;
@@ -542,12 +591,15 @@ fail:
 static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct mdp4_kms *mdp4_kms = get_kms(crtc);
-       enum mdp4_dma dma = mdp4_crtc->dma;
+       unsigned long flags;
 
-       mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma),
-                       MDP4_DMA_CURSOR_POS_X(x) |
-                       MDP4_DMA_CURSOR_POS_Y(y));
+       spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags);
+       mdp4_crtc->cursor.x = x;
+       mdp4_crtc->cursor.y = y;
+       spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags);
+
+       crtc_flush(crtc);
+       request_pending(crtc, PENDING_CURSOR);
 
        return 0;
 }
@@ -713,6 +765,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
        crtc = &mdp4_crtc->base;
 
        mdp4_crtc->plane = plane;
+       mdp4_crtc->id = id;
 
        mdp4_crtc->ovlp = ovlp_id;
        mdp4_crtc->dma = dma_id;
index 2406027200ec597e5d6a10674e82db82f122adff..1e893dd13859817ae33e199b99f0810c59c49732 100644 (file)
@@ -170,8 +170,8 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
                        MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h));
 
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe),
-                       MDP4_PIPE_SRC_XY_X(crtc_x) |
-                       MDP4_PIPE_SRC_XY_Y(crtc_y));
+                       MDP4_PIPE_DST_XY_X(crtc_x) |
+                       MDP4_PIPE_DST_XY_Y(crtc_y));
 
        mdp4_plane_set_scanout(plane, fb);
 
index 71a3b2345eb38909d53c5a57e2370fcdcbd5e0c7..f2794021f086f53fc509dea1f3136cf4facfe27d 100644 (file)
@@ -296,6 +296,7 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
        if (ret) {
+               drm_framebuffer_unreference(crtc->fb);
                dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
                                mdp5_crtc->name, ret);
                return ret;
@@ -343,11 +344,15 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
+       if (ret) {
+               drm_framebuffer_unreference(crtc->fb);
+               return ret;
+       }
 
        update_fb(crtc, crtc->fb);
        update_scanout(crtc, crtc->fb);
 
-       return ret;
+       return 0;
 }
 
 static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
index d8d60c969ac7858bce0e6114f092a5f1aad450aa..3da8264d3039017bd358ccaca48197356f932f68 100644 (file)
@@ -644,7 +644,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
 
 fail:
        if (obj)
-               drm_gem_object_unreference_unlocked(obj);
+               drm_gem_object_unreference(obj);
 
        return ERR_PTR(ret);
 }
index 5281d4bc37f750e2162e4bd1f17859e4921c45cc..5423e914e491691a7a4d511a9ec2ae84caef8414 100644 (file)
@@ -163,7 +163,7 @@ retry:
 
 
                /* if locking succeeded, pin bo: */
-               ret = msm_gem_get_iova(&msm_obj->base,
+               ret = msm_gem_get_iova_locked(&msm_obj->base,
                                submit->gpu->id, &iova);
 
                /* this would break the logic in the fail path.. there is no
@@ -247,7 +247,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob
        /* For now, just map the entire thing.  Eventually we probably
         * to do it page-by-page, w/ kmap() if not vmap()d..
         */
-       ptr = msm_gem_vaddr(&obj->base);
+       ptr = msm_gem_vaddr_locked(&obj->base);
 
        if (IS_ERR(ptr)) {
                ret = PTR_ERR(ptr);
@@ -307,14 +307,12 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool fail)
 {
        unsigned i;
 
-       mutex_lock(&submit->dev->struct_mutex);
        for (i = 0; i < submit->nr_bos; i++) {
                struct msm_gem_object *msm_obj = submit->bos[i].obj;
                submit_unlock_unpin_bo(submit, i);
                list_del_init(&msm_obj->submit_entry);
                drm_gem_object_unreference(&msm_obj->base);
        }
-       mutex_unlock(&submit->dev->struct_mutex);
 
        ww_acquire_fini(&submit->ticket);
        kfree(submit);
@@ -342,6 +340,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
        if (args->nr_cmds > MAX_CMDS)
                return -EINVAL;
 
+       mutex_lock(&dev->struct_mutex);
+
        submit = submit_create(dev, gpu, args->nr_bos);
        if (!submit) {
                ret = -ENOMEM;
@@ -410,5 +410,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
 out:
        if (submit)
                submit_cleanup(submit, !!ret);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
index 4ebce8be489db6cdf51f6ba88fb8f7bfd1dbd5ce..0cfe3f426ee4f4523d9e34c85427cd7cd37649a1 100644 (file)
@@ -298,8 +298,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
        struct msm_drm_private *priv = dev->dev_private;
        int i, ret;
 
-       mutex_lock(&dev->struct_mutex);
-
        submit->fence = ++priv->next_fence;
 
        gpu->submitted_fence = submit->fence;
@@ -331,7 +329,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
                        msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence);
        }
        hangcheck_timer_reset(gpu);
-       mutex_unlock(&dev->struct_mutex);
 
        return ret;
 }
index e88145ba1bf515429a3b85753bde5df7d28bde70..d310c195bdfed1d467abbd1f5933da703e207e13 100644 (file)
@@ -141,6 +141,7 @@ nouveau-y += core/subdev/mc/base.o
 nouveau-y += core/subdev/mc/nv04.o
 nouveau-y += core/subdev/mc/nv40.o
 nouveau-y += core/subdev/mc/nv44.o
+nouveau-y += core/subdev/mc/nv4c.o
 nouveau-y += core/subdev/mc/nv50.o
 nouveau-y += core/subdev/mc/nv94.o
 nouveau-y += core/subdev/mc/nv98.o
index 1b653dd74a7046ceaae41bca181f3097827dcccd..08b88591ed6036924c76d51efcf0d1d32c91210e 100644 (file)
@@ -311,7 +311,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
@@ -334,7 +334,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv4e_fb_oclass;
@@ -357,7 +357,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
@@ -380,7 +380,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
@@ -403,7 +403,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
                device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
-               device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nv4c_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
index 940eaa5d8b9a4bb0e3ea224cfe2ced8ec8585b44..9ad722e4e087007df76e77473c5a5f98ce24be74 100644 (file)
@@ -1142,7 +1142,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
        if (conf != ~0) {
                if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
                        u32 soff = (ffs(outp.or) - 1) * 0x08;
-                       u32 ctrl = nv_rd32(priv, 0x610798 + soff);
+                       u32 ctrl = nv_rd32(priv, 0x610794 + soff);
                        u32 datarate;
 
                        switch ((ctrl & 0x000f0000) >> 16) {
index 9a850fe19515fe2ddcd513c3497c7d87c86cba8a..54c1b5b471cdfa5682a83587a1d490455d6828c1 100644 (file)
@@ -112,7 +112,7 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
 
        nv_wr32(priv, 0x002270, cur->addr >> 12);
        nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
-       if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
+       if (!nv_wait(priv, 0x002284 + (engine * 8), 0x00100000, 0x00000000))
                nv_error(priv, "runlist %d update timeout\n", engine);
        mutex_unlock(&nv_subdev(priv)->mutex);
 }
index 30ed19c52e05ca0cd6a1e759a8fc426f61f246a7..7a367c4029786f9d3b0941b62d697902b3681e93 100644 (file)
@@ -539,7 +539,7 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
                                ustatus &= ~0x04030000;
                        }
                        if (ustatus && display) {
-                               nv_error("%s - TP%d:", name, i);
+                               nv_error(priv, "%s - TP%d:", name, i);
                                nouveau_bitfield_print(nv50_mpc_traps, ustatus);
                                pr_cont("\n");
                                ustatus = 0;
index adc88b73d9118e4b7d50ed21209675fbc47a8820..3c6738edd127040337ff8fc53b6125a47e812ad7 100644 (file)
@@ -47,6 +47,7 @@ struct nouveau_mc_oclass {
 extern struct nouveau_oclass *nv04_mc_oclass;
 extern struct nouveau_oclass *nv40_mc_oclass;
 extern struct nouveau_oclass *nv44_mc_oclass;
+extern struct nouveau_oclass *nv4c_mc_oclass;
 extern struct nouveau_oclass *nv50_mc_oclass;
 extern struct nouveau_oclass *nv94_mc_oclass;
 extern struct nouveau_oclass *nv98_mc_oclass;
index aa0fbbec7f08212cd8b3106ecb57ec4ff491403b..ef0c9c4a8cc3925f9f8df1279417fc028a39f2f9 100644 (file)
@@ -130,6 +130,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)
        u16 pcir;
        int i;
 
+       /* there is no prom on nv4x IGP's */
+       if (device->card_type == NV_40 && device->chipset >= 0x4c)
+               return;
+
        /* enable access to rom */
        if (device->card_type >= NV_50)
                pcireg = 0x088050;
index 9159a5ccee930d21172884bf9f23972c222669b5..265d1253624a337d7ebf8604a9ca1207113ee1cf 100644 (file)
@@ -36,7 +36,7 @@ nv1a_fb_oclass = &(struct nv04_fb_impl) {
                .fini = _nouveau_fb_fini,
        },
        .base.memtype = nv04_fb_memtype_valid,
-       .base.ram = &nv10_ram_oclass,
+       .base.ram = &nv1a_ram_oclass,
        .tile.regions = 8,
        .tile.init = nv10_fb_tile_init,
        .tile.fini = nv10_fb_tile_fini,
index b0d5c31606c1c50e0686f1aa000c8dc2876062c2..81a408e7d034636f6b940107839394b9a03b0cab 100644 (file)
@@ -14,6 +14,7 @@ int  nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *,
 extern const struct nouveau_mc_intr nv04_mc_intr[];
 int  nv04_mc_init(struct nouveau_object *);
 void nv40_mc_msi_rearm(struct nouveau_mc *);
+int  nv44_mc_init(struct nouveau_object *object);
 int  nv50_mc_init(struct nouveau_object *);
 extern const struct nouveau_mc_intr nv50_mc_intr[];
 extern const struct nouveau_mc_intr nvc0_mc_intr[];
index 3bfee5c6c4f21e3bd25430bb693e5d634c86773a..cc4d0d2d886e679612ca269459b4cc756cc5ab31 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "nv04.h"
 
-static int
+int
 nv44_mc_init(struct nouveau_object *object)
 {
        struct nv04_mc_priv *priv = (void *)object;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
new file mode 100644 (file)
index 0000000..a75c35c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2014 Ilia Mirkin
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ilia Mirkin
+ */
+
+#include "nv04.h"
+
+static void
+nv4c_mc_msi_rearm(struct nouveau_mc *pmc)
+{
+       struct nv04_mc_priv *priv = (void *)pmc;
+       nv_wr08(priv, 0x088050, 0xff);
+}
+
+struct nouveau_oclass *
+nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
+       .base.handle = NV_SUBDEV(MC, 0x4c),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_mc_ctor,
+               .dtor = _nouveau_mc_dtor,
+               .init = nv44_mc_init,
+               .fini = _nouveau_mc_fini,
+       },
+       .intr = nv04_mc_intr,
+       .msi_rearm = nv4c_mc_msi_rearm,
+}.base;
index 4ef83df2b246fb335dc8ce05bafead80ed7ac180..83face3f608f020f70d7d11dda363c5817102238 100644 (file)
@@ -106,6 +106,29 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
        return 0;
 }
 
+/*
+ * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special
+ * requirements on the fourth parameter, so a private implementation
+ * instead of using acpi_check_dsm().
+ */
+static int nouveau_check_optimus_dsm(acpi_handle handle)
+{
+       int result;
+
+       /*
+        * Function 0 returns a Buffer containing available functions.
+        * The args parameter is ignored for function 0, so just put 0 in it
+        */
+       if (nouveau_optimus_dsm(handle, 0, 0, &result))
+               return 0;
+
+       /*
+        * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
+        * If the n-th bit is enabled, function n is supported
+        */
+       return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS);
+}
+
 static int nouveau_dsm(acpi_handle handle, int func, int arg)
 {
        int ret = 0;
@@ -207,8 +230,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
                           1 << NOUVEAU_DSM_POWER))
                retval |= NOUVEAU_DSM_HAS_MUX;
 
-       if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100,
-                          1 << NOUVEAU_DSM_OPTIMUS_CAPS))
+       if (nouveau_check_optimus_dsm(dhandle))
                retval |= NOUVEAU_DSM_HAS_OPT;
 
        if (retval & NOUVEAU_DSM_HAS_OPT) {
index 488686d490c0c7a96ba016e0f55a4beffcda6e4f..4aed1714b9ab7d289bbadc867f9af40b046825f2 100644 (file)
@@ -1249,7 +1249,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                        mem->bus.is_iomem = !dev->agp->cant_use_aperture;
                }
 #endif
-               if (!node->memtype)
+               if (nv_device(drm->device)->card_type < NV_50 || !node->memtype)
                        /* untiled */
                        break;
                /* fallthrough, tiled memory */
index 78c8e7146d56b2c5f7d189e372e542f4d9b43717..4ee702ac8907bcc3d486000b525ad61857cdf5ff 100644 (file)
@@ -376,6 +376,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto fail_device;
 
+       dev->irq_enabled = true;
+
        /* workaround an odd issue on nvc1 by disabling the device's
         * nosnoop capability.  hopefully won't cause issues until a
         * better fix is found - assuming there is one...
@@ -475,6 +477,7 @@ nouveau_drm_remove(struct pci_dev *pdev)
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_object *device;
 
+       dev->irq_enabled = false;
        device = drm->client.base.device;
        drm_put_dev(dev);
 
@@ -863,13 +866,16 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        int ret;
 
-       if (nouveau_runtime_pm == 0)
-               return -EINVAL;
+       if (nouveau_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
 
        /* are we optimus enabled? */
        if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
                DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
-               return -EINVAL;
+               pm_runtime_forbid(dev);
+               return -EBUSY;
        }
 
        nv_debug_level(SILENT);
@@ -920,12 +926,15 @@ static int nouveau_pmops_runtime_idle(struct device *dev)
        struct nouveau_drm *drm = nouveau_drm(drm_dev);
        struct drm_crtc *crtc;
 
-       if (nouveau_runtime_pm == 0)
+       if (nouveau_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
                return -EBUSY;
+       }
 
        /* are we optimus enabled? */
        if (nouveau_runtime_pm == -1 && !nouveau_is_optimus() && !nouveau_is_v1_dsm()) {
                DRM_DEBUG_DRIVER("failing to power off - not optimus\n");
+               pm_runtime_forbid(dev);
                return -EBUSY;
        }
 
index 81638d7f2efff69cdce86ac515aac2c19191aefe..471347edc27eb869816e5d5cfed1ccd01f4c7b6f 100644 (file)
@@ -14,7 +14,9 @@ nouveau_vga_set_decode(void *priv, bool state)
 {
        struct nouveau_device *device = nouveau_dev(priv);
 
-       if (device->chipset >= 0x40)
+       if (device->card_type == NV_40 && device->chipset >= 0x4c)
+               nv_wr32(device, 0x088060, state);
+       else if (device->chipset >= 0x40)
                nv_wr32(device, 0x088054, state);
        else
                nv_wr32(device, 0x001854, state);
index a9338c85630fe0548336e8c8c492361ce797dd5a..daa4dd375ab15367266d6f0041af84386d6699bb 100644 (file)
@@ -559,7 +559,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        u32 adjusted_clock = mode->clock;
        int encoder_mode = atombios_get_encoder_mode(encoder);
        u32 dp_clock = mode->clock;
-       int bpc = radeon_get_monitor_bpc(connector);
+       int bpc = radeon_crtc->bpc;
        bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
 
        /* reset the pll flags */
@@ -1176,7 +1176,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
                evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split);
 
                /* Set NUM_BANKS. */
-               if (rdev->family >= CHIP_BONAIRE) {
+               if (rdev->family >= CHIP_TAHITI) {
                        unsigned tileb, index, num_banks, tile_split_bytes;
 
                        /* Calculate the macrotile mode index. */
@@ -1194,13 +1194,14 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
                                return -EINVAL;
                        }
 
-                       num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+                       if (rdev->family >= CHIP_BONAIRE)
+                               num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3;
+                       else
+                               num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 0x3;
                        fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks);
                } else {
-                       /* SI and older. */
-                       if (rdev->family >= CHIP_TAHITI)
-                               tmp = rdev->config.si.tile_config;
-                       else if (rdev->family >= CHIP_CAYMAN)
+                       /* NI and older. */
+                       if (rdev->family >= CHIP_CAYMAN)
                                tmp = rdev->config.cayman.tile_config;
                        else
                                tmp = rdev->config.evergreen.tile_config;
@@ -1773,6 +1774,20 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                        return ATOM_PPLL1;
                DRM_ERROR("unable to allocate a PPLL\n");
                return ATOM_PPLL_INVALID;
+       } else if (ASIC_IS_DCE41(rdev)) {
+               /* Don't share PLLs on DCE4.1 chips */
+               if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+                       if (rdev->clock.dp_extclk)
+                               /* skip PPLL programming if using ext clock */
+                               return ATOM_PPLL_INVALID;
+               }
+               pll_in_use = radeon_get_pll_use_mask(crtc);
+               if (!(pll_in_use & (1 << ATOM_PPLL1)))
+                       return ATOM_PPLL1;
+               if (!(pll_in_use & (1 << ATOM_PPLL2)))
+                       return ATOM_PPLL2;
+               DRM_ERROR("unable to allocate a PPLL\n");
+               return ATOM_PPLL_INVALID;
        } else if (ASIC_IS_DCE4(rdev)) {
                /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
                 * depending on the asic:
@@ -1800,7 +1815,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                if (pll != ATOM_PPLL_INVALID)
                                        return pll;
                        }
-               } else if (!ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */
+               } else {
                        /* use the same PPLL for all monitors with the same clock */
                        pll = radeon_get_shared_nondp_ppll(crtc);
                        if (pll != ATOM_PPLL_INVALID)
index a42d61571f49fa877e6c42564b7edeb9b1e2ef5b..607dc14d195e3540f103bf798d2e6f0e10e5634f 100644 (file)
@@ -464,11 +464,12 @@ atombios_tv_setup(struct drm_encoder *encoder, int action)
 
 static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
 {
-       struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int bpc = 8;
 
-       if (connector)
-               bpc = radeon_get_monitor_bpc(connector);
+       if (encoder->crtc) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+               bpc = radeon_crtc->bpc;
+       }
 
        switch (bpc) {
        case 0:
@@ -1313,7 +1314,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                        }
                        if (is_dp)
                                args.v5.ucLaneNum = dp_lane_count;
-                       else if (radeon_encoder->pixel_clock > 165000)
+                       else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
                                args.v5.ucLaneNum = 8;
                        else
                                args.v5.ucLaneNum = 4;
index 0fbd36f3d4e9da34b65bc5f8ed302dc143b2d3c7..ea103ccdf4bd517205b95e82a1437e4cf510f8f2 100644 (file)
@@ -29,6 +29,7 @@
 #include "cypress_dpm.h"
 #include "btc_dpm.h"
 #include "atom.h"
+#include <linux/seq_file.h>
 
 #define MC_CG_ARB_FREQ_F0           0x0a
 #define MC_CG_ARB_FREQ_F1           0x0b
@@ -2756,6 +2757,37 @@ void btc_dpm_fini(struct radeon_device *rdev)
        r600_free_extended_power_table(rdev);
 }
 
+void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+                                                    struct seq_file *m)
+{
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
+       struct rv7xx_ps *ps = rv770_get_ps(rps);
+       struct rv7xx_pl *pl;
+       u32 current_index =
+               (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+               CURRENT_PROFILE_INDEX_SHIFT;
+
+       if (current_index > 2) {
+               seq_printf(m, "invalid dpm profile %d\n", current_index);
+       } else {
+               if (current_index == 0)
+                       pl = &ps->low;
+               else if (current_index == 1)
+                       pl = &ps->medium;
+               else /* current_index == 2 */
+                       pl = &ps->high;
+               seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+               if (rdev->family >= CHIP_CEDAR) {
+                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+                                  current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+               } else {
+                       seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n",
+                                  current_index, pl->sclk, pl->mclk, pl->vddc);
+               }
+       }
+}
+
 u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
index 29e32de7e02546e98951d6656703c6848a4de03d..9c65be2d55a91bedd525a8fdf4ce448184b69433 100644 (file)
 #       define DYN_SPREAD_SPECTRUM_EN                   (1 << 23)
 #       define AC_DC_SW                                 (1 << 24)
 
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x66c
+#       define CURRENT_PROFILE_INDEX_MASK                 (0xf << 4)
+#       define CURRENT_PROFILE_INDEX_SHIFT                4
+
 #define        CG_BIF_REQ_AND_RSP                              0x7f4
 #define                CG_CLIENT_REQ(x)                        ((x) << 0)
 #define                CG_CLIENT_REQ_MASK                      (0xff << 0)
index e6419ca7cd375d6958ebcd339fb68a004c56cd1a..bbb17841a9e57ad2fdc44425a26d658848892f4c 100644 (file)
@@ -3046,7 +3046,7 @@ static u32 cik_create_bitmask(u32 bit_width)
 }
 
 /**
- * cik_select_se_sh - select which SE, SH to address
+ * cik_get_rb_disabled - computes the mask of disabled RBs
  *
  * @rdev: radeon_device pointer
  * @max_rb_num: max RBs (render backends) for the asic
@@ -4134,8 +4134,11 @@ static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
 {
        if (enable)
                WREG32(CP_MEC_CNTL, 0);
-       else
+       else {
                WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+               rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX].ready = false;
+               rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
+       }
        udelay(50);
 }
 
@@ -7902,7 +7905,8 @@ int cik_resume(struct radeon_device *rdev)
        /* init golden registers */
        cik_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = cik_startup(rdev);
index 1ecb3f1070e35c6ed3516e5f325eeeb61bc795b2..94626ea90fa57abc5efca249ab4d0d08cfc9566d 100644 (file)
@@ -264,6 +264,8 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)
                WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
                WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
        }
+       rdev->ring[R600_RING_TYPE_DMA_INDEX].ready = false;
+       rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX].ready = false;
 }
 
 /**
@@ -291,6 +293,11 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)
        u32 me_cntl, reg_offset;
        int i;
 
+       if (enable == false) {
+               cik_sdma_gfx_stop(rdev);
+               cik_sdma_rlc_stop(rdev);
+       }
+
        for (i = 0; i < 2; i++) {
                if (i == 0)
                        reg_offset = SDMA0_REGISTER_OFFSET;
@@ -420,10 +427,6 @@ static int cik_sdma_load_microcode(struct radeon_device *rdev)
        if (!rdev->sdma_fw)
                return -EINVAL;
 
-       /* stop the gfx rings and rlc compute queues */
-       cik_sdma_gfx_stop(rdev);
-       cik_sdma_rlc_stop(rdev);
-
        /* halt the MEs */
        cik_sdma_enable(rdev, false);
 
@@ -492,9 +495,6 @@ int cik_sdma_resume(struct radeon_device *rdev)
  */
 void cik_sdma_fini(struct radeon_device *rdev)
 {
-       /* stop the gfx rings and rlc compute queues */
-       cik_sdma_gfx_stop(rdev);
-       cik_sdma_rlc_stop(rdev);
        /* halt the MEs */
        cik_sdma_enable(rdev, false);
        radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
index 713a5d35990102ea315fa078a93c11d6c1aae1f5..94e85875199481ca46e3c84cef453aaec3970356 100644 (file)
@@ -278,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev)
        return !ASIC_IS_NODCE(rdev);
 }
 
-static void dce6_audio_enable(struct radeon_device *rdev,
-                             struct r600_audio_pin *pin,
-                             bool enable)
+void dce6_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable)
 {
+       if (!pin)
+               return;
+
        WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL,
-                       AUDIO_ENABLED);
-       DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
+                       enable ? AUDIO_ENABLED : 0);
 }
 
 static const u32 pin_offsets[7] =
@@ -323,7 +325,8 @@ int dce6_audio_init(struct radeon_device *rdev)
                rdev->audio.pin[i].connected = false;
                rdev->audio.pin[i].offset = pin_offsets[i];
                rdev->audio.pin[i].id = i;
-               dce6_audio_enable(rdev, &rdev->audio.pin[i], true);
+               /* disable audio.  it will be set up later */
+               dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
        }
 
        return 0;
index f2b9e21ce4da063a03004c4705a3662b2e78c437..27b0ff16082ebbbe10eb385b8bce24e127b5091d 100644 (file)
@@ -1680,7 +1680,7 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd)
        case RADEON_HPD_6:
                if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE)
                        connected = true;
-                       break;
+               break;
        default:
                break;
        }
@@ -5299,7 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev)
        /* init golden registers */
        evergreen_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = evergreen_startup(rdev);
@@ -5475,9 +5476,9 @@ void evergreen_fini(struct radeon_device *rdev)
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       evergreen_pcie_gart_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
+       evergreen_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
        radeon_fence_driver_fini(rdev);
index 0c6d5cef4cf121770c63fcb559bf6cc187640292..05b0c95813fd79ff4c31ade3a90c0ad1880d028d 100644 (file)
@@ -306,6 +306,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
                return;
        offset = dig->afmt->offset;
 
+       /* disable audio prior to setting up hw */
+       if (ASIC_IS_DCE6(rdev)) {
+               dig->afmt->pin = dce6_audio_get_pin(rdev);
+               dce6_audio_enable(rdev, dig->afmt->pin, false);
+       } else {
+               dig->afmt->pin = r600_audio_get_pin(rdev);
+               r600_audio_enable(rdev, dig->afmt->pin, false);
+       }
+
        evergreen_audio_set_dto(encoder, mode->clock);
 
        WREG32(HDMI_VBI_PACKET_CONTROL + offset,
@@ -409,12 +418,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
        WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
        WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
+
+       /* enable audio after to setting up hw */
+       if (ASIC_IS_DCE6(rdev))
+               dce6_audio_enable(rdev, dig->afmt->pin, true);
+       else
+               r600_audio_enable(rdev, dig->afmt->pin, true);
 }
 
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
 {
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
@@ -427,15 +440,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
-       if (enable) {
-               if (ASIC_IS_DCE6(rdev))
-                       dig->afmt->pin = dce6_audio_get_pin(rdev);
-               else
-                       dig->afmt->pin = r600_audio_get_pin(rdev);
-       } else {
-               dig->afmt->pin = NULL;
-       }
-
        dig->afmt->enabled = enable;
 
        DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
index 76ada8cfe902a4d9eaa9890404c390371f856621..3a03ba37d04346fb5200d67ee002716ae549a600 100644 (file)
@@ -57,7 +57,7 @@ typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
 
 #define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
 
-#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters   0x8
 #define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable      0xC
 #define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
 
index b6e01d5d2cced24edc67e773c84cba33a6d5fef8..351db361239db1d2800f845b2e9e9d02d541cc2b 100644 (file)
@@ -1223,7 +1223,7 @@ int kv_dpm_enable(struct radeon_device *rdev)
 
 int kv_dpm_late_enable(struct radeon_device *rdev)
 {
-       int ret;
+       int ret = 0;
 
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
index ea932ac66fc6647da43a8cf775b60ade25d478de..bf6300cfd62d0799deaefbd698027cf8d811dbc6 100644 (file)
@@ -2105,7 +2105,8 @@ int cayman_resume(struct radeon_device *rdev)
        /* init golden registers */
        ni_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = cayman_startup(rdev);
index c351226ecb31b0d9fa2d94a32ac23d504d61952b..ca814276b07539741b53c167abc1a0bd5105173a 100644 (file)
@@ -2588,7 +2588,7 @@ static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
        if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
                enable_sq_ramping = false;
 
-       if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+       if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
                enable_sq_ramping = false;
 
        for (i = 0; i < state->performance_level_count; i++) {
@@ -3945,7 +3945,6 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
        struct ni_ps *ps = ni_get_ps(rps);
-       u16 vddc;
        struct rv7xx_pl *pl = &ps->performance_levels[index];
 
        ps->performance_level_count = index + 1;
@@ -3961,8 +3960,8 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
 
        /* patch up vddc if necessary */
        if (pl->vddc == 0xff01) {
-               if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
-                       pl->vddc = vddc;
+               if (pi->max_vddc)
+                       pl->vddc = pi->max_vddc;
        }
 
        if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
@@ -4322,7 +4321,8 @@ void ni_dpm_print_power_state(struct radeon_device *rdev,
 void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                    struct seq_file *m)
 {
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
        struct ni_ps *ps = ni_get_ps(rps);
        struct rv7xx_pl *pl;
        u32 current_index =
index ef024ce3f7ccfd39b1be47be9840a401b588b1dc..3cc78bb66042fc5509f26825560847374888288e 100644 (file)
@@ -3942,8 +3942,6 @@ int r100_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r100_startup(rdev);
        if (r) {
index 7c63ef840e86abaf04f216201b32ee2f40323b9b..0b658b34b33ab1d2874c0c85a668b4fa48da0ecc 100644 (file)
@@ -1430,8 +1430,6 @@ int r300_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r300_startup(rdev);
        if (r) {
index 3768aab2710b3943261312c4fcc5184b4f18a6fb..802b19220a21358712dc304a894db892ec3537fb 100644 (file)
@@ -325,8 +325,6 @@ int r420_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r420_startup(rdev);
        if (r) {
index e209eb75024f9dc1c441518cbe8f8d70a41844f5..98d6053c36c678aaf598e7a0b63193d00d042f5b 100644 (file)
@@ -240,8 +240,6 @@ int r520_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = r520_startup(rdev);
        if (r) {
index 56140b4e5bb2e9fa7fc72339cc29f88b398aff1c..647ef407921764692758c56e03f92b737202e317 100644 (file)
@@ -2968,7 +2968,8 @@ int r600_resume(struct radeon_device *rdev)
        /* post card */
        atom_asic_init(rdev->mode_info.atom_context);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = r600_startup(rdev);
@@ -3991,6 +3992,10 @@ restart_ih:
                                break;
                        }
                        break;
+               case 124: /* UVD */
+                       DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
+                       radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
+                       break;
                case 176: /* CP_INT in ring buffer */
                case 177: /* CP_INT in IB1 */
                case 178: /* CP_INT in IB2 */
index 47fc2b88697928b4272a0878927d189762a82000..bffac10c4296b3b4c28d9f7a52322fe51e9ae7c5 100644 (file)
@@ -142,12 +142,15 @@ void r600_audio_update_hdmi(struct work_struct *work)
 }
 
 /* enable the audio stream */
-static void r600_audio_enable(struct radeon_device *rdev,
-                             struct r600_audio_pin *pin,
-                             bool enable)
+void r600_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable)
 {
        u32 value = 0;
 
+       if (!pin)
+               return;
+
        if (ASIC_IS_DCE4(rdev)) {
                if (enable) {
                        value |= 0x81000000; /* Required to enable audio */
@@ -158,7 +161,6 @@ static void r600_audio_enable(struct radeon_device *rdev,
                WREG32_P(R600_AUDIO_ENABLE,
                         enable ? 0x81000000 : 0x0, ~0x81000000);
        }
-       DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id);
 }
 
 /*
@@ -178,8 +180,8 @@ int r600_audio_init(struct radeon_device *rdev)
        rdev->audio.pin[0].status_bits = 0;
        rdev->audio.pin[0].category_code = 0;
        rdev->audio.pin[0].id = 0;
-
-       r600_audio_enable(rdev, &rdev->audio.pin[0], true);
+       /* disable audio.  it will be set up later */
+       r600_audio_enable(rdev, &rdev->audio.pin[0], false);
 
        return 0;
 }
index 3016fc14f502c49a61c2343c3b2ca877d2590109..85a2bb28aed27699e464edc54a8573c8d1d41b39 100644 (file)
@@ -329,9 +329,6 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
        u8 *sadb;
        int sad_count;
 
-       /* XXX: setting this register causes hangs on some asics */
-       return;
-
        list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
                if (connector->encoder == encoder) {
                        radeon_connector = to_radeon_connector(connector);
@@ -460,6 +457,10 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
                return;
        offset = dig->afmt->offset;
 
+       /* disable audio prior to setting up hw */
+       dig->afmt->pin = r600_audio_get_pin(rdev);
+       r600_audio_enable(rdev, dig->afmt->pin, false);
+
        r600_audio_set_dto(encoder, mode->clock);
 
        WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
@@ -531,6 +532,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
 
        r600_hdmi_audio_workaround(encoder);
+
+       /* enable audio after to setting up hw */
+       r600_audio_enable(rdev, dig->afmt->pin, true);
 }
 
 /*
@@ -651,11 +655,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
-       if (enable)
-               dig->afmt->pin = r600_audio_get_pin(rdev);
-       else
-               dig->afmt->pin = NULL;
-
        /* Older chipsets require setting HDMI and routing manually */
        if (!ASIC_IS_DCE3(rdev)) {
                if (enable)
index 4a8ac1cd6b4c65582690e035e026aa6f1b125e00..e887d027b6d01fda8082305d11ff1b27bad06db9 100644 (file)
@@ -135,6 +135,9 @@ extern int radeon_hard_reset;
 /* R600+ */
 #define R600_RING_TYPE_UVD_INDEX       5
 
+/* number of hw syncs before falling back on blocking */
+#define RADEON_NUM_SYNCS                       4
+
 /* hardcode those limit for now */
 #define RADEON_VA_IB_OFFSET                    (1 << 20)
 #define RADEON_VA_RESERVED_SIZE                        (8 << 20)
@@ -554,7 +557,6 @@ int radeon_mode_dumb_mmap(struct drm_file *filp,
 /*
  * Semaphores.
  */
-/* everything here is constant */
 struct radeon_semaphore {
        struct radeon_sa_bo             *sa_bo;
        signed                          waiters;
@@ -2745,6 +2747,12 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
 void r600_audio_update_hdmi(struct work_struct *work);
 struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev);
 struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev);
+void r600_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable);
+void dce6_audio_enable(struct radeon_device *rdev,
+                      struct r600_audio_pin *pin,
+                      bool enable);
 
 /*
  * R600 vram scratch functions
index f74db43346fd86f4658e11cc62e6e08134127936..dda02bfc10a49b55497479e3a911167b91397481 100644 (file)
@@ -1555,7 +1555,7 @@ static struct radeon_asic btc_asic = {
                .get_sclk = &btc_dpm_get_sclk,
                .get_mclk = &btc_dpm_get_mclk,
                .print_power_state = &rv770_dpm_print_power_state,
-               .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+               .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &rv770_dpm_force_performance_level,
                .vblank_too_short = &btc_dpm_vblank_too_short,
        },
index b3bc433eed4c3bd832424051306a845461c90aa8..ae637cfda783285a0f2638435e6620c6026fb534 100644 (file)
@@ -551,6 +551,8 @@ void btc_dpm_fini(struct radeon_device *rdev);
 u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low);
 u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
 bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
+void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+                                                    struct seq_file *m);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 int sumo_dpm_late_enable(struct radeon_device *rdev);
index 485848f889f55c9f4b86bf61bd8c019e2ad96a27..fa9a9c02751ea865251f7854665c3757caa48e00 100644 (file)
@@ -219,7 +219,8 @@ static int radeon_atpx_verify_interface(struct radeon_atpx *atpx)
        memcpy(&output, info->buffer.pointer, size);
 
        /* TODO: check version? */
-       printk("ATPX version %u\n", output.version);
+       printk("ATPX version %u, functions 0x%08x\n",
+              output.version, output.function_bits);
 
        radeon_atpx_parse_functions(&atpx->functions, output.function_bits);
 
index b012cbbc3ed5a9b892b433eff0ee5f3134a130de..044bc98fb459e46fac62b929696ad047f835360d 100644 (file)
@@ -1521,13 +1521,16 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        if (r)
                DRM_ERROR("ib ring test failed (%d).\n", r);
 
-       if (rdev->pm.dpm_enabled) {
+       if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
                /* do dpm late init */
                r = radeon_pm_late_init(rdev);
                if (r) {
                        rdev->pm.dpm_enabled = false;
                        DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
                }
+       } else {
+               /* resume old pm late */
+               radeon_pm_resume(rdev);
        }
 
        radeon_restore_bios_scratch_regs(rdev);
index d680608f6f5bc9a80e879b4f24769f8a9ffb1e8c..fbd8b930f2bec75276a5baf781653e658a023eaa 100644 (file)
@@ -571,6 +571,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
                radeon_crtc->max_cursor_width = CURSOR_WIDTH;
                radeon_crtc->max_cursor_height = CURSOR_HEIGHT;
        }
+       dev->mode_config.cursor_width = radeon_crtc->max_cursor_width;
+       dev->mode_config.cursor_height = radeon_crtc->max_cursor_height;
 
 #if 0
        radeon_crtc->mode_set.crtc = &radeon_crtc->base;
index 84a1bbb75f914a7bd914ad9120b8a2e2ac9aac5a..f633c2782170b09bcc8722d1568cbe0a8c665f12 100644 (file)
@@ -403,11 +403,15 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        int ret;
 
-       if (radeon_runtime_pm == 0)
-               return -EINVAL;
+       if (radeon_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
 
-       if (radeon_runtime_pm == -1 && !radeon_is_px())
-               return -EINVAL;
+       if (radeon_runtime_pm == -1 && !radeon_is_px()) {
+               pm_runtime_forbid(dev);
+               return -EBUSY;
+       }
 
        drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
        drm_kms_helper_poll_disable(drm_dev);
@@ -456,12 +460,15 @@ static int radeon_pmops_runtime_idle(struct device *dev)
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        struct drm_crtc *crtc;
 
-       if (radeon_runtime_pm == 0)
+       if (radeon_runtime_pm == 0) {
+               pm_runtime_forbid(dev);
                return -EBUSY;
+       }
 
        /* are we PX enabled? */
        if (radeon_runtime_pm == -1 && !radeon_is_px()) {
                DRM_DEBUG_DRIVER("failing to power off - not px\n");
+               pm_runtime_forbid(dev);
                return -EBUSY;
        }
 
index 114d1672d616d0b5d7b85ab5d739da66f2db823e..66ed3ea7144010e7c95bc0d07c01ad5499242947 100644 (file)
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+
+#if defined(CONFIG_VGA_SWITCHEROO)
+bool radeon_is_px(void);
+#else
+static inline bool radeon_is_px(void) { return false; }
+#endif
+
 /**
  * radeon_driver_unload_kms - Main unload function for KMS.
  *
@@ -130,7 +137,8 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
                                "Error during ACPI methods call\n");
        }
 
-       if (radeon_runtime_pm != 0) {
+       if ((radeon_runtime_pm == 1) ||
+           ((radeon_runtime_pm == -1) && radeon_is_px())) {
                pm_runtime_use_autosuspend(dev->dev);
                pm_runtime_set_autosuspend_delay(dev->dev, 5000);
                pm_runtime_set_active(dev->dev);
@@ -537,6 +545,10 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
 
                radeon_vm_init(rdev, &fpriv->vm);
 
+               r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
+               if (r)
+                       return r;
+
                /* map the ib pool buffer read only into
                 * virtual address space */
                bo_va = radeon_vm_bo_add(rdev, &fpriv->vm,
@@ -544,6 +556,8 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET,
                                          RADEON_VM_PAGE_READABLE |
                                          RADEON_VM_PAGE_SNOOPED);
+
+               radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
                if (r) {
                        radeon_vm_fini(rdev, &fpriv->vm);
                        kfree(fpriv);
index 1b783f0e6d3ad084b0a62629a4b5d67c9e92453f..15e44a7281ab96f6b14592ed2e4e840ddae0b74f 100644 (file)
@@ -139,7 +139,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        }
 
        /* 64 dwords should be enough for fence too */
-       r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8);
+       r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8);
        if (r) {
                dev_err(rdev->dev, "scheduling IB failed (%d).\n", r);
                return r;
index 2b42aa1914f2006dabddee990cd14fc919668d59..9006b32d5eed0433d336ef56e1bfb17c6fffa0de 100644 (file)
 int radeon_semaphore_create(struct radeon_device *rdev,
                            struct radeon_semaphore **semaphore)
 {
+       uint32_t *cpu_addr;
        int i, r;
 
        *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
        if (*semaphore == NULL) {
                return -ENOMEM;
        }
-       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
-                            &(*semaphore)->sa_bo, 8, 8, true);
+       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
+                            8 * RADEON_NUM_SYNCS, 8, true);
        if (r) {
                kfree(*semaphore);
                *semaphore = NULL;
@@ -49,7 +50,10 @@ int radeon_semaphore_create(struct radeon_device *rdev,
        }
        (*semaphore)->waiters = 0;
        (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
-       *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
+
+       cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo);
+       for (i = 0; i < RADEON_NUM_SYNCS; ++i)
+               cpu_addr[i] = 0;
 
        for (i = 0; i < RADEON_NUM_RINGS; ++i)
                (*semaphore)->sync_to[i] = NULL;
@@ -125,6 +129,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                                struct radeon_semaphore *semaphore,
                                int ring)
 {
+       unsigned count = 0;
        int i, r;
 
         for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -140,6 +145,12 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                        return -EINVAL;
                }
 
+               if (++count > RADEON_NUM_SYNCS) {
+                       /* not enough room, wait manually */
+                       radeon_fence_wait_locked(fence);
+                       continue;
+               }
+
                /* allocate enough space for sync command */
                r = radeon_ring_alloc(rdev, &rdev->ring[i], 16);
                if (r) {
@@ -164,6 +175,8 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
 
                radeon_ring_commit(rdev, &rdev->ring[i]);
                radeon_fence_note_sync(fence, ring);
+
+               semaphore->gpu_addr += 8;
        }
 
        return 0;
index 77f5b0c3edb8d8b1f4835620d626c3981171c7a6..040a2a10ea17e8136a4274decc83de131ad79e3f 100644 (file)
@@ -714,6 +714,9 @@ int radeon_ttm_init(struct radeon_device *rdev)
                DRM_ERROR("Failed initializing VRAM heap.\n");
                return r;
        }
+       /* Change the size here instead of the init above so only lpfn is affected */
+       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
        r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
                             RADEON_GEM_DOMAIN_VRAM,
                             NULL, &rdev->stollen_vga_memory);
@@ -935,7 +938,7 @@ static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
        while (size) {
                loff_t p = *pos / PAGE_SIZE;
                unsigned off = *pos & ~PAGE_MASK;
-               ssize_t cur_size = min(size, PAGE_SIZE - off);
+               size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
                struct page *page;
                void *ptr;
 
index 6781fee1eaadc21a68e50de696dd353be0a3e9e5..3e6804b2b2ef748e9727e34817243aa31e7f9210 100644 (file)
@@ -171,6 +171,8 @@ void radeon_uvd_fini(struct radeon_device *rdev)
 
        radeon_bo_unref(&rdev->uvd.vcpu_bo);
 
+       radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]);
+
        release_firmware(rdev->uvd_fw);
 }
 
index b5c2369cda2fe28ca043fe91f4fcfe12fc227fc6..130d5cc50d436fd90c1d3055bd03e177ba2dce6c 100644 (file)
@@ -474,8 +474,6 @@ int rs400_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs400_startup(rdev);
        if (r) {
index fdcde7693032c28cc30008b494fd573fd82e58f3..72d3616de08e054efe6199fcd529f59cef3e18d5 100644 (file)
@@ -1048,8 +1048,6 @@ int rs600_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs600_startup(rdev);
        if (r) {
index 35950738bd5e449465e0e5062d096e3e8ae9ff0e..3462b64369bfe6142a4c8acfaec09e0bb7d8826c 100644 (file)
@@ -756,8 +756,6 @@ int rs690_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r = rs690_startup(rdev);
        if (r) {
index 98e8138ff77945ecdba447bdcb94310c30dcb1c7..237dd29d9f1c893b1e17600fec59660848b394c3 100644 (file)
@@ -586,8 +586,6 @@ int rv515_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
-       radeon_pm_resume(rdev);
-
        rdev->accel_working = true;
        r =  rv515_startup(rdev);
        if (r) {
index 6c772e58c7845e7d4170287d3e583afd64c5a3e8..fef310773aadc71260888372b896df0afcced749 100644 (file)
@@ -1811,7 +1811,8 @@ int rv770_resume(struct radeon_device *rdev)
        /* init golden registers */
        rv770_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = rv770_startup(rdev);
@@ -1955,9 +1956,9 @@ void rv770_fini(struct radeon_device *rdev)
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       rv770_pcie_gart_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
+       rv770_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
        radeon_fence_driver_fini(rdev);
index 80c595aba359b53c4f748feae3aeab9d207f5db8..b5f63f5e22a324dd6b2714834d58c339359ab918 100644 (file)
@@ -2174,7 +2174,6 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
        struct rv7xx_ps *ps = rv770_get_ps(rps);
        u32 sclk, mclk;
-       u16 vddc;
        struct rv7xx_pl *pl;
 
        switch (index) {
@@ -2214,8 +2213,8 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
 
        /* patch up vddc if necessary */
        if (pl->vddc == 0xff01) {
-               if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
-                       pl->vddc = vddc;
+               if (pi->max_vddc)
+                       pl->vddc = pi->max_vddc;
        }
 
        if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
@@ -2527,14 +2526,7 @@ u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)
 bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
 {
        u32 vblank_time = r600_dpm_get_vblank_time(rdev);
-       u32 switch_limit = 300;
-
-       /* quirks */
-       /* ASUS K70AF */
-       if ((rdev->pdev->device == 0x9553) &&
-           (rdev->pdev->subsystem_vendor == 0x1043) &&
-           (rdev->pdev->subsystem_device == 0x1c42))
-               switch_limit = 200;
+       u32 switch_limit = 200; /* 300 */
 
        /* RV770 */
        /* mclk switching doesn't seem to work reliably on desktop RV770s */
index 09ec4f6c53bb2202dec2e9c039a3877593d2c4fe..9a124d0608b36f3ae594709ac92c4d4ad563b6d7 100644 (file)
@@ -6338,6 +6338,10 @@ restart_ih:
                                break;
                        }
                        break;
+               case 124: /* UVD */
+                       DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
+                       radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
+                       break;
                case 146:
                case 147:
                        addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
@@ -6614,7 +6618,8 @@ int si_resume(struct radeon_device *rdev)
        /* init golden registers */
        si_init_golden_registers(rdev);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.pm_method == PM_METHOD_DPM)
+               radeon_pm_resume(rdev);
 
        rdev->accel_working = true;
        r = si_startup(rdev);
index 0471501338fbbeb9e7b72ee572b2bda126ab475a..0a2f5b4bca430bf94a8d1e49dd9f786437772186 100644 (file)
@@ -2395,7 +2395,7 @@ static int si_populate_sq_ramping_values(struct radeon_device *rdev,
        if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
                enable_sq_ramping = false;
 
-       if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+       if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
                enable_sq_ramping = false;
 
        for (i = 0; i < state->performance_level_count; i++) {
@@ -6472,7 +6472,8 @@ void si_dpm_fini(struct radeon_device *rdev)
 void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                    struct seq_file *m)
 {
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       struct radeon_ps *rps = &eg_pi->current_rps;
        struct ni_ps *ps = ni_get_ps(rps);
        struct rv7xx_pl *pl;
        u32 current_index =
index f121efe12dc5c10a4fd6f1c5283ee7f87e8b0797..8b47b3cd0357cf7065aace2c90fa0751b203b506 100644 (file)
@@ -1807,7 +1807,7 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev
                                                      struct seq_file *m)
 {
        struct sumo_power_info *pi = sumo_get_pi(rdev);
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct radeon_ps *rps = &pi->current_rps;
        struct sumo_ps *ps = sumo_get_ps(rps);
        struct sumo_pl *pl;
        u32 current_index =
index 2d447192d6f7356b1f37af690e1242932b23d7bf..2da0e17eb96060e3027e185106e5f4366561d799 100644 (file)
@@ -1926,7 +1926,8 @@ void trinity_dpm_print_power_state(struct radeon_device *rdev,
 void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                         struct seq_file *m)
 {
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+       struct radeon_ps *rps = &pi->current_rps;
        struct trinity_ps *ps = trinity_get_ps(rps);
        struct trinity_pl *pl;
        u32 current_index =
index 824550db3fed59e2220953e9e9976b8b28443260..d1771004cb52ecee46ae22dc7665bd54adb477b6 100644 (file)
@@ -57,7 +57,6 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0));
        radeon_ring_write(ring, 2);
-       return;
 }
 
 /**
index 88a529008ce0e59210e917422b2cfe07570a0d7d..c71594754f46fa18810d5b654d2c2d31288f6c3a 100644 (file)
@@ -104,7 +104,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
 
 static void tegra_drm_lastclose(struct drm_device *drm)
 {
-#ifdef CONFIG_TEGRA_DRM_FBDEV
+#ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_drm *tegra = drm->dev_private;
 
        tegra_fbdev_restore_mode(tegra->fbdev);
index 338f7f6561d701d601a92b2f6362782536d03e2e..0266fb40479eae05f5176e9835d7c2a1ede75519 100644 (file)
@@ -15,6 +15,7 @@
 struct tegra_rgb {
        struct tegra_output output;
        struct tegra_dc *dc;
+       bool enabled;
 
        struct clk *clk_parent;
        struct clk *clk;
@@ -89,6 +90,9 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
        struct tegra_rgb *rgb = to_rgb(output);
        unsigned long value;
 
+       if (rgb->enabled)
+               return 0;
+
        tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
 
        value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
@@ -122,6 +126,8 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
        tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
        tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
 
+       rgb->enabled = true;
+
        return 0;
 }
 
@@ -130,6 +136,9 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
        struct tegra_rgb *rgb = to_rgb(output);
        unsigned long value;
 
+       if (!rgb->enabled)
+               return 0;
+
        value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
        value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
                   PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
@@ -144,6 +153,8 @@ static int tegra_output_rgb_disable(struct tegra_output *output)
 
        tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
 
+       rgb->enabled = false;
+
        return 0;
 }
 
index 3302f99e7497002edf15f842d1b0abcebb71fbe4..764be36397fd2363d7bf9039574af51a6557136c 100644 (file)
@@ -126,6 +126,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev,
        agp_be->ttm.func = &ttm_agp_func;
 
        if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags, dummy_read_page)) {
+               kfree(agp_be);
                return NULL;
        }
 
index a066513093880a218d185624589ec07efce66b0b..214b7992a3aa74296eeb2a083b28398c08c3cb4d 100644 (file)
@@ -351,9 +351,11 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
 
 moved:
        if (bo->evicted) {
-               ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
-               if (ret)
-                       pr_err("Can not flush read caches\n");
+               if (bdev->driver->invalidate_caches) {
+                       ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
+                       if (ret)
+                               pr_err("Can not flush read caches\n");
+               }
                bo->evicted = false;
        }
 
index 801231c9ae483980afe0e93a0af73a7f07123864..0ce48e5a9cb4a70b56461f0ceb529e2c48ed58aa 100644 (file)
@@ -339,11 +339,13 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
        vma->vm_private_data = bo;
 
        /*
-        * PFNMAP is faster than MIXEDMAP due to reduced page
-        * administration. So use MIXEDMAP only if private VMA, where
-        * we need to support COW.
+        * We'd like to use VM_PFNMAP on shared mappings, where
+        * (vma->vm_flags & VM_SHARED) != 0, for performance reasons,
+        * but for some reason VM_PFNMAP + x86 PAT + write-combine is very
+        * bad for performance. Until that has been sorted out, use
+        * VM_MIXEDMAP on all mappings. See freedesktop.org bug #75719
         */
-       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
        vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
        return 0;
 out_unref:
@@ -359,7 +361,7 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
 
        vma->vm_ops = &ttm_bo_vm_ops;
        vma->vm_private_data = ttm_bo_reference(bo);
-       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_MIXEDMAP;
        vma->vm_flags |= VM_IO | VM_DONTEXPAND;
        return 0;
 }
index 8d67b943ac05ce2d1dd44597d00a1e5a07fd9bdb..0394811251bd7e8dd75159d9d01b045d089d2290 100644 (file)
@@ -177,8 +177,10 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)
        if (obj->vmapping)
                udl_gem_vunmap(obj);
 
-       if (gem_obj->import_attach)
+       if (gem_obj->import_attach) {
                drm_prime_gem_destroy(gem_obj, obj->sg);
+               put_device(gem_obj->dev->dev);
+       }
 
        if (obj->pages)
                udl_gem_put_pages(obj);
@@ -256,9 +258,12 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
        int ret;
 
        /* need to attach */
+       get_device(dev->dev);
        attach = dma_buf_attach(dma_buf, dev->dev);
-       if (IS_ERR(attach))
+       if (IS_ERR(attach)) {
+               put_device(dev->dev);
                return ERR_CAST(attach);
+       }
 
        get_dma_buf(dma_buf);
 
@@ -282,6 +287,6 @@ fail_unmap:
 fail_detach:
        dma_buf_detach(dma_buf, attach);
        dma_buf_put(dma_buf);
-
+       put_device(dev->dev);
        return ERR_PTR(ret);
 }
index b645647b77764f47ccc1f294696579d1ba6d9cf7..f58dc7dd15c576ad2e4e0a702ee6aea1bffb01ce 100644 (file)
@@ -261,12 +261,7 @@ typedef enum SVGA3dSurfaceFormat {
    /* Planar video formats. */
    SVGA3D_YV12                         = 121,
 
-   /* Shader constant formats. */
-   SVGA3D_SURFACE_SHADERCONST_FLOAT    = 122,
-   SVGA3D_SURFACE_SHADERCONST_INT      = 123,
-   SVGA3D_SURFACE_SHADERCONST_BOOL     = 124,
-
-   SVGA3D_FORMAT_MAX                   = 125,
+   SVGA3D_FORMAT_MAX                   = 122,
 } SVGA3dSurfaceFormat;
 
 typedef uint32 SVGA3dColor; /* a, r, g, b */
@@ -1223,9 +1218,19 @@ typedef enum {
 #define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129
 
 #define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE  1130
-
+#define SVGA_3D_CMD_GB_SCREEN_DMA               1131
+#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH  1132
+#define SVGA_3D_CMD_GB_MOB_FENCE                1133
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2        1134
 #define SVGA_3D_CMD_DEFINE_GB_MOB64          1135
 #define SVGA_3D_CMD_REDEFINE_GB_MOB64        1136
+#define SVGA_3D_CMD_NOP_ERROR                1137
+
+#define SVGA_3D_CMD_RESERVED1                1138
+#define SVGA_3D_CMD_RESERVED2                1139
+#define SVGA_3D_CMD_RESERVED3                1140
+#define SVGA_3D_CMD_RESERVED4                1141
+#define SVGA_3D_CMD_RESERVED5                1142
 
 #define SVGA_3D_CMD_MAX                      1142
 #define SVGA_3D_CMD_FUTURE_MAX               3000
@@ -1973,8 +1978,7 @@ struct {
    uint32 sizeInBytes;
    uint32 validSizeInBytes;
    SVGAMobFormat ptDepth;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdSetOTableBase;  /* SVGA_3D_CMD_SET_OTABLE_BASE */
 
 typedef
@@ -1984,15 +1988,13 @@ struct {
    uint32 sizeInBytes;
    uint32 validSizeInBytes;
    SVGAMobFormat ptDepth;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdSetOTableBase64;  /* SVGA_3D_CMD_SET_OTABLE_BASE64 */
 
 typedef
 struct {
    SVGAOTableType type;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdReadbackOTable;  /* SVGA_3D_CMD_READBACK_OTABLE */
 
 /*
@@ -2005,8 +2007,7 @@ struct SVGA3dCmdDefineGBMob {
    SVGAMobFormat ptDepth;
    PPN base;
    uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdDefineGBMob;   /* SVGA_3D_CMD_DEFINE_GB_MOB */
 
 
@@ -2017,8 +2018,7 @@ SVGA3dCmdDefineGBMob;   /* SVGA_3D_CMD_DEFINE_GB_MOB */
 typedef
 struct SVGA3dCmdDestroyGBMob {
    SVGAMobId mobid;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdDestroyGBMob;   /* SVGA_3D_CMD_DESTROY_GB_MOB */
 
 /*
@@ -2031,8 +2031,7 @@ struct SVGA3dCmdRedefineGBMob {
    SVGAMobFormat ptDepth;
    PPN base;
    uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdRedefineGBMob;   /* SVGA_3D_CMD_REDEFINE_GB_MOB */
 
 /*
@@ -2045,8 +2044,7 @@ struct SVGA3dCmdDefineGBMob64 {
    SVGAMobFormat ptDepth;
    PPN64 base;
    uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdDefineGBMob64;   /* SVGA_3D_CMD_DEFINE_GB_MOB64 */
 
 /*
@@ -2059,8 +2057,7 @@ struct SVGA3dCmdRedefineGBMob64 {
    SVGAMobFormat ptDepth;
    PPN64 base;
    uint32 sizeInBytes;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdRedefineGBMob64;   /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
 
 /*
@@ -2070,8 +2067,7 @@ SVGA3dCmdRedefineGBMob64;   /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
 typedef
 struct SVGA3dCmdUpdateGBMobMapping {
    SVGAMobId mobid;
-}
-__attribute__((__packed__))
+} __packed
 SVGA3dCmdUpdateGBMobMapping;   /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */
 
 /*
@@ -2087,7 +2083,8 @@ struct SVGA3dCmdDefineGBSurface {
    uint32 multisampleCount;
    SVGA3dTextureFilter autogenFilter;
    SVGA3dSize size;
-} SVGA3dCmdDefineGBSurface;   /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
+} __packed
+SVGA3dCmdDefineGBSurface;   /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
 
 /*
  * Destroy a guest-backed surface.
@@ -2096,7 +2093,8 @@ struct SVGA3dCmdDefineGBSurface {
 typedef
 struct SVGA3dCmdDestroyGBSurface {
    uint32 sid;
-} SVGA3dCmdDestroyGBSurface;   /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
+} __packed
+SVGA3dCmdDestroyGBSurface;   /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
 
 /*
  * Bind a guest-backed surface to an object.
@@ -2106,7 +2104,8 @@ typedef
 struct SVGA3dCmdBindGBSurface {
    uint32 sid;
    SVGAMobId mobid;
-} SVGA3dCmdBindGBSurface;   /* SVGA_3D_CMD_BIND_GB_SURFACE */
+} __packed
+SVGA3dCmdBindGBSurface;   /* SVGA_3D_CMD_BIND_GB_SURFACE */
 
 /*
  * Conditionally bind a mob to a guest backed surface if testMobid
@@ -2123,7 +2122,7 @@ struct{
    SVGAMobId testMobid;
    SVGAMobId mobid;
    uint32 flags;
-}
+} __packed
 SVGA3dCmdCondBindGBSurface;          /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */
 
 /*
@@ -2135,7 +2134,8 @@ typedef
 struct SVGA3dCmdUpdateGBImage {
    SVGA3dSurfaceImageId image;
    SVGA3dBox box;
-} SVGA3dCmdUpdateGBImage;   /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
+} __packed
+SVGA3dCmdUpdateGBImage;   /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
 
 /*
  * Update an entire guest-backed surface.
@@ -2145,7 +2145,8 @@ struct SVGA3dCmdUpdateGBImage {
 typedef
 struct SVGA3dCmdUpdateGBSurface {
    uint32 sid;
-} SVGA3dCmdUpdateGBSurface;   /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
+} __packed
+SVGA3dCmdUpdateGBSurface;   /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
 
 /*
  * Readback an image in a guest-backed surface.
@@ -2155,7 +2156,8 @@ struct SVGA3dCmdUpdateGBSurface {
 typedef
 struct SVGA3dCmdReadbackGBImage {
    SVGA3dSurfaceImageId image;
-} SVGA3dCmdReadbackGBImage;   /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
+} __packed
+SVGA3dCmdReadbackGBImage;   /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
 
 /*
  * Readback an entire guest-backed surface.
@@ -2165,7 +2167,8 @@ struct SVGA3dCmdReadbackGBImage {
 typedef
 struct SVGA3dCmdReadbackGBSurface {
    uint32 sid;
-} SVGA3dCmdReadbackGBSurface;   /* SVGA_3D_CMD_READBACK_GB_SURFACE */
+} __packed
+SVGA3dCmdReadbackGBSurface;   /* SVGA_3D_CMD_READBACK_GB_SURFACE */
 
 /*
  * Readback a sub rect of an image in a guest-backed surface.  After
@@ -2179,7 +2182,7 @@ struct SVGA3dCmdReadbackGBImagePartial {
    SVGA3dSurfaceImageId image;
    SVGA3dBox box;
    uint32 invertBox;
-}
+} __packed
 SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
 
 /*
@@ -2190,7 +2193,8 @@ SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
 typedef
 struct SVGA3dCmdInvalidateGBImage {
    SVGA3dSurfaceImageId image;
-} SVGA3dCmdInvalidateGBImage;   /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
+} __packed
+SVGA3dCmdInvalidateGBImage;   /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
 
 /*
  * Invalidate an entire guest-backed surface.
@@ -2200,7 +2204,8 @@ struct SVGA3dCmdInvalidateGBImage {
 typedef
 struct SVGA3dCmdInvalidateGBSurface {
    uint32 sid;
-} SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
+} __packed
+SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
 
 /*
  * Invalidate a sub rect of an image in a guest-backed surface.  After
@@ -2214,7 +2219,7 @@ struct SVGA3dCmdInvalidateGBImagePartial {
    SVGA3dSurfaceImageId image;
    SVGA3dBox box;
    uint32 invertBox;
-}
+} __packed
 SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
 
 /*
@@ -2224,7 +2229,8 @@ SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
 typedef
 struct SVGA3dCmdDefineGBContext {
    uint32 cid;
-} SVGA3dCmdDefineGBContext;   /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
+} __packed
+SVGA3dCmdDefineGBContext;   /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
 
 /*
  * Destroy a guest-backed context.
@@ -2233,7 +2239,8 @@ struct SVGA3dCmdDefineGBContext {
 typedef
 struct SVGA3dCmdDestroyGBContext {
    uint32 cid;
-} SVGA3dCmdDestroyGBContext;   /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
+} __packed
+SVGA3dCmdDestroyGBContext;   /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
 
 /*
  * Bind a guest-backed context.
@@ -2252,7 +2259,8 @@ struct SVGA3dCmdBindGBContext {
    uint32 cid;
    SVGAMobId mobid;
    uint32 validContents;
-} SVGA3dCmdBindGBContext;   /* SVGA_3D_CMD_BIND_GB_CONTEXT */
+} __packed
+SVGA3dCmdBindGBContext;   /* SVGA_3D_CMD_BIND_GB_CONTEXT */
 
 /*
  * Readback a guest-backed context.
@@ -2262,7 +2270,8 @@ struct SVGA3dCmdBindGBContext {
 typedef
 struct SVGA3dCmdReadbackGBContext {
    uint32 cid;
-} SVGA3dCmdReadbackGBContext;   /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
+} __packed
+SVGA3dCmdReadbackGBContext;   /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
 
 /*
  * Invalidate a guest-backed context.
@@ -2270,7 +2279,8 @@ struct SVGA3dCmdReadbackGBContext {
 typedef
 struct SVGA3dCmdInvalidateGBContext {
    uint32 cid;
-} SVGA3dCmdInvalidateGBContext;   /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
+} __packed
+SVGA3dCmdInvalidateGBContext;   /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
 
 /*
  * Define a guest-backed shader.
@@ -2281,7 +2291,8 @@ struct SVGA3dCmdDefineGBShader {
    uint32 shid;
    SVGA3dShaderType type;
    uint32 sizeInBytes;
-} SVGA3dCmdDefineGBShader;   /* SVGA_3D_CMD_DEFINE_GB_SHADER */
+} __packed
+SVGA3dCmdDefineGBShader;   /* SVGA_3D_CMD_DEFINE_GB_SHADER */
 
 /*
  * Bind a guest-backed shader.
@@ -2291,7 +2302,8 @@ typedef struct SVGA3dCmdBindGBShader {
    uint32 shid;
    SVGAMobId mobid;
    uint32 offsetInBytes;
-} SVGA3dCmdBindGBShader;   /* SVGA_3D_CMD_BIND_GB_SHADER */
+} __packed
+SVGA3dCmdBindGBShader;   /* SVGA_3D_CMD_BIND_GB_SHADER */
 
 /*
  * Destroy a guest-backed shader.
@@ -2299,7 +2311,8 @@ typedef struct SVGA3dCmdBindGBShader {
 
 typedef struct SVGA3dCmdDestroyGBShader {
    uint32 shid;
-} SVGA3dCmdDestroyGBShader;   /* SVGA_3D_CMD_DESTROY_GB_SHADER */
+} __packed
+SVGA3dCmdDestroyGBShader;   /* SVGA_3D_CMD_DESTROY_GB_SHADER */
 
 typedef
 struct {
@@ -2314,14 +2327,16 @@ struct {
     * Note that FLOAT and INT constants are 4-dwords in length, while
     * BOOL constants are 1-dword in length.
     */
-} SVGA3dCmdSetGBShaderConstInline;
+} __packed
+SVGA3dCmdSetGBShaderConstInline;
 /* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */
 
 typedef
 struct {
    uint32               cid;
    SVGA3dQueryType      type;
-} SVGA3dCmdBeginGBQuery;           /* SVGA_3D_CMD_BEGIN_GB_QUERY */
+} __packed
+SVGA3dCmdBeginGBQuery;           /* SVGA_3D_CMD_BEGIN_GB_QUERY */
 
 typedef
 struct {
@@ -2329,7 +2344,8 @@ struct {
    SVGA3dQueryType      type;
    SVGAMobId mobid;
    uint32 offset;
-} SVGA3dCmdEndGBQuery;                  /* SVGA_3D_CMD_END_GB_QUERY */
+} __packed
+SVGA3dCmdEndGBQuery;                  /* SVGA_3D_CMD_END_GB_QUERY */
 
 
 /*
@@ -2346,21 +2362,22 @@ struct {
    SVGA3dQueryType      type;
    SVGAMobId mobid;
    uint32 offset;
-} SVGA3dCmdWaitForGBQuery;          /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
+} __packed
+SVGA3dCmdWaitForGBQuery;          /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
 
 typedef
 struct {
    SVGAMobId mobid;
    uint32 fbOffset;
    uint32 initalized;
-}
+} __packed
 SVGA3dCmdEnableGart;              /* SVGA_3D_CMD_ENABLE_GART */
 
 typedef
 struct {
    SVGAMobId mobid;
    uint32 gartOffset;
-}
+} __packed
 SVGA3dCmdMapMobIntoGart;          /* SVGA_3D_CMD_MAP_MOB_INTO_GART */
 
 
@@ -2368,7 +2385,7 @@ typedef
 struct {
    uint32 gartOffset;
    uint32 numPages;
-}
+} __packed
 SVGA3dCmdUnmapGartRange;          /* SVGA_3D_CMD_UNMAP_GART_RANGE */
 
 
@@ -2385,27 +2402,27 @@ struct {
    int32 xRoot;
    int32 yRoot;
    uint32 flags;
-}
+} __packed
 SVGA3dCmdDefineGBScreenTarget;    /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */
 
 typedef
 struct {
    uint32 stid;
-}
+} __packed
 SVGA3dCmdDestroyGBScreenTarget;  /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */
 
 typedef
 struct {
    uint32 stid;
    SVGA3dSurfaceImageId image;
-}
+} __packed
 SVGA3dCmdBindGBScreenTarget;  /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */
 
 typedef
 struct {
    uint32 stid;
    SVGA3dBox box;
-}
+} __packed
 SVGA3dCmdUpdateGBScreenTarget;  /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */
 
 /*
index 8369c3ba10fe5119ea09ba713f6bd1e5cb81f9cf..ef3385096145586fa7f148944b518b93e61d2974 100644 (file)
 
 #define DIV_ROUND_UP(x, y)  (((x) + (y) - 1) / (y))
 #define max_t(type, x, y)  ((x) > (y) ? (x) : (y))
+#define min_t(type, x, y)  ((x) < (y) ? (x) : (y))
 #define surf_size_struct SVGA3dSize
 #define u32 uint32
+#define u64 uint64_t
+#define U32_MAX ((u32)~0U)
 
 #endif /* __KERNEL__ */
 
@@ -704,8 +707,8 @@ static const struct svga3d_surface_desc svga3d_surface_descs[] = {
 
 static inline u32 clamped_umul32(u32 a, u32 b)
 {
-       uint64_t tmp = (uint64_t) a*b;
-       return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp;
+       u64 tmp = (u64) a*b;
+       return (tmp > (u64) U32_MAX) ? U32_MAX : tmp;
 }
 
 static inline const struct svga3d_surface_desc *
@@ -834,7 +837,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
                                  bool cubemap)
 {
        const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format);
-       u32 total_size = 0;
+       u64 total_size = 0;
        u32 mip;
 
        for (mip = 0; mip < num_mip_levels; mip++) {
@@ -847,7 +850,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format,
        if (cubemap)
                total_size *= SVGA3D_MAX_SURFACE_FACES;
 
-       return total_size;
+       return (u32) min_t(u64, total_size, (u64) U32_MAX);
 }
 
 
index 71defa4d2d7528a247b8e985a7b14cd1197e2a58..11323dd5196f495e5f2dd24b388c1720f3b6c1ce 100644 (file)
@@ -169,10 +169,17 @@ enum {
    SVGA_REG_TRACES = 45,            /* Enable trace-based updates even when FIFO is on */
    SVGA_REG_GMRS_MAX_PAGES = 46,    /* Maximum number of 4KB pages for all GMRs */
    SVGA_REG_MEMORY_SIZE = 47,       /* Total dedicated device memory excluding FIFO */
+   SVGA_REG_COMMAND_LOW = 48,       /* Lower 32 bits and submits commands */
+   SVGA_REG_COMMAND_HIGH = 49,      /* Upper 32 bits of command buffer PA */
    SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50,   /* Max primary memory */
    SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */
    SVGA_REG_DEV_CAP = 52,           /* Write dev cap index, read value */
-   SVGA_REG_TOP = 53,               /* Must be 1 more than the last register */
+   SVGA_REG_CMD_PREPEND_LOW = 53,
+   SVGA_REG_CMD_PREPEND_HIGH = 54,
+   SVGA_REG_SCREENTARGET_MAX_WIDTH = 55,
+   SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56,
+   SVGA_REG_MOB_MAX_SIZE = 57,
+   SVGA_REG_TOP = 58,               /* Must be 1 more than the last register */
 
    SVGA_PALETTE_BASE = 1024,        /* Base of SVGA color map */
    /* Next 768 (== 256*3) registers exist for colormap */
index 9426c53fb4834cdcb5e4ab98e1912419f9369b5b..1e80152674b50ed62a73e3544c19855de29af070 100644 (file)
@@ -551,8 +551,7 @@ static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind)
        cmd->header.size = sizeof(cmd->body);
        cmd->body.cid = bi->ctx->id;
        cmd->body.type = bi->i1.shader_type;
-       cmd->body.shid =
-               cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+       cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 
        return 0;
@@ -585,8 +584,7 @@ static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi,
        cmd->header.size = sizeof(cmd->body);
        cmd->body.cid = bi->ctx->id;
        cmd->body.type = bi->i1.rt_type;
-       cmd->body.target.sid =
-               cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+       cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
        cmd->body.target.face = 0;
        cmd->body.target.mipmap = 0;
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
@@ -628,8 +626,7 @@ static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi,
        cmd->body.c.cid = bi->ctx->id;
        cmd->body.s1.stage = bi->i1.texture_stage;
        cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
-       cmd->body.s1.value =
-               cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
+       cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID);
        vmw_fifo_commit(dev_priv, sizeof(*cmd));
 
        return 0;
index 3bdc0adc656d002a22e1b95b28c4ba6f3a7d7747..0083cbf99edfd33bdfac9ad819ff4b12b1e7b5d8 100644 (file)
@@ -667,6 +667,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                dev_priv->memory_size = 512*1024*1024;
        }
        dev_priv->max_mob_pages = 0;
+       dev_priv->max_mob_size = 0;
        if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
                uint64_t mem_size =
                        vmw_read(dev_priv,
@@ -676,6 +677,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                dev_priv->prim_bb_mem =
                        vmw_read(dev_priv,
                                 SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM);
+               dev_priv->max_mob_size =
+                       vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE);
        } else
                dev_priv->prim_bb_mem = dev_priv->vram_size;
 
index ecaa302a61546277cf52f787e385b9b233ca6a3c..07831554dad7acc3dae34f36e3a96e7b7f5299af 100644 (file)
@@ -40,7 +40,7 @@
 #include <drm/ttm/ttm_module.h>
 #include "vmwgfx_fence.h"
 
-#define VMWGFX_DRIVER_DATE "20121114"
+#define VMWGFX_DRIVER_DATE "20140228"
 #define VMWGFX_DRIVER_MAJOR 2
 #define VMWGFX_DRIVER_MINOR 5
 #define VMWGFX_DRIVER_PATCHLEVEL 0
@@ -386,6 +386,7 @@ struct vmw_private {
        uint32_t max_gmr_ids;
        uint32_t max_gmr_pages;
        uint32_t max_mob_pages;
+       uint32_t max_mob_size;
        uint32_t memory_size;
        bool has_gmr;
        bool has_mob;
index 269b85cc875aa2108381eea88b70affd5f26757c..efb575a7996c2aed35e7046a47fd61acdbc167a0 100644 (file)
@@ -602,7 +602,7 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv,
 {
        struct vmw_cid_cmd {
                SVGA3dCmdHeader header;
-               __le32 cid;
+               uint32_t cid;
        } *cmd;
 
        cmd = container_of(header, struct vmw_cid_cmd, header);
@@ -1835,7 +1835,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
        return 0;
 }
 
-static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
+static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
        VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,
                    false, false, false),
        VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,
@@ -2032,6 +2032,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
                goto out_invalid;
 
        entry = &vmw_cmd_entries[cmd_id];
+       if (unlikely(!entry->func))
+               goto out_invalid;
+
        if (unlikely(!entry->user_allow && !sw_context->kernel))
                goto out_privileged;
 
@@ -2469,7 +2472,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        if (dev_priv->has_mob) {
                ret = vmw_rebind_contexts(sw_context);
                if (unlikely(ret != 0))
-                       goto out_err;
+                       goto out_unlock_binding;
        }
 
        cmd = vmw_fifo_reserve(dev_priv, command_size);
index f9881f9e62bd401dbb8b25ad63414c0acdc51efb..47b70949bf3af6683bb74552c0b91fa7b06d7a82 100644 (file)
@@ -102,6 +102,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
                vmw_fp->gb_aware = true;
                param->value = dev_priv->max_mob_pages * PAGE_SIZE;
                break;
+       case DRM_VMW_PARAM_MAX_MOB_SIZE:
+               param->value = dev_priv->max_mob_size;
+               break;
        default:
                DRM_ERROR("Illegal vmwgfx get param request: %d\n",
                          param->param);
index d4a5a19cb8c3ca1bd9db9424aad745ecfea5f868..04a64b8cd3cd4f17e00765efe2769e502c4b8240 100644 (file)
@@ -188,18 +188,20 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
 
        bo = otable->page_table->pt_bo;
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
-       if (unlikely(cmd == NULL))
-               DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
-
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
-       cmd->header.size = sizeof(cmd->body);
-       cmd->body.type = type;
-       cmd->body.baseAddress = 0;
-       cmd->body.sizeInBytes = 0;
-       cmd->body.validSizeInBytes = 0;
-       cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
-       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for OTable "
+                         "takedown.\n");
+       } else {
+               memset(cmd, 0, sizeof(*cmd));
+               cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
+               cmd->header.size = sizeof(cmd->body);
+               cmd->body.type = type;
+               cmd->body.baseAddress = 0;
+               cmd->body.sizeInBytes = 0;
+               cmd->body.validSizeInBytes = 0;
+               cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
+               vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       }
 
        if (bo) {
                int ret;
@@ -562,11 +564,12 @@ void vmw_mob_unbind(struct vmw_private *dev_priv,
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Failed reserving FIFO space for Memory "
                          "Object unbinding.\n");
+       } else {
+               cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
+               cmd->header.size = sizeof(cmd->body);
+               cmd->body.mobid = mob->id;
+               vmw_fifo_commit(dev_priv, sizeof(*cmd));
        }
-       cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
-       cmd->header.size = sizeof(cmd->body);
-       cmd->body.mobid = mob->id;
-       vmw_fifo_commit(dev_priv, sizeof(*cmd));
        if (bo) {
                vmw_fence_single_bo(bo, NULL);
                ttm_bo_unreserve(bo);
index 2aa4bc6a4d601578c294c3003b15985de9b28385..9757b57f8388d7a29fa51d04f61f5076fd149793 100644 (file)
@@ -427,8 +427,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
        INIT_LIST_HEAD(&vmw_bo->res_list);
 
        ret = ttm_bo_init(bdev, &vmw_bo->base, size,
-                         (user) ? ttm_bo_type_device :
-                         ttm_bo_type_kernel, placement,
+                         ttm_bo_type_device, placement,
                          0, interruptible,
                          NULL, acc_size, NULL, bo_free);
        return ret;
index 217d941b81766187012b6747ae54752f2825d7e5..ee3856578a12589d8b12e4133666d04134ad729a 100644 (file)
@@ -371,13 +371,13 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
                                         TTM_REF_USAGE);
 }
 
-int vmw_shader_alloc(struct vmw_private *dev_priv,
-                    struct vmw_dma_buffer *buffer,
-                    size_t shader_size,
-                    size_t offset,
-                    SVGA3dShaderType shader_type,
-                    struct ttm_object_file *tfile,
-                    u32 *handle)
+static int vmw_shader_alloc(struct vmw_private *dev_priv,
+                           struct vmw_dma_buffer *buffer,
+                           size_t shader_size,
+                           size_t offset,
+                           SVGA3dShaderType shader_type,
+                           struct ttm_object_file *tfile,
+                           u32 *handle)
 {
        struct vmw_user_shader *ushader;
        struct vmw_resource *res, *tmp;
@@ -779,6 +779,8 @@ vmw_compat_shader_man_create(struct vmw_private *dev_priv)
        int ret;
 
        man = kzalloc(sizeof(*man), GFP_KERNEL);
+       if (man == NULL)
+               return ERR_PTR(-ENOMEM);
 
        man->dev_priv = dev_priv;
        INIT_LIST_HEAD(&man->list);
index 82468d9029156c6588a4480a9c0ed8c0aed82736..e7af580ab977f5932629b8d45e5d5e68a52942a5 100644 (file)
@@ -830,6 +830,24 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        if (unlikely(ret != 0))
                goto out_unlock;
 
+       /*
+        * A gb-aware client referencing a shared surface will
+        * expect a backup buffer to be present.
+        */
+       if (dev_priv->has_mob && req->shareable) {
+               uint32_t backup_handle;
+
+               ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
+                                           res->backup_size,
+                                           true,
+                                           &backup_handle,
+                                           &res->backup);
+               if (unlikely(ret != 0)) {
+                       vmw_resource_unreference(&res);
+                       goto out_unlock;
+               }
+       }
+
        tmp = vmw_resource_reference(&srf->res);
        ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
                                    req->shareable, VMW_RES_SURFACE,
index 1146e3bba6e19bb69cd7f866c149b4aa7202ae46..112f27e51bc7df81b45efcb58f7c11fc46f097e0 100644 (file)
@@ -538,7 +538,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
 
                g->base = job->gather_addr_phys[i];
 
-               for (j = 0; j < job->num_gathers; j++)
+               for (j = i + 1; j < job->num_gathers; j++)
                        if (job->gathers[j].bo == g->bo)
                                job->gathers[j].handled = true;
 
index 497558127bb3e63609af2b5e1f75265f9e7b1423..f822fd2a1adabc4b3e53d86155c2d9e50d3d241e 100644 (file)
@@ -469,6 +469,9 @@ static const struct hid_device_id apple_devices[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                                USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+                               USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS),
+               .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
index 3bfac3accd22fa6dc8a9be7a31cf9fd2814d2443..cc32a6f96c64804d8a1fc936f0fd22244eb51e83 100644 (file)
@@ -1679,6 +1679,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
@@ -1779,6 +1780,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
index 8fae6d1414cca83bc7af2386b7db5dc4cbd3f27b..c24908f14934f4d788263d3a768ae69797913769 100644 (file)
@@ -157,6 +157,7 @@ struct mousevsc_dev {
        u32                     report_desc_size;
        struct hv_input_dev_info hid_dev_info;
        struct hid_device       *hid_device;
+       u8                      input_buf[HID_MAX_BUFFER_SIZE];
 };
 
 
@@ -256,6 +257,7 @@ static void mousevsc_on_receive(struct hv_device *device,
        struct synthhid_msg *hid_msg;
        struct mousevsc_dev *input_dev = hv_get_drvdata(device);
        struct synthhid_input_report *input_report;
+       size_t len;
 
        pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet +
                                                (packet->offset8 << 3));
@@ -300,9 +302,12 @@ static void mousevsc_on_receive(struct hv_device *device,
                        (struct synthhid_input_report *)pipe_msg->data;
                if (!input_dev->init_complete)
                        break;
-               hid_input_report(input_dev->hid_device,
-                               HID_INPUT_REPORT, input_report->buffer,
-                               input_report->header.size, 1);
+
+               len = min(input_report->header.size,
+                         (u32)sizeof(input_dev->input_buf));
+               memcpy(input_dev->input_buf, input_report->buffer, len);
+               hid_input_report(input_dev->hid_device, HID_INPUT_REPORT,
+                                input_dev->input_buf, len, 1);
                break;
        default:
                pr_err("unsupported hid msg type - type %d len %d",
index 5a5248f2cc075b73ca68250866bddbc2b46f9bb1..22f28d6b33a845f0c728b3d4423b6c6fd848ff78 100644 (file)
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS   0x023b
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI  0x0255
 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO   0x0256
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS   0x0257
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI   0x0290
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO    0x0291
 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS    0x0292
 
 #define USB_VENDOR_ID_CYGNAL           0x10c4
 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X      0x818a
+#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH      0x81b9
 
 #define USB_DEVICE_ID_CYGNAL_RADIO_SI4713       0x8244
 
 #define USB_VENDOR_ID_INTEL_1          0x8087
 #define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa
 
+#define USB_VENDOR_ID_STM_0             0x0483
+#define USB_DEVICE_ID_STM_HID_SENSOR    0x91d1
+
 #define USB_VENDOR_ID_ION              0x15e4
 #define USB_DEVICE_ID_ICADE            0x0132
 
 #define USB_DEVICE_ID_MS_PRESENTER_8K_USB      0x0713
 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K      0x0730
 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500    0x076c
+#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
+#define USB_DEVICE_ID_MS_TYPE_COVER_2  0x07a9
 
 #define USB_VENDOR_ID_MOJO             0x8282
 #define USB_DEVICE_ID_RETRO_ADAPTER    0x3201
 
 #define USB_VENDOR_ID_NEXIO            0x1870
 #define USB_DEVICE_ID_NEXIO_MULTITOUCH_420     0x010d
+#define USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750 0x0110
 
 #define USB_VENDOR_ID_NEXTWINDOW       0x1926
 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN   0x0003
index d50e7313b171e4e9bd732cbee40a1a5cd5e501b5..a713e6211419c880ddd0a39597b78f16ad84919a 100644 (file)
@@ -1178,7 +1178,7 @@ static void hidinput_led_worker(struct work_struct *work)
 
        /* fall back to generic raw-output-report */
        len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
-       buf = kmalloc(len, GFP_KERNEL);
+       buf = hid_alloc_report_buf(report, GFP_KERNEL);
        if (!buf)
                return;
 
index befe0e336471b0f36e34473ee97c3ba72759ddf9..24883b4d1a49d40a2bb3462ee36ed094f474b3cd 100644 (file)
@@ -43,6 +43,7 @@
 #define G25_REV_MIN 0x22
 #define G27_REV_MAJ 0x12
 #define G27_REV_MIN 0x38
+#define G27_2_REV_MIN 0x39
 
 #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
 
@@ -130,6 +131,7 @@ static const struct lg4ff_usb_revision lg4ff_revs[] = {
        {DFP_REV_MAJ,  DFP_REV_MIN,  &native_dfp},      /* Driving Force Pro */
        {G25_REV_MAJ,  G25_REV_MIN,  &native_g25},      /* G25 */
        {G27_REV_MAJ,  G27_REV_MIN,  &native_g27},      /* G27 */
+       {G27_REV_MAJ,  G27_2_REV_MIN,  &native_g27},    /* G27 v2 */
 };
 
 /* Recalculates X axis value accordingly to currently selected range */
index c6ef6eed30915e272edf7249001d3005b9e1b667..404a3a8a82f123c40bca4c38ee84a0505aa404f6 100644 (file)
@@ -208,6 +208,10 @@ static const struct hid_device_id ms_devices[] = {
                .driver_data = MS_NOGET },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
                .driver_data = MS_DUPLICATE_USAGES },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2),
+               .driver_data = 0 },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2),
+               .driver_data = 0 },
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
                .driver_data = MS_PRESENTER },
index f134d73beca16b72ddce5716d36e4d7ca949e61d..221d503f1c24fa7b1bbbc0c5871c3cbe742d1a5b 100644 (file)
@@ -1166,6 +1166,11 @@ static const struct hid_device_id mt_devices[] = {
                MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
                        USB_DEVICE_ID_MULTITOUCH_3200) },
 
+       /* FocalTech Panels */
+       { .driver_data = MT_CLS_SERIAL,
+               MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
+                       USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) },
+
        /* GeneralTouch panel */
        { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS,
                MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
index 46f4480035bca14642c43618eb17bfd6729dfb0f..9c22e14c57f079622f297f6d5287919b8c5e2e31 100644 (file)
@@ -665,6 +665,9 @@ static const struct hid_device_id sensor_hub_devices[] = {
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
                        USB_DEVICE_ID_INTEL_HID_SENSOR),
                        .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+       { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
+                       USB_DEVICE_ID_STM_HID_SENSOR),
+                       .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
        { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
                     HID_ANY_ID) },
        { }
index 12354055d4745a4a50e783f624ec8b24bee46dc4..2f19b15f47f2ffca68de731ef0e0ba3ae53c972b 100644 (file)
@@ -42,6 +42,7 @@
 #define DUALSHOCK4_CONTROLLER_BT  BIT(6)
 
 #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER_USB | BUZZ_CONTROLLER | DUALSHOCK4_CONTROLLER_USB)
+#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER_USB | DUALSHOCK4_CONTROLLER_USB)
 
 #define MAX_LEDS 4
 
@@ -499,6 +500,7 @@ struct sony_sc {
        __u8 right;
 #endif
 
+       __u8 worker_initialized;
        __u8 led_state[MAX_LEDS];
        __u8 led_count;
 };
@@ -993,22 +995,11 @@ static int sony_init_ff(struct hid_device *hdev)
        return input_ff_create_memless(input_dev, NULL, sony_play_effect);
 }
 
-static void sony_destroy_ff(struct hid_device *hdev)
-{
-       struct sony_sc *sc = hid_get_drvdata(hdev);
-
-       cancel_work_sync(&sc->state_worker);
-}
-
 #else
 static int sony_init_ff(struct hid_device *hdev)
 {
        return 0;
 }
-
-static void sony_destroy_ff(struct hid_device *hdev)
-{
-}
 #endif
 
 static int sony_set_output_report(struct sony_sc *sc, int req_id, int req_size)
@@ -1077,6 +1068,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
                hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
                ret = sixaxis_set_operational_usb(hdev);
+
+               sc->worker_initialized = 1;
                INIT_WORK(&sc->state_worker, sixaxis_state_worker);
        }
        else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
@@ -1087,6 +1080,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                if (ret < 0)
                        goto err_stop;
 
+               sc->worker_initialized = 1;
                INIT_WORK(&sc->state_worker, dualshock4_state_worker);
        } else {
                ret = 0;
@@ -1101,9 +1095,11 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
                        goto err_stop;
        }
 
-       ret = sony_init_ff(hdev);
-       if (ret < 0)
-               goto err_stop;
+       if (sc->quirks & SONY_FF_SUPPORT) {
+               ret = sony_init_ff(hdev);
+               if (ret < 0)
+                       goto err_stop;
+       }
 
        return 0;
 err_stop:
@@ -1120,7 +1116,8 @@ static void sony_remove(struct hid_device *hdev)
        if (sc->quirks & SONY_LED_SUPPORT)
                sony_leds_remove(hdev);
 
-       sony_destroy_ff(hdev);
+       if (sc->worker_initialized)
+               cancel_work_sync(&sc->state_worker);
 
        hid_hw_stop(hdev);
 }
index cb0137b3718d8cd0a42d6483a9817a26733452c6..ab24ce2eb28f484e30fa0994cd2781994ff7d22d 100644 (file)
@@ -320,13 +320,13 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
                        hid_hw_close(hidraw->hid);
                        wake_up_interruptible(&hidraw->wait);
                }
+               device_destroy(hidraw_class,
+                              MKDEV(hidraw_major, hidraw->minor));
        } else {
                --hidraw->open;
        }
        if (!hidraw->open) {
                if (!hidraw->exist) {
-                       device_destroy(hidraw_class,
-                                       MKDEV(hidraw_major, hidraw->minor));
                        hidraw_table[hidraw->minor] = NULL;
                        kfree(hidraw);
                } else {
index d1f81f52481a40bf7a0521eca0033da057d15641..42eebd14de1f2e41ed932335e729bfb448b7f3f1 100644 (file)
@@ -582,7 +582,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
        int ret;
        int len = i2c_hid_get_report_length(rep) - 2;
 
-       buf = kzalloc(len, GFP_KERNEL);
+       buf = hid_alloc_report_buf(rep, GFP_KERNEL);
        if (!buf)
                return;
 
index 175ec0afb70cff7770fe4460e18e3d1480546cec..dbd83878ff99ec029a1cda07b265ddcd27418710 100644 (file)
@@ -74,6 +74,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
index af6edf9b19365a4938ca16f6a913a08cc6a35fa7..f2d7bf90c9fe5b319d85bf1372a1c0cec36aa91c 100644 (file)
@@ -67,7 +67,6 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
        int ret = 0;
        struct vmbus_channel_initiate_contact *msg;
        unsigned long flags;
-       int t;
 
        init_completion(&msginfo->waitevent);
 
@@ -78,6 +77,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
        msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
        msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
        msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
+       if (version == VERSION_WIN8)
+               msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
 
        /*
         * Add to list before we send the request since we may
@@ -100,15 +101,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
        }
 
        /* Wait for the connection response */
-       t =  wait_for_completion_timeout(&msginfo->waitevent, 5*HZ);
-       if (t == 0) {
-               spin_lock_irqsave(&vmbus_connection.channelmsg_lock,
-                               flags);
-               list_del(&msginfo->msglistentry);
-               spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock,
-                                       flags);
-               return -ETIMEDOUT;
-       }
+       wait_for_completion(&msginfo->waitevent);
 
        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
        list_del(&msginfo->msglistentry);
index a7626358c95df29c2ccb62fa89ed23251acfb979..029b65e6c58914d36061914e35738bda0c1e385c 100644 (file)
@@ -243,7 +243,7 @@ static ssize_t set_temp_min(struct device *dev,
        data->temp_min[index] = clamp_val(temp/1000, -128, 127);
        if (i2c_smbus_write_byte_data(client,
                                        MAX1668_REG_LIML_WR(index),
-                                       data->temp_max[index]))
+                                       data->temp_min[index]))
                count = -EIO;
        mutex_unlock(&data->update_lock);
 
index 8c23203915af3644cd138b13ec99faef572b49b5..8a17f01e8672065d7099e4c3ae156f93705eade4 100644 (file)
@@ -145,7 +145,7 @@ struct ntc_data {
 static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
 {
        struct iio_channel *channel = pdata->chan;
-       unsigned int result;
+       s64 result;
        int val, ret;
 
        ret = iio_read_channel_raw(channel, &val);
@@ -155,10 +155,10 @@ static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata)
        }
 
        /* unit: mV */
-       result = pdata->pullup_uv * val;
+       result = pdata->pullup_uv * (s64) val;
        result >>= 12;
 
-       return result;
+       return (int)result;
 }
 
 static const struct of_device_id ntc_match[] = {
index f5ed03164d86c314942453d244f103d6e9276070..de17c5593d97c1d702563217f0932aa0a0aee6bd 100644 (file)
@@ -387,7 +387,7 @@ config I2C_CBUS_GPIO
 
 config I2C_CPM
        tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
-       depends on (CPM1 || CPM2) && OF_I2C
+       depends on CPM1 || CPM2
        help
          This supports the use of the I2C interface on Freescale
          processors with CPM1 or CPM2.
index be7f0a20d634d1107a7bb3147b32edf0256546ed..f3b89a4698b6192a24d031bab358796e51fbb767 100644 (file)
@@ -39,7 +39,9 @@
 #include <linux/i2c.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <sysdev/fsl_soc.h>
 #include <asm/cpm.h>
index b8c5187b9ee0da912b3a872b828705891a0146a4..d52d84937ad39fee5f81f5a5ec832995cf6d956d 100644 (file)
@@ -97,7 +97,6 @@ enum {
 enum {
        MV64XXX_I2C_ACTION_INVALID,
        MV64XXX_I2C_ACTION_CONTINUE,
-       MV64XXX_I2C_ACTION_OFFLOAD_SEND_START,
        MV64XXX_I2C_ACTION_SEND_START,
        MV64XXX_I2C_ACTION_SEND_RESTART,
        MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
@@ -204,6 +203,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
        unsigned long ctrl_reg;
        struct i2c_msg *msg = drv_data->msgs;
 
+       if (!drv_data->offload_enabled)
+               return -EOPNOTSUPP;
+
        drv_data->msg = msg;
        drv_data->byte_posn = 0;
        drv_data->bytes_left = msg->len;
@@ -433,8 +435,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
 
                drv_data->msgs++;
                drv_data->num_msgs--;
-               if (!(drv_data->offload_enabled &&
-                               mv64xxx_i2c_offload_msg(drv_data))) {
+               if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
                        drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
                        writel(drv_data->cntl_bits,
                        drv_data->reg_base + drv_data->reg_offsets.control);
@@ -458,15 +459,14 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
                        drv_data->reg_base + drv_data->reg_offsets.control);
                break;
 
-       case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START:
-               if (!mv64xxx_i2c_offload_msg(drv_data))
-                       break;
-               else
-                       drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
-               /* FALLTHRU */
        case MV64XXX_I2C_ACTION_SEND_START:
-               writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
-                       drv_data->reg_base + drv_data->reg_offsets.control);
+               /* Can we offload this msg ? */
+               if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
+                       /* No, switch to standard path */
+                       mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+                       writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+                               drv_data->reg_base + drv_data->reg_offsets.control);
+               }
                break;
 
        case MV64XXX_I2C_ACTION_SEND_ADDR_1:
@@ -625,15 +625,10 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
        unsigned long   flags;
 
        spin_lock_irqsave(&drv_data->lock, flags);
-       if (drv_data->offload_enabled) {
-               drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START;
-               drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
-       } else {
-               mv64xxx_i2c_prepare_for_io(drv_data, msg);
 
-               drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
-               drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
-       }
+       drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+       drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+
        drv_data->send_stop = is_last;
        drv_data->block = 1;
        mv64xxx_i2c_do_action(drv_data);
index 3bec9220df04e2a16ade76727dee9851ab1dee7e..bfec313492b3f0de16c8aa26bfb5b77ba9160473 100644 (file)
@@ -447,14 +447,14 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
        { },
 };
 
-#define BMA180_CHANNEL(_index) {                                       \
+#define BMA180_CHANNEL(_axis) {                                        \
        .type = IIO_ACCEL,                                              \
-       .indexed = 1,                                                   \
-       .channel = (_index),                                            \
+       .modified = 1,                                                  \
+       .channel2 = IIO_MOD_##_axis,                                    \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
                BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),       \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
-       .scan_index = (_index),                                         \
+       .scan_index = AXIS_##_axis,                                     \
        .scan_type = {                                                  \
                .sign = 's',                                            \
                .realbits = 14,                                         \
@@ -465,10 +465,10 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = {
 }
 
 static const struct iio_chan_spec bma180_channels[] = {
-       BMA180_CHANNEL(AXIS_X),
-       BMA180_CHANNEL(AXIS_Y),
-       BMA180_CHANNEL(AXIS_Z),
-       IIO_CHAN_SOFT_TIMESTAMP(4),
+       BMA180_CHANNEL(X),
+       BMA180_CHANNEL(Y),
+       BMA180_CHANNEL(Z),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
 static irqreturn_t bma180_trigger_handler(int irq, void *p)
index e283f2f2ee2fb89eadef04aebd198e1e0bc0ea7e..360259266d4f47a70702638c5a08d3d7779dca68 100644 (file)
@@ -1560,7 +1560,7 @@ static int max1363_probe(struct i2c_client *client,
        st->client = client;
 
        st->vref_uv = st->chip_info->int_vref_mv * 1000;
-       vref = devm_regulator_get(&client->dev, "vref");
+       vref = devm_regulator_get_optional(&client->dev, "vref");
        if (!IS_ERR(vref)) {
                int vref_uv;
 
index 41c64a43bcab163a1b08d70ce1433ee1e941b86a..ac2d69e34c8ceb60661c5f3b433d415939e607f9 100644 (file)
@@ -70,7 +70,7 @@ config IIO_ST_GYRO_3AXIS
        select IIO_TRIGGERED_BUFFER if (IIO_BUFFER)
        help
          Say yes here to build support for STMicroelectronics gyroscopes:
-         L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330.
+         L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330.
 
          This driver can also be built as a module. If so, these modules
          will be created:
index f8f2bf84a5a281f9d9cff04eeb4af3d81de6c5be..c197360c450bd8549a980a24941b322df4fca88f 100644 (file)
@@ -19,7 +19,6 @@
 #define LSM330DL_GYRO_DEV_NAME         "lsm330dl_gyro"
 #define LSM330DLC_GYRO_DEV_NAME                "lsm330dlc_gyro"
 #define L3GD20_GYRO_DEV_NAME           "l3gd20"
-#define L3GD20H_GYRO_DEV_NAME          "l3gd20h"
 #define L3G4IS_GYRO_DEV_NAME           "l3g4is_ui"
 #define LSM330_GYRO_DEV_NAME           "lsm330_gyro"
 
index d53d91adfb557b0e575a17030221c6e01b2b7d38..a8e174a47bc409cc22ece45c5a971ca3fe14f37d 100644 (file)
@@ -167,11 +167,10 @@ static const struct st_sensors st_gyro_sensors[] = {
                .wai = ST_GYRO_2_WAI_EXP,
                .sensors_supported = {
                        [0] = L3GD20_GYRO_DEV_NAME,
-                       [1] = L3GD20H_GYRO_DEV_NAME,
-                       [2] = LSM330D_GYRO_DEV_NAME,
-                       [3] = LSM330DLC_GYRO_DEV_NAME,
-                       [4] = L3G4IS_GYRO_DEV_NAME,
-                       [5] = LSM330_GYRO_DEV_NAME,
+                       [1] = LSM330D_GYRO_DEV_NAME,
+                       [2] = LSM330DLC_GYRO_DEV_NAME,
+                       [3] = L3G4IS_GYRO_DEV_NAME,
+                       [4] = LSM330_GYRO_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
                .odr = {
index 16b8b8d70bf127973b43f819999c3876f7a8683d..23c12f361b05b13f37430df0958f02a406b8812d 100644 (file)
@@ -55,7 +55,6 @@ static const struct i2c_device_id st_gyro_id_table[] = {
        { LSM330DL_GYRO_DEV_NAME },
        { LSM330DLC_GYRO_DEV_NAME },
        { L3GD20_GYRO_DEV_NAME },
-       { L3GD20H_GYRO_DEV_NAME },
        { L3G4IS_GYRO_DEV_NAME },
        { LSM330_GYRO_DEV_NAME },
        {},
index 94763e25caf999c22f2237fa3a5783d063512173..b4ad3be2668768e7a4ef35979478ed033933007f 100644 (file)
@@ -54,7 +54,6 @@ static const struct spi_device_id st_gyro_id_table[] = {
        { LSM330DL_GYRO_DEV_NAME },
        { LSM330DLC_GYRO_DEV_NAME },
        { L3GD20_GYRO_DEV_NAME },
-       { L3GD20H_GYRO_DEV_NAME },
        { L3G4IS_GYRO_DEV_NAME },
        { LSM330_GYRO_DEV_NAME },
        {},
index 2f8f9d632386b34b2ad6f6a776277fc65fc3acf4..0916bf6b6c311c503931f26387712c6677b17645 100644 (file)
@@ -189,6 +189,7 @@ enum {
        ADIS16300_SCAN_INCLI_X,
        ADIS16300_SCAN_INCLI_Y,
        ADIS16400_SCAN_ADC,
+       ADIS16400_SCAN_TIMESTAMP,
 };
 
 #ifdef CONFIG_IIO_BUFFER
index 368660dfe135a51c3cac05dd90d7dcb75dacb7c2..7c582f7ae34e15885dc075515de60a2a81be30b3 100644 (file)
@@ -632,7 +632,7 @@ static const struct iio_chan_spec adis16400_channels[] = {
        ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14),
        ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12),
        ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12),
-       IIO_CHAN_SOFT_TIMESTAMP(12)
+       IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
 static const struct iio_chan_spec adis16448_channels[] = {
@@ -659,7 +659,7 @@ static const struct iio_chan_spec adis16448_channels[] = {
                },
        },
        ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12),
-       IIO_CHAN_SOFT_TIMESTAMP(11)
+       IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
 static const struct iio_chan_spec adis16350_channels[] = {
@@ -677,7 +677,7 @@ static const struct iio_chan_spec adis16350_channels[] = {
        ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12),
        ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12),
        ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12),
-       IIO_CHAN_SOFT_TIMESTAMP(11)
+       IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
 static const struct iio_chan_spec adis16300_channels[] = {
@@ -690,7 +690,7 @@ static const struct iio_chan_spec adis16300_channels[] = {
        ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12),
        ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13),
        ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13),
-       IIO_CHAN_SOFT_TIMESTAMP(14)
+       IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
 static const struct iio_chan_spec adis16334_channels[] = {
@@ -701,7 +701,7 @@ static const struct iio_chan_spec adis16334_channels[] = {
        ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14),
        ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14),
        ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12),
-       IIO_CHAN_SOFT_TIMESTAMP(8)
+       IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP),
 };
 
 static struct attribute *adis16400_attributes[] = {
index f17b4e6183c6bae6f36ee8acfaac897f76dfd8d9..47a6dbac2d0ca8b23dcea31158b43d3c3df3d2f0 100644 (file)
@@ -103,13 +103,13 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
 /**
  *  cm32181_read_als_it() - Get sensor integration time (ms)
  *  @cm32181:  pointer of struct cm32181
- *  @val     pointer of int to load the als_it value.
+ *  @val2:     pointer of int to load the als_it value.
  *
  *  Report the current integartion time by millisecond.
  *
- *  Return: IIO_VAL_INT for success, otherwise -EINVAL.
+ *  Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
  */
-static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
+static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
 {
        u16 als_it;
        int i;
@@ -119,8 +119,8 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
        als_it >>= CM32181_CMD_ALS_IT_SHIFT;
        for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
                if (als_it == als_it_bits[i]) {
-                       *val = als_it_value[i];
-                       return IIO_VAL_INT;
+                       *val2 = als_it_value[i];
+                       return IIO_VAL_INT_PLUS_MICRO;
                }
        }
 
@@ -221,7 +221,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
                *val = cm32181->calibscale;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = cm32181_read_als_it(cm32181, val);
+               ret = cm32181_read_als_it(cm32181, val2);
                return ret;
        }
 
@@ -240,7 +240,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
                cm32181->calibscale = val;
                return val;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = cm32181_write_als_it(cm32181, val);
+               ret = cm32181_write_als_it(cm32181, val2);
                return ret;
        }
 
@@ -264,7 +264,7 @@ static ssize_t cm32181_get_it_available(struct device *dev,
 
        n = ARRAY_SIZE(als_it_value);
        for (i = 0, len = 0; i < n; i++)
-               len += sprintf(buf + len, "%d ", als_it_value[i]);
+               len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
        return len + sprintf(buf + len, "\n");
 }
 
index 0a142af83e25dbb112809f04a048fd581f9a7d96..a45e07492db318a22171546291d2b590e0d0668f 100644 (file)
 #define CM36651_CS_CONF2_DEFAULT_BIT   0x08
 
 /* CS_CONF3 channel integration time */
-#define CM36651_CS_IT1                 0x00 /* Integration time 80000 usec */
-#define CM36651_CS_IT2                 0x40 /* Integration time 160000 usec */
-#define CM36651_CS_IT3                 0x80 /* Integration time 320000 usec */
-#define CM36651_CS_IT4                 0xC0 /* Integration time 640000 usec */
+#define CM36651_CS_IT1                 0x00 /* Integration time 80 msec */
+#define CM36651_CS_IT2                 0x40 /* Integration time 160 msec */
+#define CM36651_CS_IT3                 0x80 /* Integration time 320 msec */
+#define CM36651_CS_IT4                 0xC0 /* Integration time 640 msec */
 
 /* PS_CONF1 command code */
 #define CM36651_PS_ENABLE              0x00
 #define CM36651_PS_PERS4               0x0C
 
 /* PS_CONF1 command code: integration time */
-#define CM36651_PS_IT1                 0x00 /* Integration time 320 usec */
-#define CM36651_PS_IT2                 0x10 /* Integration time 420 usec */
-#define CM36651_PS_IT3                 0x20 /* Integration time 520 usec */
-#define CM36651_PS_IT4                 0x30 /* Integration time 640 usec */
+#define CM36651_PS_IT1                 0x00 /* Integration time 0.32 msec */
+#define CM36651_PS_IT2                 0x10 /* Integration time 0.42 msec */
+#define CM36651_PS_IT3                 0x20 /* Integration time 0.52 msec */
+#define CM36651_PS_IT4                 0x30 /* Integration time 0.64 msec */
 
 /* PS_CONF1 command code: duty ratio */
 #define CM36651_PS_DR1                 0x00 /* Duty ratio 1/80 */
@@ -93,8 +93,8 @@
 #define CM36651_CLOSE_PROXIMITY                0x32
 #define CM36651_FAR_PROXIMITY                  0x33
 
-#define CM36651_CS_INT_TIME_AVAIL      "80000 160000 320000 640000"
-#define CM36651_PS_INT_TIME_AVAIL      "320 420 520 640"
+#define CM36651_CS_INT_TIME_AVAIL      "0.08 0.16 0.32 0.64"
+#define CM36651_PS_INT_TIME_AVAIL      "0.000320 0.000420 0.000520 0.000640"
 
 enum cm36651_operation_mode {
        CM36651_LIGHT_EN,
@@ -356,30 +356,30 @@ static int cm36651_read_channel(struct cm36651_data *cm36651,
 }
 
 static int cm36651_read_int_time(struct cm36651_data *cm36651,
-                               struct iio_chan_spec const *chan, int *val)
+                               struct iio_chan_spec const *chan, int *val2)
 {
        switch (chan->type) {
        case IIO_LIGHT:
                if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
-                       *val = 80000;
+                       *val2 = 80000;
                else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
-                       *val = 160000;
+                       *val2 = 160000;
                else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
-                       *val = 320000;
+                       *val2 = 320000;
                else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
-                       *val = 640000;
+                       *val2 = 640000;
                else
                        return -EINVAL;
                break;
        case IIO_PROXIMITY:
                if (cm36651->ps_int_time == CM36651_PS_IT1)
-                       *val = 320;
+                       *val2 = 320;
                else if (cm36651->ps_int_time == CM36651_PS_IT2)
-                       *val = 420;
+                       *val2 = 420;
                else if (cm36651->ps_int_time == CM36651_PS_IT3)
-                       *val = 520;
+                       *val2 = 520;
                else if (cm36651->ps_int_time == CM36651_PS_IT4)
-                       *val = 640;
+                       *val2 = 640;
                else
                        return -EINVAL;
                break;
@@ -387,7 +387,7 @@ static int cm36651_read_int_time(struct cm36651_data *cm36651,
                return -EINVAL;
        }
 
-       return IIO_VAL_INT;
+       return IIO_VAL_INT_PLUS_MICRO;
 }
 
 static int cm36651_write_int_time(struct cm36651_data *cm36651,
@@ -459,7 +459,8 @@ static int cm36651_read_raw(struct iio_dev *indio_dev,
                ret = cm36651_read_channel(cm36651, chan, val);
                break;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = cm36651_read_int_time(cm36651, chan, val);
+               *val = 0;
+               ret = cm36651_read_int_time(cm36651, chan, val2);
                break;
        default:
                ret = -EINVAL;
@@ -479,7 +480,7 @@ static int cm36651_write_raw(struct iio_dev *indio_dev,
        int ret = -EINVAL;
 
        if (mask == IIO_CHAN_INFO_INT_TIME) {
-               ret = cm36651_write_int_time(cm36651, chan, val);
+               ret = cm36651_write_int_time(cm36651, chan, val2);
                if (ret < 0)
                        dev_err(&client->dev, "Integration time write failed\n");
        }
index 3d8110157f2d4b33557be5415504ca81b992cf4d..94daa9fc12478b868dbe73a5cdce7a767bdc34a3 100644 (file)
@@ -460,10 +460,14 @@ static int tsl2563_write_raw(struct iio_dev *indio_dev,
 {
        struct tsl2563_chip *chip = iio_priv(indio_dev);
 
-       if (chan->channel == IIO_MOD_LIGHT_BOTH)
+       if (mask != IIO_CHAN_INFO_CALIBSCALE)
+               return -EINVAL;
+       if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
                chip->calib0 = calib_from_sysfs(val);
-       else
+       else if (chan->channel2 == IIO_MOD_LIGHT_IR)
                chip->calib1 = calib_from_sysfs(val);
+       else
+               return -EINVAL;
 
        return 0;
 }
@@ -472,14 +476,14 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int *val,
                            int *val2,
-                           long m)
+                           long mask)
 {
        int ret = -EINVAL;
        u32 calib0, calib1;
        struct tsl2563_chip *chip = iio_priv(indio_dev);
 
        mutex_lock(&chip->lock);
-       switch (m) {
+       switch (mask) {
        case IIO_CHAN_INFO_RAW:
        case IIO_CHAN_INFO_PROCESSED:
                switch (chan->type) {
@@ -498,7 +502,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
                        ret = tsl2563_get_adc(chip);
                        if (ret)
                                goto error_ret;
-                       if (chan->channel == 0)
+                       if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
                                *val = chip->data0;
                        else
                                *val = chip->data1;
@@ -510,7 +514,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
                break;
 
        case IIO_CHAN_INFO_CALIBSCALE:
-               if (chan->channel == 0)
+               if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
                        *val = calib_to_sysfs(chip->calib0);
                else
                        *val = calib_to_sysfs(chip->calib1);
index ff284e5afd9587c4e8a14bc9633b018098ce983c..05423543f89d7896ba1a6f086b409955c35417fa 100644 (file)
@@ -85,6 +85,7 @@
 #define AK8975_MAX_CONVERSION_TIMEOUT  500
 #define AK8975_CONVERSION_DONE_POLL_TIME 10
 #define AK8975_DATA_READY_TIMEOUT      ((100*HZ)/1000)
+#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256)
 
 /*
  * Per-instance context data for the device.
@@ -265,15 +266,15 @@ static int ak8975_setup(struct i2c_client *client)
  *
  * Since 1uT = 0.01 gauss, our final scale factor becomes:
  *
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 100
- * Hadj = H * ((ASA + 128) * 30 / 256
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
  *
  * Since ASA doesn't change, we cache the resultant scale factor into the
  * device context in ak8975_setup().
  */
-       data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8;
-       data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8;
-       data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8;
+       data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]);
+       data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]);
+       data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]);
 
        return 0;
 }
@@ -428,8 +429,9 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_RAW:
                return ak8975_read_axis(indio_dev, chan->address, val);
        case IIO_CHAN_INFO_SCALE:
-               *val = data->raw_to_gauss[chan->address];
-               return IIO_VAL_INT;
+               *val = 0;
+               *val2 = data->raw_to_gauss[chan->address];
+               return IIO_VAL_INT_PLUS_MICRO;
        }
        return -EINVAL;
 }
index 4b65b6d3bdb17696027f58c34887befaaa209671..f66955fb3509e261f3a0d0cf7028f6178b3cb1a2 100644 (file)
@@ -106,7 +106,7 @@ static ssize_t mag3110_show_int_plus_micros(char *buf,
 
        while (n-- > 0)
                len += scnprintf(buf + len, PAGE_SIZE - len,
-                       "%d.%d ", vals[n][0], vals[n][1]);
+                       "%d.%06d ", vals[n][0], vals[n][1]);
 
        /* replace trailing space by newline */
        buf[len - 1] = '\n';
@@ -154,6 +154,9 @@ static int mag3110_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+               if (iio_buffer_enabled(indio_dev))
+                       return -EBUSY;
+
                switch (chan->type) {
                case IIO_MAGN: /* in 0.1 uT / LSB */
                        ret = mag3110_read(data, buffer);
@@ -199,6 +202,9 @@ static int mag3110_write_raw(struct iio_dev *indio_dev,
        struct mag3110_data *data = iio_priv(indio_dev);
        int rate;
 
+       if (iio_buffer_enabled(indio_dev))
+               return -EBUSY;
+
        switch (mask) {
        case IIO_CHAN_INFO_SAMP_FREQ:
                rate = mag3110_get_samp_freq_index(data, val, val2);
index d53cf519f42a4267bcfecf487343150eed1cc7f9..00400c352c1a9ec33e7c291bcb997049686816c5 100644 (file)
@@ -1082,6 +1082,7 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
 
        /* Initialize network device */
        if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) {
+               ret = -ENOMEM;
                iounmap(mmio_regs);
                goto bail4;
        }
@@ -1151,7 +1152,8 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
                goto bail10;
        }
 
-       if (c2_register_device(c2dev))
+       ret = c2_register_device(c2dev);
+       if (ret)
                goto bail10;
 
        return 0;
index b7c986990053da3f379bd013e7ed9a3bf1d893db..d2a6d961344b7e6f32855fad7b176149964bd43e 100644 (file)
@@ -576,7 +576,8 @@ int c2_rnic_init(struct c2_dev *c2dev)
                goto bail4;
 
        /* Initialize cached the adapter limits */
-       if (c2_rnic_query(c2dev, &c2dev->props))
+       err = c2_rnic_query(c2dev, &c2dev->props);
+       if (err)
                goto bail5;
 
        /* Initialize the PD pool */
index 45126879ad28a2149351232a1f9c4a2551f06c09..7e98a58aacfd68f6d8af350b2483e225409df55c 100644 (file)
@@ -1647,6 +1647,15 @@ static inline int act_open_has_tid(int status)
               status != CPL_ERR_ARP_MISS;
 }
 
+/* Returns whether a CPL status conveys negative advice.
+ */
+static int is_neg_adv(unsigned int status)
+{
+       return status == CPL_ERR_RTX_NEG_ADVICE ||
+              status == CPL_ERR_PERSIST_NEG_ADVICE ||
+              status == CPL_ERR_KEEPALV_NEG_ADVICE;
+}
+
 #define ACT_OPEN_RETRY_COUNT 2
 
 static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
@@ -1835,7 +1844,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
        PDBG("%s ep %p atid %u status %u errno %d\n", __func__, ep, atid,
             status, status2errno(status));
 
-       if (status == CPL_ERR_RTX_NEG_ADVICE) {
+       if (is_neg_adv(status)) {
                printk(KERN_WARNING MOD "Connection problems for atid %u\n",
                        atid);
                return 0;
@@ -2265,15 +2274,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
        return 0;
 }
 
-/*
- * Returns whether an ABORT_REQ_RSS message is a negative advice.
- */
-static int is_neg_adv_abort(unsigned int status)
-{
-       return status == CPL_ERR_RTX_NEG_ADVICE ||
-              status == CPL_ERR_PERSIST_NEG_ADVICE;
-}
-
 static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
 {
        struct cpl_abort_req_rss *req = cplhdr(skb);
@@ -2287,7 +2287,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
        unsigned int tid = GET_TID(req);
 
        ep = lookup_tid(t, tid);
-       if (is_neg_adv_abort(req->status)) {
+       if (is_neg_adv(req->status)) {
                PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
                     ep->hwtid);
                return 0;
@@ -3352,6 +3352,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
                goto free_dst;
        }
 
+       neigh_release(neigh);
        step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan;
        rss_qid = dev->rdev.lldi.rxq_ids[pi->port_id * step];
        window = (__force u16) htons((__force u16)tcph->window);
@@ -3569,7 +3570,7 @@ static int peer_abort_intr(struct c4iw_dev *dev, struct sk_buff *skb)
                kfree_skb(skb);
                return 0;
        }
-       if (is_neg_adv_abort(req->status)) {
+       if (is_neg_adv(req->status)) {
                PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,
                     ep->hwtid);
                kfree_skb(skb);
index 4a033853312e52c6ff026d8e7e7892f010826255..ba7335fd4ebfca7db505585ac7fbee792fd4d67e 100644 (file)
@@ -64,6 +64,10 @@ struct uld_ctx {
 static LIST_HEAD(uld_ctx_list);
 static DEFINE_MUTEX(dev_mutex);
 
+#define DB_FC_RESUME_SIZE 64
+#define DB_FC_RESUME_DELAY 1
+#define DB_FC_DRAIN_THRESH 0
+
 static struct dentry *c4iw_debugfs_root;
 
 struct c4iw_debugfs_data {
@@ -282,7 +286,7 @@ static const struct file_operations stag_debugfs_fops = {
        .llseek  = default_llseek,
 };
 
-static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"};
+static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY", "STOPPED"};
 
 static int stats_show(struct seq_file *seq, void *v)
 {
@@ -311,9 +315,10 @@ static int stats_show(struct seq_file *seq, void *v)
        seq_printf(seq, "  DB FULL: %10llu\n", dev->rdev.stats.db_full);
        seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty);
        seq_printf(seq, "  DB DROP: %10llu\n", dev->rdev.stats.db_drop);
-       seq_printf(seq, " DB State: %s Transitions %llu\n",
+       seq_printf(seq, " DB State: %s Transitions %llu FC Interruptions %llu\n",
                   db_state_str[dev->db_state],
-                  dev->rdev.stats.db_state_transitions);
+                  dev->rdev.stats.db_state_transitions,
+                  dev->rdev.stats.db_fc_interruptions);
        seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
        seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n",
                   dev->rdev.stats.act_ofld_conn_fails);
@@ -643,6 +648,12 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
                printk(KERN_ERR MOD "error %d initializing ocqp pool\n", err);
                goto err4;
        }
+       rdev->status_page = (struct t4_dev_status_page *)
+                           __get_free_page(GFP_KERNEL);
+       if (!rdev->status_page) {
+               pr_err(MOD "error allocating status page\n");
+               goto err4;
+       }
        return 0;
 err4:
        c4iw_rqtpool_destroy(rdev);
@@ -656,6 +667,7 @@ err1:
 
 static void c4iw_rdev_close(struct c4iw_rdev *rdev)
 {
+       free_page((unsigned long)rdev->status_page);
        c4iw_pblpool_destroy(rdev);
        c4iw_rqtpool_destroy(rdev);
        c4iw_destroy_resource(&rdev->resource);
@@ -703,18 +715,6 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
                pr_info("%s: On-Chip Queues not supported on this device.\n",
                        pci_name(infop->pdev));
 
-       if (!is_t4(infop->adapter_type)) {
-               if (!allow_db_fc_on_t5) {
-                       db_fc_threshold = 100000;
-                       pr_info("DB Flow Control Disabled.\n");
-               }
-
-               if (!allow_db_coalescing_on_t5) {
-                       db_coalescing_threshold = -1;
-                       pr_info("DB Coalescing Disabled.\n");
-               }
-       }
-
        devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
        if (!devp) {
                printk(KERN_ERR MOD "Cannot allocate ib device\n");
@@ -749,6 +749,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
        spin_lock_init(&devp->lock);
        mutex_init(&devp->rdev.stats.lock);
        mutex_init(&devp->db_mutex);
+       INIT_LIST_HEAD(&devp->db_fc_list);
 
        if (c4iw_debugfs_root) {
                devp->debugfs_root = debugfs_create_dir(
@@ -977,13 +978,16 @@ static int disable_qp_db(int id, void *p, void *data)
 
 static void stop_queues(struct uld_ctx *ctx)
 {
-       spin_lock_irq(&ctx->dev->lock);
-       if (ctx->dev->db_state == NORMAL) {
-               ctx->dev->rdev.stats.db_state_transitions++;
-               ctx->dev->db_state = FLOW_CONTROL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->dev->lock, flags);
+       ctx->dev->rdev.stats.db_state_transitions++;
+       ctx->dev->db_state = STOPPED;
+       if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED)
                idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
-       }
-       spin_unlock_irq(&ctx->dev->lock);
+       else
+               ctx->dev->rdev.status_page->db_off = 1;
+       spin_unlock_irqrestore(&ctx->dev->lock, flags);
 }
 
 static int enable_qp_db(int id, void *p, void *data)
@@ -994,15 +998,70 @@ static int enable_qp_db(int id, void *p, void *data)
        return 0;
 }
 
+static void resume_rc_qp(struct c4iw_qp *qp)
+{
+       spin_lock(&qp->lock);
+       t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc);
+       qp->wq.sq.wq_pidx_inc = 0;
+       t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc);
+       qp->wq.rq.wq_pidx_inc = 0;
+       spin_unlock(&qp->lock);
+}
+
+static void resume_a_chunk(struct uld_ctx *ctx)
+{
+       int i;
+       struct c4iw_qp *qp;
+
+       for (i = 0; i < DB_FC_RESUME_SIZE; i++) {
+               qp = list_first_entry(&ctx->dev->db_fc_list, struct c4iw_qp,
+                                     db_fc_entry);
+               list_del_init(&qp->db_fc_entry);
+               resume_rc_qp(qp);
+               if (list_empty(&ctx->dev->db_fc_list))
+                       break;
+       }
+}
+
 static void resume_queues(struct uld_ctx *ctx)
 {
        spin_lock_irq(&ctx->dev->lock);
-       if (ctx->dev->qpcnt <= db_fc_threshold &&
-           ctx->dev->db_state == FLOW_CONTROL) {
-               ctx->dev->db_state = NORMAL;
-               ctx->dev->rdev.stats.db_state_transitions++;
-               idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
+       if (ctx->dev->db_state != STOPPED)
+               goto out;
+       ctx->dev->db_state = FLOW_CONTROL;
+       while (1) {
+               if (list_empty(&ctx->dev->db_fc_list)) {
+                       WARN_ON(ctx->dev->db_state != FLOW_CONTROL);
+                       ctx->dev->db_state = NORMAL;
+                       ctx->dev->rdev.stats.db_state_transitions++;
+                       if (ctx->dev->rdev.flags & T4_STATUS_PAGE_DISABLED) {
+                               idr_for_each(&ctx->dev->qpidr, enable_qp_db,
+                                            NULL);
+                       } else {
+                               ctx->dev->rdev.status_page->db_off = 0;
+                       }
+                       break;
+               } else {
+                       if (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1)
+                           < (ctx->dev->rdev.lldi.dbfifo_int_thresh <<
+                              DB_FC_DRAIN_THRESH)) {
+                               resume_a_chunk(ctx);
+                       }
+                       if (!list_empty(&ctx->dev->db_fc_list)) {
+                               spin_unlock_irq(&ctx->dev->lock);
+                               if (DB_FC_RESUME_DELAY) {
+                                       set_current_state(TASK_UNINTERRUPTIBLE);
+                                       schedule_timeout(DB_FC_RESUME_DELAY);
+                               }
+                               spin_lock_irq(&ctx->dev->lock);
+                               if (ctx->dev->db_state != FLOW_CONTROL)
+                                       break;
+                       }
+               }
        }
+out:
+       if (ctx->dev->db_state != NORMAL)
+               ctx->dev->rdev.stats.db_fc_interruptions++;
        spin_unlock_irq(&ctx->dev->lock);
 }
 
@@ -1028,12 +1087,12 @@ static int count_qps(int id, void *p, void *data)
        return 0;
 }
 
-static void deref_qps(struct qp_list qp_list)
+static void deref_qps(struct qp_list *qp_list)
 {
        int idx;
 
-       for (idx = 0; idx < qp_list.idx; idx++)
-               c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp);
+       for (idx = 0; idx < qp_list->idx; idx++)
+               c4iw_qp_rem_ref(&qp_list->qps[idx]->ibqp);
 }
 
 static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
@@ -1044,17 +1103,22 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
        for (idx = 0; idx < qp_list->idx; idx++) {
                struct c4iw_qp *qp = qp_list->qps[idx];
 
+               spin_lock_irq(&qp->rhp->lock);
+               spin_lock(&qp->lock);
                ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
                                          qp->wq.sq.qid,
                                          t4_sq_host_wq_pidx(&qp->wq),
                                          t4_sq_wq_size(&qp->wq));
                if (ret) {
-                       printk(KERN_ERR MOD "%s: Fatal error - "
+                       pr_err(KERN_ERR MOD "%s: Fatal error - "
                               "DB overflow recovery failed - "
                               "error syncing SQ qid %u\n",
                               pci_name(ctx->lldi.pdev), qp->wq.sq.qid);
+                       spin_unlock(&qp->lock);
+                       spin_unlock_irq(&qp->rhp->lock);
                        return;
                }
+               qp->wq.sq.wq_pidx_inc = 0;
 
                ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],
                                          qp->wq.rq.qid,
@@ -1062,12 +1126,17 @@ static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)
                                          t4_rq_wq_size(&qp->wq));
 
                if (ret) {
-                       printk(KERN_ERR MOD "%s: Fatal error - "
+                       pr_err(KERN_ERR MOD "%s: Fatal error - "
                               "DB overflow recovery failed - "
                               "error syncing RQ qid %u\n",
                               pci_name(ctx->lldi.pdev), qp->wq.rq.qid);
+                       spin_unlock(&qp->lock);
+                       spin_unlock_irq(&qp->rhp->lock);
                        return;
                }
+               qp->wq.rq.wq_pidx_inc = 0;
+               spin_unlock(&qp->lock);
+               spin_unlock_irq(&qp->rhp->lock);
 
                /* Wait for the dbfifo to drain */
                while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) {
@@ -1083,36 +1152,22 @@ static void recover_queues(struct uld_ctx *ctx)
        struct qp_list qp_list;
        int ret;
 
-       /* lock out kernel db ringers */
-       mutex_lock(&ctx->dev->db_mutex);
-
-       /* put all queues in to recovery mode */
-       spin_lock_irq(&ctx->dev->lock);
-       ctx->dev->db_state = RECOVERY;
-       ctx->dev->rdev.stats.db_state_transitions++;
-       idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);
-       spin_unlock_irq(&ctx->dev->lock);
-
        /* slow everybody down */
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule_timeout(usecs_to_jiffies(1000));
 
-       /* Wait for the dbfifo to completely drain. */
-       while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(usecs_to_jiffies(10));
-       }
-
        /* flush the SGE contexts */
        ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]);
        if (ret) {
                printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
                       pci_name(ctx->lldi.pdev));
-               goto out;
+               return;
        }
 
        /* Count active queues so we can build a list of queues to recover */
        spin_lock_irq(&ctx->dev->lock);
+       WARN_ON(ctx->dev->db_state != STOPPED);
+       ctx->dev->db_state = RECOVERY;
        idr_for_each(&ctx->dev->qpidr, count_qps, &count);
 
        qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC);
@@ -1120,7 +1175,7 @@ static void recover_queues(struct uld_ctx *ctx)
                printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",
                       pci_name(ctx->lldi.pdev));
                spin_unlock_irq(&ctx->dev->lock);
-               goto out;
+               return;
        }
        qp_list.idx = 0;
 
@@ -1133,29 +1188,13 @@ static void recover_queues(struct uld_ctx *ctx)
        recover_lost_dbs(ctx, &qp_list);
 
        /* we're almost done!  deref the qps and clean up */
-       deref_qps(qp_list);
+       deref_qps(&qp_list);
        kfree(qp_list.qps);
 
-       /* Wait for the dbfifo to completely drain again */
-       while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(usecs_to_jiffies(10));
-       }
-
-       /* resume the queues */
        spin_lock_irq(&ctx->dev->lock);
-       if (ctx->dev->qpcnt > db_fc_threshold)
-               ctx->dev->db_state = FLOW_CONTROL;
-       else {
-               ctx->dev->db_state = NORMAL;
-               idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);
-       }
-       ctx->dev->rdev.stats.db_state_transitions++;
+       WARN_ON(ctx->dev->db_state != RECOVERY);
+       ctx->dev->db_state = STOPPED;
        spin_unlock_irq(&ctx->dev->lock);
-
-out:
-       /* start up kernel db ringers again */
-       mutex_unlock(&ctx->dev->db_mutex);
 }
 
 static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
@@ -1165,9 +1204,7 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
        switch (control) {
        case CXGB4_CONTROL_DB_FULL:
                stop_queues(ctx);
-               mutex_lock(&ctx->dev->rdev.stats.lock);
                ctx->dev->rdev.stats.db_full++;
-               mutex_unlock(&ctx->dev->rdev.stats.lock);
                break;
        case CXGB4_CONTROL_DB_EMPTY:
                resume_queues(ctx);
index 23eaeabab93b50d483e279de2adb7175c7c29dfc..eb18f9be35e4f84ffb64d4d8e24d6fbba1dd087d 100644 (file)
@@ -109,6 +109,7 @@ struct c4iw_dev_ucontext {
 
 enum c4iw_rdev_flags {
        T4_FATAL_ERROR = (1<<0),
+       T4_STATUS_PAGE_DISABLED = (1<<1),
 };
 
 struct c4iw_stat {
@@ -130,6 +131,7 @@ struct c4iw_stats {
        u64  db_empty;
        u64  db_drop;
        u64  db_state_transitions;
+       u64  db_fc_interruptions;
        u64  tcam_full;
        u64  act_ofld_conn_fails;
        u64  pas_ofld_conn_fails;
@@ -150,6 +152,7 @@ struct c4iw_rdev {
        unsigned long oc_mw_pa;
        void __iomem *oc_mw_kva;
        struct c4iw_stats stats;
+       struct t4_dev_status_page *status_page;
 };
 
 static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
@@ -211,7 +214,8 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
 enum db_state {
        NORMAL = 0,
        FLOW_CONTROL = 1,
-       RECOVERY = 2
+       RECOVERY = 2,
+       STOPPED = 3
 };
 
 struct c4iw_dev {
@@ -225,10 +229,10 @@ struct c4iw_dev {
        struct mutex db_mutex;
        struct dentry *debugfs_root;
        enum db_state db_state;
-       int qpcnt;
        struct idr hwtid_idr;
        struct idr atid_idr;
        struct idr stid_idr;
+       struct list_head db_fc_list;
 };
 
 static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
@@ -432,6 +436,7 @@ struct c4iw_qp_attributes {
 
 struct c4iw_qp {
        struct ib_qp ibqp;
+       struct list_head db_fc_entry;
        struct c4iw_dev *rhp;
        struct c4iw_ep *ep;
        struct c4iw_qp_attributes attr;
index 7e94c9a656a1429d37c14bd2e7b8f4b8590d494e..79429256023a7e2e7be7f83e7f1b305233f5348a 100644 (file)
@@ -106,15 +106,56 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev,
 {
        struct c4iw_ucontext *context;
        struct c4iw_dev *rhp = to_c4iw_dev(ibdev);
+       static int warned;
+       struct c4iw_alloc_ucontext_resp uresp;
+       int ret = 0;
+       struct c4iw_mm_entry *mm = NULL;
 
        PDBG("%s ibdev %p\n", __func__, ibdev);
        context = kzalloc(sizeof(*context), GFP_KERNEL);
-       if (!context)
-               return ERR_PTR(-ENOMEM);
+       if (!context) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
        c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx);
        INIT_LIST_HEAD(&context->mmaps);
        spin_lock_init(&context->mmap_lock);
+
+       if (udata->outlen < sizeof(uresp)) {
+               if (!warned++)
+                       pr_err(MOD "Warning - downlevel libcxgb4 (non-fatal), device status page disabled.");
+               rhp->rdev.flags |= T4_STATUS_PAGE_DISABLED;
+       } else {
+               mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+               if (!mm) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
+
+               uresp.status_page_size = PAGE_SIZE;
+
+               spin_lock(&context->mmap_lock);
+               uresp.status_page_key = context->key;
+               context->key += PAGE_SIZE;
+               spin_unlock(&context->mmap_lock);
+
+               ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
+               if (ret)
+                       goto err_mm;
+
+               mm->key = uresp.status_page_key;
+               mm->addr = virt_to_phys(rhp->rdev.status_page);
+               mm->len = PAGE_SIZE;
+               insert_mmap(context, mm);
+       }
        return &context->ibucontext;
+err_mm:
+       kfree(mm);
+err_free:
+       kfree(context);
+err:
+       return ERR_PTR(ret);
 }
 
 static int c4iw_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
index 582936708e6e492dfca46b88b5db98f16159c0db..3b62eb556a4780f56cfd5131ca69272a388523b4 100644 (file)
@@ -638,6 +638,46 @@ void c4iw_qp_rem_ref(struct ib_qp *qp)
                wake_up(&(to_c4iw_qp(qp)->wait));
 }
 
+static void add_to_fc_list(struct list_head *head, struct list_head *entry)
+{
+       if (list_empty(entry))
+               list_add_tail(entry, head);
+}
+
+static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qhp->rhp->lock, flags);
+       spin_lock(&qhp->lock);
+       if (qhp->rhp->db_state == NORMAL) {
+               t4_ring_sq_db(&qhp->wq, inc);
+       } else {
+               add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
+               qhp->wq.sq.wq_pidx_inc += inc;
+       }
+       spin_unlock(&qhp->lock);
+       spin_unlock_irqrestore(&qhp->rhp->lock, flags);
+       return 0;
+}
+
+static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qhp->rhp->lock, flags);
+       spin_lock(&qhp->lock);
+       if (qhp->rhp->db_state == NORMAL) {
+               t4_ring_rq_db(&qhp->wq, inc);
+       } else {
+               add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry);
+               qhp->wq.rq.wq_pidx_inc += inc;
+       }
+       spin_unlock(&qhp->lock);
+       spin_unlock_irqrestore(&qhp->rhp->lock, flags);
+       return 0;
+}
+
 int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                   struct ib_send_wr **bad_wr)
 {
@@ -750,9 +790,13 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                t4_sq_produce(&qhp->wq, len16);
                idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE);
        }
-       if (t4_wq_db_enabled(&qhp->wq))
+       if (!qhp->rhp->rdev.status_page->db_off) {
                t4_ring_sq_db(&qhp->wq, idx);
-       spin_unlock_irqrestore(&qhp->lock, flag);
+               spin_unlock_irqrestore(&qhp->lock, flag);
+       } else {
+               spin_unlock_irqrestore(&qhp->lock, flag);
+               ring_kernel_sq_db(qhp, idx);
+       }
        return err;
 }
 
@@ -812,9 +856,13 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
                wr = wr->next;
                num_wrs--;
        }
-       if (t4_wq_db_enabled(&qhp->wq))
+       if (!qhp->rhp->rdev.status_page->db_off) {
                t4_ring_rq_db(&qhp->wq, idx);
-       spin_unlock_irqrestore(&qhp->lock, flag);
+               spin_unlock_irqrestore(&qhp->lock, flag);
+       } else {
+               spin_unlock_irqrestore(&qhp->lock, flag);
+               ring_kernel_rq_db(qhp, idx);
+       }
        return err;
 }
 
@@ -1200,35 +1248,6 @@ out:
        return ret;
 }
 
-/*
- * Called by the library when the qp has user dbs disabled due to
- * a DB_FULL condition.  This function will single-thread all user
- * DB rings to avoid overflowing the hw db-fifo.
- */
-static int ring_kernel_db(struct c4iw_qp *qhp, u32 qid, u16 inc)
-{
-       int delay = db_delay_usecs;
-
-       mutex_lock(&qhp->rhp->db_mutex);
-       do {
-
-               /*
-                * The interrupt threshold is dbfifo_int_thresh << 6. So
-                * make sure we don't cross that and generate an interrupt.
-                */
-               if (cxgb4_dbfifo_count(qhp->rhp->rdev.lldi.ports[0], 1) <
-                   (qhp->rhp->rdev.lldi.dbfifo_int_thresh << 5)) {
-                       writel(QID(qid) | PIDX(inc), qhp->wq.db);
-                       break;
-               }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(usecs_to_jiffies(delay));
-               delay = min(delay << 1, 2000);
-       } while (1);
-       mutex_unlock(&qhp->rhp->db_mutex);
-       return 0;
-}
-
 int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
                   enum c4iw_qp_attr_mask mask,
                   struct c4iw_qp_attributes *attrs,
@@ -1278,11 +1297,11 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
        }
 
        if (mask & C4IW_QP_ATTR_SQ_DB) {
-               ret = ring_kernel_db(qhp, qhp->wq.sq.qid, attrs->sq_db_inc);
+               ret = ring_kernel_sq_db(qhp, attrs->sq_db_inc);
                goto out;
        }
        if (mask & C4IW_QP_ATTR_RQ_DB) {
-               ret = ring_kernel_db(qhp, qhp->wq.rq.qid, attrs->rq_db_inc);
+               ret = ring_kernel_rq_db(qhp, attrs->rq_db_inc);
                goto out;
        }
 
@@ -1465,14 +1484,6 @@ out:
        return ret;
 }
 
-static int enable_qp_db(int id, void *p, void *data)
-{
-       struct c4iw_qp *qp = p;
-
-       t4_enable_wq_db(&qp->wq);
-       return 0;
-}
-
 int c4iw_destroy_qp(struct ib_qp *ib_qp)
 {
        struct c4iw_dev *rhp;
@@ -1490,22 +1501,15 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
                c4iw_modify_qp(rhp, qhp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 0);
        wait_event(qhp->wait, !qhp->ep);
 
-       spin_lock_irq(&rhp->lock);
-       remove_handle_nolock(rhp, &rhp->qpidr, qhp->wq.sq.qid);
-       rhp->qpcnt--;
-       BUG_ON(rhp->qpcnt < 0);
-       if (rhp->qpcnt <= db_fc_threshold && rhp->db_state == FLOW_CONTROL) {
-               rhp->rdev.stats.db_state_transitions++;
-               rhp->db_state = NORMAL;
-               idr_for_each(&rhp->qpidr, enable_qp_db, NULL);
-       }
-       if (db_coalescing_threshold >= 0)
-               if (rhp->qpcnt <= db_coalescing_threshold)
-                       cxgb4_enable_db_coalescing(rhp->rdev.lldi.ports[0]);
-       spin_unlock_irq(&rhp->lock);
+       remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
        atomic_dec(&qhp->refcnt);
        wait_event(qhp->wait, !atomic_read(&qhp->refcnt));
 
+       spin_lock_irq(&rhp->lock);
+       if (!list_empty(&qhp->db_fc_entry))
+               list_del_init(&qhp->db_fc_entry);
+       spin_unlock_irq(&rhp->lock);
+
        ucontext = ib_qp->uobject ?
                   to_c4iw_ucontext(ib_qp->uobject->context) : NULL;
        destroy_qp(&rhp->rdev, &qhp->wq,
@@ -1516,14 +1520,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp)
        return 0;
 }
 
-static int disable_qp_db(int id, void *p, void *data)
-{
-       struct c4iw_qp *qp = p;
-
-       t4_disable_wq_db(&qp->wq);
-       return 0;
-}
-
 struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                             struct ib_udata *udata)
 {
@@ -1610,20 +1606,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        init_waitqueue_head(&qhp->wait);
        atomic_set(&qhp->refcnt, 1);
 
-       spin_lock_irq(&rhp->lock);
-       if (rhp->db_state != NORMAL)
-               t4_disable_wq_db(&qhp->wq);
-       rhp->qpcnt++;
-       if (rhp->qpcnt > db_fc_threshold && rhp->db_state == NORMAL) {
-               rhp->rdev.stats.db_state_transitions++;
-               rhp->db_state = FLOW_CONTROL;
-               idr_for_each(&rhp->qpidr, disable_qp_db, NULL);
-       }
-       if (db_coalescing_threshold >= 0)
-               if (rhp->qpcnt > db_coalescing_threshold)
-                       cxgb4_disable_db_coalescing(rhp->rdev.lldi.ports[0]);
-       ret = insert_handle_nolock(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
-       spin_unlock_irq(&rhp->lock);
+       ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
        if (ret)
                goto err2;
 
@@ -1709,6 +1692,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
        }
        qhp->ibqp.qp_num = qhp->wq.sq.qid;
        init_timer(&(qhp->timer));
+       INIT_LIST_HEAD(&qhp->db_fc_entry);
        PDBG("%s qhp %p sq_num_entries %d, rq_num_entries %d qpid 0x%0x\n",
             __func__, qhp, qhp->attr.sq_num_entries, qhp->attr.rq_num_entries,
             qhp->wq.sq.qid);
index e73ace739183a9864ab8fee70e374cdc9ce0d178..eeca8b1e63764cbbd7e8f1a0760028730bd9e944 100644 (file)
@@ -300,6 +300,7 @@ struct t4_sq {
        u16 cidx;
        u16 pidx;
        u16 wq_pidx;
+       u16 wq_pidx_inc;
        u16 flags;
        short flush_cidx;
 };
@@ -324,6 +325,7 @@ struct t4_rq {
        u16 cidx;
        u16 pidx;
        u16 wq_pidx;
+       u16 wq_pidx_inc;
 };
 
 struct t4_wq {
@@ -609,3 +611,7 @@ static inline void t4_set_cq_in_error(struct t4_cq *cq)
        ((struct t4_status_page *)&cq->queue[cq->size])->qp_err = 1;
 }
 #endif
+
+struct t4_dev_status_page {
+       u8 db_off;
+};
index 32b754c35ab78f5f11f9e0014de8952df549e060..11ccd276e5d9c334d2cb3aa445ddaac1401483b7 100644 (file)
@@ -70,4 +70,9 @@ struct c4iw_create_qp_resp {
        __u32 qid_mask;
        __u32 flags;
 };
+
+struct c4iw_alloc_ucontext_resp {
+       __u64 status_page_key;
+       __u32 status_page_size;
+};
 #endif
index 2f215b93db6ba5a68b6d7e6fc38d21c91ff0cfa9..0eb141c41416cd89c99a3529df3e1dd0f2246234 100644 (file)
@@ -154,7 +154,7 @@ void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
                        continue;
 
                slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
-               if (slave_id >= dev->dev->num_slaves)
+               if (slave_id >= dev->dev->num_vfs + 1)
                        return;
                tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
                form_cache_ag = get_cached_alias_guid(dev, port_num,
index d1f5f1dd77b0db3d364fe447bd7f3259b4a0ff6d..56a593e0ae5d1f537db0f3615ee29eb99b0defc2 100644 (file)
@@ -61,6 +61,11 @@ struct cm_generic_msg {
        __be32 remote_comm_id;
 };
 
+struct cm_sidr_generic_msg {
+       struct ib_mad_hdr hdr;
+       __be32 request_id;
+};
+
 struct cm_req_msg {
        unsigned char unused[0x60];
        union ib_gid primary_path_sgid;
@@ -69,28 +74,62 @@ struct cm_req_msg {
 
 static void set_local_comm_id(struct ib_mad *mad, u32 cm_id)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-       msg->local_comm_id = cpu_to_be32(cm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               msg->request_id = cpu_to_be32(cm_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               pr_err("trying to set local_comm_id in SIDR_REP\n");
+               return;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               msg->local_comm_id = cpu_to_be32(cm_id);
+       }
 }
 
 static u32 get_local_comm_id(struct ib_mad *mad)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-
-       return be32_to_cpu(msg->local_comm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               return be32_to_cpu(msg->request_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               pr_err("trying to set local_comm_id in SIDR_REP\n");
+               return -1;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               return be32_to_cpu(msg->local_comm_id);
+       }
 }
 
 static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-       msg->remote_comm_id = cpu_to_be32(cm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               msg->request_id = cpu_to_be32(cm_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               pr_err("trying to set remote_comm_id in SIDR_REQ\n");
+               return;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               msg->remote_comm_id = cpu_to_be32(cm_id);
+       }
 }
 
 static u32 get_remote_comm_id(struct ib_mad *mad)
 {
-       struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
-
-       return be32_to_cpu(msg->remote_comm_id);
+       if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
+               struct cm_sidr_generic_msg *msg =
+                       (struct cm_sidr_generic_msg *)mad;
+               return be32_to_cpu(msg->request_id);
+       } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               pr_err("trying to set remote_comm_id in SIDR_REQ\n");
+               return -1;
+       } else {
+               struct cm_generic_msg *msg = (struct cm_generic_msg *)mad;
+               return be32_to_cpu(msg->remote_comm_id);
+       }
 }
 
 static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad)
@@ -282,19 +321,21 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
        u32 sl_cm_id;
        int pv_cm_id = -1;
 
-       sl_cm_id = get_local_comm_id(mad);
-
        if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
-                       mad->mad_hdr.attr_id == CM_REP_ATTR_ID) {
+                       mad->mad_hdr.attr_id == CM_REP_ATTR_ID ||
+                       mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
+               sl_cm_id = get_local_comm_id(mad);
                id = id_map_alloc(ibdev, slave_id, sl_cm_id);
                if (IS_ERR(id)) {
                        mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n",
                                __func__, slave_id, sl_cm_id);
                        return PTR_ERR(id);
                }
-       } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID) {
+       } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID ||
+                  mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) {
                return 0;
        } else {
+               sl_cm_id = get_local_comm_id(mad);
                id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id);
        }
 
@@ -315,14 +356,18 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id
 }
 
 int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
-                                                            struct ib_mad *mad)
+                            struct ib_mad *mad)
 {
        u32 pv_cm_id;
        struct id_map_entry *id;
 
-       if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID) {
+       if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID ||
+           mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) {
                union ib_gid gid;
 
+               if (!slave)
+                       return 0;
+
                gid = gid_from_req_msg(ibdev, mad);
                *slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
                if (*slave < 0) {
@@ -341,7 +386,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
                return -ENOENT;
        }
 
-       *slave = id->slave_id;
+       if (slave)
+               *slave = id->slave_id;
        set_remote_comm_id(mad, id->sl_cm_id);
 
        if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID)
index cc40f08ca8f1d353faafde91015ab13c247bad4b..5f640814cc81763e61fad3fb2bcdc50993a57a51 100644 (file)
@@ -564,7 +564,7 @@ static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum)
 }
 
 static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct ib_wc *wc,
-                          unsigned tail, struct mlx4_cqe *cqe)
+                          unsigned tail, struct mlx4_cqe *cqe, int is_eth)
 {
        struct mlx4_ib_proxy_sqp_hdr *hdr;
 
@@ -574,12 +574,20 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct
                                   DMA_FROM_DEVICE);
        hdr = (struct mlx4_ib_proxy_sqp_hdr *) (qp->sqp_proxy_rcv[tail].addr);
        wc->pkey_index  = be16_to_cpu(hdr->tun.pkey_index);
-       wc->slid        = be16_to_cpu(hdr->tun.slid_mac_47_32);
-       wc->sl          = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12);
        wc->src_qp      = be32_to_cpu(hdr->tun.flags_src_qp) & 0xFFFFFF;
        wc->wc_flags   |= (hdr->tun.g_ml_path & 0x80) ? (IB_WC_GRH) : 0;
        wc->dlid_path_bits = 0;
 
+       if (is_eth) {
+               wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid);
+               memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4);
+               memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2);
+               wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
+       } else {
+               wc->slid        = be16_to_cpu(hdr->tun.slid_mac_47_32);
+               wc->sl          = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12);
+       }
+
        return 0;
 }
 
@@ -594,6 +602,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
        struct mlx4_srq *msrq = NULL;
        int is_send;
        int is_error;
+       int is_eth;
        u32 g_mlpath_rqpn;
        u16 wqe_ctr;
        unsigned tail = 0;
@@ -778,11 +787,15 @@ repoll:
                        break;
                }
 
+               is_eth = (rdma_port_get_link_layer(wc->qp->device,
+                                                 (*cur_qp)->port) ==
+                         IB_LINK_LAYER_ETHERNET);
                if (mlx4_is_mfunc(to_mdev(cq->ibcq.device)->dev)) {
                        if ((*cur_qp)->mlx4_ib_qp_type &
                            (MLX4_IB_QPT_PROXY_SMI_OWNER |
                             MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI))
-                               return use_tunnel_data(*cur_qp, cq, wc, tail, cqe);
+                               return use_tunnel_data(*cur_qp, cq, wc, tail,
+                                                      cqe, is_eth);
                }
 
                wc->slid           = be16_to_cpu(cqe->rlid);
@@ -793,20 +806,21 @@ repoll:
                wc->pkey_index     = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f;
                wc->wc_flags      |= mlx4_ib_ipoib_csum_ok(cqe->status,
                                        cqe->checksum) ? IB_WC_IP_CSUM_OK : 0;
-               if (rdma_port_get_link_layer(wc->qp->device,
-                               (*cur_qp)->port) == IB_LINK_LAYER_ETHERNET)
+               if (is_eth) {
                        wc->sl  = be16_to_cpu(cqe->sl_vid) >> 13;
-               else
-                       wc->sl  = be16_to_cpu(cqe->sl_vid) >> 12;
-               if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) {
-                       wc->vlan_id = be16_to_cpu(cqe->sl_vid) &
-                               MLX4_CQE_VID_MASK;
+                       if (be32_to_cpu(cqe->vlan_my_qpn) &
+                                       MLX4_CQE_VLAN_PRESENT_MASK) {
+                               wc->vlan_id = be16_to_cpu(cqe->sl_vid) &
+                                       MLX4_CQE_VID_MASK;
+                       } else {
+                               wc->vlan_id = 0xffff;
+                       }
+                       memcpy(wc->smac, cqe->smac, ETH_ALEN);
+                       wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
                } else {
+                       wc->sl  = be16_to_cpu(cqe->sl_vid) >> 12;
                        wc->vlan_id = 0xffff;
                }
-               wc->wc_flags |= IB_WC_WITH_VLAN;
-               memcpy(wc->smac, cqe->smac, ETH_ALEN);
-               wc->wc_flags |= IB_WC_WITH_SMAC;
        }
 
        return 0;
index f2a3f48107e71e1d53b0abb61757f1f0ba38bb59..fd36ec67263208745170b28fce61e0ffec88844d 100644 (file)
@@ -467,6 +467,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
        int ret = 0;
        u16 tun_pkey_ix;
        u16 cached_pkey;
+       u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
 
        if (dest_qpt > IB_QPT_GSI)
                return -EINVAL;
@@ -509,6 +510,10 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
         * The driver will set the force loopback bit in post_send */
        memset(&attr, 0, sizeof attr);
        attr.port_num = port;
+       if (is_eth) {
+               memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16);
+               attr.ah_flags = IB_AH_GRH;
+       }
        ah = ib_create_ah(tun_ctx->pd, &attr);
        if (IS_ERR(ah))
                return -ENOMEM;
@@ -540,11 +545,36 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
 
        /* adjust tunnel data */
        tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix);
-       tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12);
-       tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid);
        tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF);
        tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0;
 
+       if (is_eth) {
+               u16 vlan = 0;
+               if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan,
+                                               NULL)) {
+                       /* VST mode */
+                       if (vlan != wc->vlan_id)
+                               /* Packet vlan is not the VST-assigned vlan.
+                                * Drop the packet.
+                                */
+                               goto out;
+                        else
+                               /* Remove the vlan tag before forwarding
+                                * the packet to the VF.
+                                */
+                               vlan = 0xffff;
+               } else {
+                       vlan = wc->vlan_id;
+               }
+
+               tun_mad->hdr.sl_vid = cpu_to_be16(vlan);
+               memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4);
+               memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2);
+       } else {
+               tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12);
+               tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid);
+       }
+
        ib_dma_sync_single_for_device(&dev->ib_dev,
                                      tun_qp->tx_ring[tun_tx_ix].buf.map,
                                      sizeof (struct mlx4_rcv_tunnel_mad),
@@ -580,6 +610,41 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port,
        int err;
        int slave;
        u8 *slave_id;
+       int is_eth = 0;
+
+       if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND)
+               is_eth = 0;
+       else
+               is_eth = 1;
+
+       if (is_eth) {
+               if (!(wc->wc_flags & IB_WC_GRH)) {
+                       mlx4_ib_warn(ibdev, "RoCE grh not present.\n");
+                       return -EINVAL;
+               }
+               if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) {
+                       mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n");
+                       return -EINVAL;
+               }
+               if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) {
+                       mlx4_ib_warn(ibdev, "failed matching grh\n");
+                       return -ENOENT;
+               }
+               if (slave >= dev->dev->caps.sqp_demux) {
+                       mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n",
+                                    slave, dev->dev->caps.sqp_demux);
+                       return -ENOENT;
+               }
+
+               if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad))
+                       return 0;
+
+               err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad);
+               if (err)
+                       pr_debug("failed sending to slave %d via tunnel qp (%d)\n",
+                                slave, err);
+               return 0;
+       }
 
        /* Initially assume that this mad is for us */
        slave = mlx4_master_func_num(dev->dev);
@@ -1076,8 +1141,9 @@ static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave)
 
 
 int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
-                        enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
-                        u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad)
+                        enum ib_qp_type dest_qpt, u16 pkey_index,
+                        u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr,
+                        u8 *s_mac, struct ib_mad *mad)
 {
        struct ib_sge list;
        struct ib_send_wr wr, *bad_wr;
@@ -1166,6 +1232,9 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
        wr.num_sge = 1;
        wr.opcode = IB_WR_SEND;
        wr.send_flags = IB_SEND_SIGNALED;
+       if (s_mac)
+               memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6);
+
 
        ret = ib_post_send(send_qp, &wr, &bad_wr);
 out:
@@ -1174,6 +1243,22 @@ out:
        return ret;
 }
 
+static int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port)
+{
+       if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND)
+               return slave;
+       return mlx4_get_base_gid_ix(dev->dev, slave, port);
+}
+
+static void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port,
+                                   struct ib_ah_attr *ah_attr)
+{
+       if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND)
+               ah_attr->grh.sgid_index = slave;
+       else
+               ah_attr->grh.sgid_index += get_slave_base_gid_ix(dev, slave, port);
+}
+
 static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc)
 {
        struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev);
@@ -1184,6 +1269,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
        struct ib_ah_attr ah_attr;
        u8 *slave_id;
        int slave;
+       int port;
 
        /* Get slave that sent this packet */
        if (wc->src_qp < dev->dev->phys_caps.base_proxy_sqpn ||
@@ -1260,12 +1346,18 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
        memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av));
        ah.ibah.device = ctx->ib_dev;
        mlx4_ib_query_ah(&ah.ibah, &ah_attr);
-       if ((ah_attr.ah_flags & IB_AH_GRH) &&
-           (ah_attr.grh.sgid_index != slave)) {
-               mlx4_ib_warn(ctx->ib_dev, "slave:%d accessed invalid sgid_index:%d\n",
-                            slave, ah_attr.grh.sgid_index);
+       if (ah_attr.ah_flags & IB_AH_GRH)
+               fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr);
+
+       port = mlx4_slave_convert_port(dev->dev, slave, ah_attr.port_num);
+       if (port < 0)
                return;
-       }
+       ah_attr.port_num = port;
+       memcpy(ah_attr.dmac, tunnel->hdr.mac, 6);
+       ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan);
+       /* if slave have default vlan use it */
+       mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave,
+                                   &ah_attr.vlan_id, &ah_attr.sl);
 
        mlx4_ib_send_to_wire(dev, slave, ctx->port,
                             is_proxy_qp0(dev, wc->src_qp, slave) ?
@@ -1273,7 +1365,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc
                             be16_to_cpu(tunnel->hdr.pkey_index),
                             be32_to_cpu(tunnel->hdr.remote_qpn),
                             be32_to_cpu(tunnel->hdr.qkey),
-                            &ah_attr, &tunnel->mad);
+                            &ah_attr, wc->smac, &tunnel->mad);
 }
 
 static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx,
@@ -1850,7 +1942,15 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
        ctx->port = port;
        ctx->ib_dev = &dev->ib_dev;
 
-       for (i = 0; i < dev->dev->caps.sqp_demux; i++) {
+       for (i = 0;
+            i < min(dev->dev->caps.sqp_demux, (u16)(dev->dev->num_vfs + 1));
+            i++) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev->dev, i);
+
+               if (!test_bit(port - 1, actv_ports.ports))
+                       continue;
+
                ret = alloc_pv_object(dev, i, port, &ctx->tun[i]);
                if (ret) {
                        ret = -ENOMEM;
index c2702f549f10aae4f7ef115fc25a238fb65c25bd..6cb85467dde7e53db3fdaddf9f626d056b671938 100644 (file)
@@ -53,8 +53,8 @@
 #include "user.h"
 
 #define DRV_NAME       MLX4_IB_DRV_NAME
-#define DRV_VERSION    "1.0"
-#define DRV_RELDATE    "April 4, 2008"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb 2014"
 
 #define MLX4_IB_FLOW_MAX_PRIO 0xFFF
 #define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF
@@ -347,7 +347,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
        props->active_width     =  (((u8 *)mailbox->buf)[5] == 0x40) ?
                                                IB_WIDTH_4X : IB_WIDTH_1X;
        props->active_speed     = IB_SPEED_QDR;
-       props->port_cap_flags   = IB_PORT_CM_SUP;
+       props->port_cap_flags   = IB_PORT_CM_SUP | IB_PORT_IP_BASED_GIDS;
        props->gid_tbl_len      = mdev->dev->caps.gid_table_len[port];
        props->max_msg_sz       = mdev->dev->caps.max_msg_sz;
        props->pkey_tbl_len     = 1;
@@ -1357,6 +1357,21 @@ static struct device_attribute *mlx4_class_attributes[] = {
        &dev_attr_board_id
 };
 
+static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id,
+                                    struct net_device *dev)
+{
+       memcpy(eui, dev->dev_addr, 3);
+       memcpy(eui + 5, dev->dev_addr + 3, 3);
+       if (vlan_id < 0x1000) {
+               eui[3] = vlan_id >> 8;
+               eui[4] = vlan_id & 0xff;
+       } else {
+               eui[3] = 0xff;
+               eui[4] = 0xfe;
+       }
+       eui[0] ^= 2;
+}
+
 static void update_gids_task(struct work_struct *work)
 {
        struct update_gid_work *gw = container_of(work, struct update_gid_work, work);
@@ -1393,7 +1408,6 @@ static void reset_gids_task(struct work_struct *work)
        struct mlx4_cmd_mailbox *mailbox;
        union ib_gid *gids;
        int err;
-       int i;
        struct mlx4_dev *dev = gw->dev->dev;
 
        mailbox = mlx4_alloc_cmd_mailbox(dev);
@@ -1405,18 +1419,16 @@ static void reset_gids_task(struct work_struct *work)
        gids = mailbox->buf;
        memcpy(gids, gw->gids, sizeof(gw->gids));
 
-       for (i = 1; i < gw->dev->num_ports + 1; i++) {
-               if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, i) ==
-                                           IB_LINK_LAYER_ETHERNET) {
-                       err = mlx4_cmd(dev, mailbox->dma,
-                                      MLX4_SET_PORT_GID_TABLE << 8 | i,
-                                      1, MLX4_CMD_SET_PORT,
-                                      MLX4_CMD_TIME_CLASS_B,
-                                      MLX4_CMD_WRAPPED);
-                       if (err)
-                               pr_warn(KERN_WARNING
-                                       "set port %d command failed\n", i);
-               }
+       if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, gw->port) ==
+                                   IB_LINK_LAYER_ETHERNET) {
+               err = mlx4_cmd(dev, mailbox->dma,
+                              MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
+                              1, MLX4_CMD_SET_PORT,
+                              MLX4_CMD_TIME_CLASS_B,
+                              MLX4_CMD_WRAPPED);
+               if (err)
+                       pr_warn(KERN_WARNING
+                               "set port %d command failed\n", gw->port);
        }
 
        mlx4_free_cmd_mailbox(dev, mailbox);
@@ -1425,7 +1437,8 @@ free:
 }
 
 static int update_gid_table(struct mlx4_ib_dev *dev, int port,
-                           union ib_gid *gid, int clear)
+                           union ib_gid *gid, int clear,
+                           int default_gid)
 {
        struct update_gid_work *work;
        int i;
@@ -1434,26 +1447,31 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port,
        int found = -1;
        int max_gids;
 
-       max_gids = dev->dev->caps.gid_table_len[port];
-       for (i = 0; i < max_gids; ++i) {
-               if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid,
-                           sizeof(*gid)))
-                       found = i;
-
-               if (clear) {
-                       if (found >= 0) {
-                               need_update = 1;
-                               dev->iboe.gid_table[port - 1][found] = zgid;
-                               break;
-                       }
-               } else {
-                       if (found >= 0)
-                               break;
-
-                       if (free < 0 &&
-                           !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid,
+       if (default_gid) {
+               free = 0;
+       } else {
+               max_gids = dev->dev->caps.gid_table_len[port];
+               for (i = 1; i < max_gids; ++i) {
+                       if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid,
                                    sizeof(*gid)))
-                               free = i;
+                               found = i;
+
+                       if (clear) {
+                               if (found >= 0) {
+                                       need_update = 1;
+                                       dev->iboe.gid_table[port - 1][found] =
+                                               zgid;
+                                       break;
+                               }
+                       } else {
+                               if (found >= 0)
+                                       break;
+
+                               if (free < 0 &&
+                                   !memcmp(&dev->iboe.gid_table[port - 1][i],
+                                           &zgid, sizeof(*gid)))
+                                       free = i;
+                       }
                }
        }
 
@@ -1478,18 +1496,26 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port,
        return 0;
 }
 
-static int reset_gid_table(struct mlx4_ib_dev *dev)
+static void mlx4_make_default_gid(struct  net_device *dev, union ib_gid *gid)
 {
-       struct update_gid_work *work;
+       gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
+       mlx4_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev);
+}
+
 
+static int reset_gid_table(struct mlx4_ib_dev *dev, u8 port)
+{
+       struct update_gid_work *work;
 
        work = kzalloc(sizeof(*work), GFP_ATOMIC);
        if (!work)
                return -ENOMEM;
-       memset(dev->iboe.gid_table, 0, sizeof(dev->iboe.gid_table));
+
+       memset(dev->iboe.gid_table[port - 1], 0, sizeof(work->gids));
        memset(work->gids, 0, sizeof(work->gids));
        INIT_WORK(&work->work, reset_gids_task);
        work->dev = dev;
+       work->port = port;
        queue_work(wq, &work->work);
        return 0;
 }
@@ -1502,6 +1528,12 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev,
        struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ?
                                rdma_vlan_dev_real_dev(event_netdev) :
                                event_netdev;
+       union ib_gid default_gid;
+
+       mlx4_make_default_gid(real_dev, &default_gid);
+
+       if (!memcmp(gid, &default_gid, sizeof(*gid)))
+               return 0;
 
        if (event != NETDEV_DOWN && event != NETDEV_UP)
                return 0;
@@ -1514,13 +1546,13 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev,
        iboe = &ibdev->iboe;
        spin_lock(&iboe->lock);
 
-       for (port = 1; port <= MLX4_MAX_PORTS; ++port)
+       for (port = 1; port <= ibdev->dev->caps.num_ports; ++port)
                if ((netif_is_bond_master(real_dev) &&
                     (real_dev == iboe->masters[port - 1])) ||
                     (!netif_is_bond_master(real_dev) &&
                     (real_dev == iboe->netdevs[port - 1])))
                        update_gid_table(ibdev, port, gid,
-                                        event == NETDEV_DOWN);
+                                        event == NETDEV_DOWN, 0);
 
        spin_unlock(&iboe->lock);
        return 0;
@@ -1536,18 +1568,15 @@ static u8 mlx4_ib_get_dev_port(struct net_device *dev,
                                rdma_vlan_dev_real_dev(dev) : dev;
 
        iboe = &ibdev->iboe;
-       spin_lock(&iboe->lock);
 
-       for (port = 1; port <= MLX4_MAX_PORTS; ++port)
+       for (port = 1; port <= ibdev->dev->caps.num_ports; ++port)
                if ((netif_is_bond_master(real_dev) &&
                     (real_dev == iboe->masters[port - 1])) ||
                     (!netif_is_bond_master(real_dev) &&
                     (real_dev == iboe->netdevs[port - 1])))
                        break;
 
-       spin_unlock(&iboe->lock);
-
-       if ((port == 0) || (port > MLX4_MAX_PORTS))
+       if ((port == 0) || (port > ibdev->dev->caps.num_ports))
                return 0;
        else
                return port;
@@ -1597,7 +1626,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
        union ib_gid gid;
 
 
-       if ((port == 0) || (port > MLX4_MAX_PORTS))
+       if ((port == 0) || (port > ibdev->dev->caps.num_ports))
                return;
 
        /* IPv4 gids */
@@ -1607,7 +1636,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
                        /*ifa->ifa_address;*/
                        ipv6_addr_set_v4mapped(ifa->ifa_address,
                                               (struct in6_addr *)&gid);
-                       update_gid_table(ibdev, port, &gid, 0);
+                       update_gid_table(ibdev, port, &gid, 0, 0);
                }
                endfor_ifa(in_dev);
                in_dev_put(in_dev);
@@ -1619,7 +1648,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
                read_lock_bh(&in6_dev->lock);
                list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
                        pgid = (union ib_gid *)&ifp->addr;
-                       update_gid_table(ibdev, port, pgid, 0);
+                       update_gid_table(ibdev, port, pgid, 0, 0);
                }
                read_unlock_bh(&in6_dev->lock);
                in6_dev_put(in6_dev);
@@ -1627,14 +1656,26 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev,
 #endif
 }
 
+static void mlx4_ib_set_default_gid(struct mlx4_ib_dev *ibdev,
+                                struct  net_device *dev, u8 port)
+{
+       union ib_gid gid;
+       mlx4_make_default_gid(dev, &gid);
+       update_gid_table(ibdev, port, &gid, 0, 1);
+}
+
 static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev)
 {
        struct  net_device *dev;
+       struct mlx4_ib_iboe *iboe = &ibdev->iboe;
+       int i;
 
-       if (reset_gid_table(ibdev))
-               return -1;
+       for (i = 1; i <= ibdev->num_ports; ++i)
+               if (reset_gid_table(ibdev, i))
+                       return -1;
 
        read_lock(&dev_base_lock);
+       spin_lock(&iboe->lock);
 
        for_each_netdev(&init_net, dev) {
                u8 port = mlx4_ib_get_dev_port(dev, ibdev);
@@ -1642,6 +1683,7 @@ static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev)
                        mlx4_ib_get_dev_addr(dev, ibdev, port);
        }
 
+       spin_unlock(&iboe->lock);
        read_unlock(&dev_base_lock);
 
        return 0;
@@ -1656,25 +1698,57 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev)
 
        spin_lock(&iboe->lock);
        mlx4_foreach_ib_transport_port(port, ibdev->dev) {
+               enum ib_port_state      port_state = IB_PORT_NOP;
                struct net_device *old_master = iboe->masters[port - 1];
+               struct net_device *curr_netdev;
                struct net_device *curr_master;
+
                iboe->netdevs[port - 1] =
                        mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port);
+               if (iboe->netdevs[port - 1])
+                       mlx4_ib_set_default_gid(ibdev,
+                                               iboe->netdevs[port - 1], port);
+               curr_netdev = iboe->netdevs[port - 1];
 
                if (iboe->netdevs[port - 1] &&
                    netif_is_bond_slave(iboe->netdevs[port - 1])) {
-                       rtnl_lock();
                        iboe->masters[port - 1] = netdev_master_upper_dev_get(
                                iboe->netdevs[port - 1]);
-                       rtnl_unlock();
+               } else {
+                       iboe->masters[port - 1] = NULL;
                }
                curr_master = iboe->masters[port - 1];
 
+               if (curr_netdev) {
+                       port_state = (netif_running(curr_netdev) && netif_carrier_ok(curr_netdev)) ?
+                                               IB_PORT_ACTIVE : IB_PORT_DOWN;
+                       mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
+               } else {
+                       reset_gid_table(ibdev, port);
+               }
+               /* if using bonding/team and a slave port is down, we don't the bond IP
+                * based gids in the table since flows that select port by gid may get
+                * the down port.
+                */
+               if (curr_master && (port_state == IB_PORT_DOWN)) {
+                       reset_gid_table(ibdev, port);
+                       mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
+               }
                /* if bonding is used it is possible that we add it to masters
-                   only after IP address is assigned to the net bonding
-                   interface */
-               if (curr_master && (old_master != curr_master))
+                * only after IP address is assigned to the net bonding
+                * interface.
+               */
+               if (curr_master && (old_master != curr_master)) {
+                       reset_gid_table(ibdev, port);
+                       mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
                        mlx4_ib_get_dev_addr(curr_master, ibdev, port);
+               }
+
+               if (!curr_master && (old_master != curr_master)) {
+                       reset_gid_table(ibdev, port);
+                       mlx4_ib_set_default_gid(ibdev, curr_netdev, port);
+                       mlx4_ib_get_dev_addr(curr_netdev, ibdev, port);
+               }
        }
 
        spin_unlock(&iboe->lock);
@@ -1810,17 +1884,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
        int i, j;
        int err;
        struct mlx4_ib_iboe *iboe;
+       int ib_num_ports = 0;
 
        pr_info_once("%s", mlx4_ib_version);
 
-       mlx4_foreach_non_ib_transport_port(i, dev)
-               num_ports++;
-
-       if (mlx4_is_mfunc(dev) && num_ports) {
-               dev_err(&dev->pdev->dev, "RoCE is not supported over SRIOV as yet\n");
-               return NULL;
-       }
-
        num_ports = 0;
        mlx4_foreach_ib_transport_port(i, dev)
                num_ports++;
@@ -1985,10 +2052,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                                ibdev->counters[i] = -1;
        }
 
+       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+               ib_num_ports++;
+
        spin_lock_init(&ibdev->sm_lock);
        mutex_init(&ibdev->cap_mask_mutex);
 
-       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) {
+       if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED &&
+           ib_num_ports) {
                ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS;
                err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count,
                                            MLX4_IB_UC_STEER_QPN_ALIGN,
@@ -2051,7 +2122,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
                        }
                }
 #endif
+               for (i = 1 ; i <= ibdev->num_ports ; ++i)
+                       reset_gid_table(ibdev, i);
+               rtnl_lock();
                mlx4_ib_scan_netdevs(ibdev);
+               rtnl_unlock();
                mlx4_ib_init_gid_table(ibdev);
        }
 
@@ -2248,17 +2323,24 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
        struct mlx4_dev *dev = ibdev->dev;
        int i;
        unsigned long flags;
+       struct mlx4_active_ports actv_ports;
+       unsigned int ports;
+       unsigned int first_port;
 
        if (!mlx4_is_master(dev))
                return;
 
-       dm = kcalloc(dev->caps.num_ports, sizeof *dm, GFP_ATOMIC);
+       actv_ports = mlx4_get_active_ports(dev, slave);
+       ports = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+       first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+
+       dm = kcalloc(ports, sizeof(*dm), GFP_ATOMIC);
        if (!dm) {
                pr_err("failed to allocate memory for tunneling qp update\n");
                goto out;
        }
 
-       for (i = 0; i < dev->caps.num_ports; i++) {
+       for (i = 0; i < ports; i++) {
                dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC);
                if (!dm[i]) {
                        pr_err("failed to allocate memory for tunneling qp update work struct\n");
@@ -2270,9 +2352,9 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init)
                }
        }
        /* initialize or tear down tunnel QPs for the slave */
-       for (i = 0; i < dev->caps.num_ports; i++) {
+       for (i = 0; i < ports; i++) {
                INIT_WORK(&dm[i]->work, mlx4_ib_tunnels_update_work);
-               dm[i]->port = i + 1;
+               dm[i]->port = first_port + i + 1;
                dm[i]->slave = slave;
                dm[i]->do_init = do_init;
                dm[i]->dev = ibdev;
index 25b2cdff00f8e4bcd76044e8916b2aa257a7276e..ed327e6c8fdca54baf19c3ded92d60776cc1adbf 100644 (file)
@@ -215,8 +215,9 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad)
        }
        mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr);
        spin_unlock(&dev->sm_lock);
-       return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port,
-                                   IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, mad);
+       return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev),
+                                   ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY,
+                                   &ah_attr, NULL, mad);
 }
 
 static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx,
index a230683af940663a214ca611f28f842d956270ba..f589522fddfd9efa4e32fdd0a7e8f63e49a54927 100644 (file)
@@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr {
        struct mlx4_rcv_tunnel_hdr tun;
 }  __packed;
 
+struct mlx4_roce_smac_vlan_info {
+       u64 smac;
+       int smac_index;
+       int smac_port;
+       u64 candidate_smac;
+       int candidate_smac_index;
+       int candidate_smac_port;
+       u16 vid;
+       int vlan_index;
+       int vlan_port;
+       u16 candidate_vid;
+       int candidate_vlan_index;
+       int candidate_vlan_port;
+       int update_vid;
+};
+
 struct mlx4_ib_qp {
        struct ib_qp            ibqp;
        struct mlx4_qp          mqp;
@@ -273,8 +289,9 @@ struct mlx4_ib_qp {
        struct list_head        gid_list;
        struct list_head        steering_rules;
        struct mlx4_ib_buf      *sqp_proxy_rcv;
+       struct mlx4_roce_smac_vlan_info pri;
+       struct mlx4_roce_smac_vlan_info alt;
        u64                     reg_id;
-
 };
 
 struct mlx4_ib_srq {
@@ -720,9 +737,12 @@ void mlx4_ib_tunnels_update_work(struct work_struct *work);
 int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
                          enum ib_qp_type qpt, struct ib_wc *wc,
                          struct ib_grh *grh, struct ib_mad *mad);
+
 int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port,
                         enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn,
-                        u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad);
+                        u32 qkey, struct ib_ah_attr *attr, u8 *s_mac,
+                        struct ib_mad *mad);
+
 __be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx);
 
 int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
index d8f4d1fe849430ceb40eab47470d5af033884694..aadf7f82e1f388e387d053637da2e9b12fda22e2 100644 (file)
@@ -662,10 +662,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
                        if (!sqp)
                                return -ENOMEM;
                        qp = &sqp->qp;
+                       qp->pri.vid = 0xFFFF;
+                       qp->alt.vid = 0xFFFF;
                } else {
                        qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL);
                        if (!qp)
                                return -ENOMEM;
+                       qp->pri.vid = 0xFFFF;
+                       qp->alt.vid = 0xFFFF;
                }
        } else
                qp = *caller_qp;
@@ -940,11 +944,32 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
 {
        struct mlx4_ib_cq *send_cq, *recv_cq;
 
-       if (qp->state != IB_QPS_RESET)
+       if (qp->state != IB_QPS_RESET) {
                if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
                                   MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp))
                        pr_warn("modify QP %06x to RESET failed.\n",
                               qp->mqp.qpn);
+               if (qp->pri.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+                       qp->pri.smac = 0;
+               }
+               if (qp->alt.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+                       qp->alt.smac = 0;
+               }
+               if (qp->pri.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
+                       qp->pri.vid = 0xFFFF;
+                       qp->pri.candidate_vid = 0xFFFF;
+                       qp->pri.update_vid = 0;
+               }
+               if (qp->alt.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
+                       qp->alt.vid = 0xFFFF;
+                       qp->alt.candidate_vid = 0xFFFF;
+                       qp->alt.update_vid = 0;
+               }
+       }
 
        get_cqs(qp, &send_cq, &recv_cq);
 
@@ -1057,6 +1082,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
                qp = kzalloc(sizeof *qp, GFP_KERNEL);
                if (!qp)
                        return ERR_PTR(-ENOMEM);
+               qp->pri.vid = 0xFFFF;
+               qp->alt.vid = 0xFFFF;
                /* fall through */
        case IB_QPT_UD:
        {
@@ -1188,12 +1215,13 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port)
 
 static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
                          u64 smac, u16 vlan_tag, struct mlx4_qp_path *path,
-                         u8 port)
+                         struct mlx4_roce_smac_vlan_info *smac_info, u8 port)
 {
        int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) ==
                IB_LINK_LAYER_ETHERNET;
        int vidx;
        int smac_index;
+       int err;
 
 
        path->grh_mylmc     = ah->src_path_bits & 0x7f;
@@ -1223,61 +1251,103 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah,
        }
 
        if (is_eth) {
-               path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
-                       ((port - 1) << 6) | ((ah->sl & 7) << 3);
-
                if (!(ah->ah_flags & IB_AH_GRH))
                        return -1;
 
-               memcpy(path->dmac, ah->dmac, ETH_ALEN);
-               path->ackto = MLX4_IB_LINK_TYPE_ETH;
-               /* find the index  into MAC table for IBoE */
-               if (!is_zero_ether_addr((const u8 *)&smac)) {
-                       if (mlx4_find_cached_mac(dev->dev, port, smac,
-                                                &smac_index))
-                               return -ENOENT;
-               } else {
-                       smac_index = 0;
-               }
-
-               path->grh_mylmc &= 0x80 | smac_index;
+               path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
+                       ((port - 1) << 6) | ((ah->sl & 7) << 3);
 
                path->feup |= MLX4_FEUP_FORCE_ETH_UP;
                if (vlan_tag < 0x1000) {
-                       if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx))
-                               return -ENOENT;
-
-                       path->vlan_index = vidx;
-                       path->fl = 1 << 6;
+                       if (smac_info->vid < 0x1000) {
+                               /* both valid vlan ids */
+                               if (smac_info->vid != vlan_tag) {
+                                       /* different VIDs.  unreg old and reg new */
+                                       err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
+                                       if (err)
+                                               return err;
+                                       smac_info->candidate_vid = vlan_tag;
+                                       smac_info->candidate_vlan_index = vidx;
+                                       smac_info->candidate_vlan_port = port;
+                                       smac_info->update_vid = 1;
+                                       path->vlan_index = vidx;
+                               } else {
+                                       path->vlan_index = smac_info->vlan_index;
+                               }
+                       } else {
+                               /* no current vlan tag in qp */
+                               err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx);
+                               if (err)
+                                       return err;
+                               smac_info->candidate_vid = vlan_tag;
+                               smac_info->candidate_vlan_index = vidx;
+                               smac_info->candidate_vlan_port = port;
+                               smac_info->update_vid = 1;
+                               path->vlan_index = vidx;
+                       }
                        path->feup |= MLX4_FVL_FORCE_ETH_VLAN;
+                       path->fl = 1 << 6;
+               } else {
+                       /* have current vlan tag. unregister it at modify-qp success */
+                       if (smac_info->vid < 0x1000) {
+                               smac_info->candidate_vid = 0xFFFF;
+                               smac_info->update_vid = 1;
+                       }
                }
-       } else
+
+               /* get smac_index for RoCE use.
+                * If no smac was yet assigned, register one.
+                * If one was already assigned, but the new mac differs,
+                * unregister the old one and register the new one.
+               */
+               if (!smac_info->smac || smac_info->smac != smac) {
+                       /* register candidate now, unreg if needed, after success */
+                       smac_index = mlx4_register_mac(dev->dev, port, smac);
+                       if (smac_index >= 0) {
+                               smac_info->candidate_smac_index = smac_index;
+                               smac_info->candidate_smac = smac;
+                               smac_info->candidate_smac_port = port;
+                       } else {
+                               return -EINVAL;
+                       }
+               } else {
+                       smac_index = smac_info->smac_index;
+               }
+
+               memcpy(path->dmac, ah->dmac, 6);
+               path->ackto = MLX4_IB_LINK_TYPE_ETH;
+               /* put MAC table smac index for IBoE */
+               path->grh_mylmc = (u8) (smac_index) | 0x80;
+       } else {
                path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE |
                        ((port - 1) << 6) | ((ah->sl & 0xf) << 2);
+       }
 
        return 0;
 }
 
 static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp,
                         enum ib_qp_attr_mask qp_attr_mask,
+                        struct mlx4_ib_qp *mqp,
                         struct mlx4_qp_path *path, u8 port)
 {
        return _mlx4_set_path(dev, &qp->ah_attr,
                              mlx4_mac_to_u64((u8 *)qp->smac),
                              (qp_attr_mask & IB_QP_VID) ? qp->vlan_id : 0xffff,
-                             path, port);
+                             path, &mqp->pri, port);
 }
 
 static int mlx4_set_alt_path(struct mlx4_ib_dev *dev,
                             const struct ib_qp_attr *qp,
                             enum ib_qp_attr_mask qp_attr_mask,
+                            struct mlx4_ib_qp *mqp,
                             struct mlx4_qp_path *path, u8 port)
 {
        return _mlx4_set_path(dev, &qp->alt_ah_attr,
                              mlx4_mac_to_u64((u8 *)qp->alt_smac),
                              (qp_attr_mask & IB_QP_ALT_VID) ?
                              qp->alt_vlan_id : 0xffff,
-                             path, port);
+                             path, &mqp->alt, port);
 }
 
 static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
@@ -1292,6 +1362,37 @@ static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp)
        }
 }
 
+static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, u8 *smac,
+                                   struct mlx4_qp_context *context)
+{
+       struct net_device *ndev;
+       u64 u64_mac;
+       int smac_index;
+
+
+       ndev = dev->iboe.netdevs[qp->port - 1];
+       if (ndev) {
+               smac = ndev->dev_addr;
+               u64_mac = mlx4_mac_to_u64(smac);
+       } else {
+               u64_mac = dev->dev->caps.def_mac[qp->port];
+       }
+
+       context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6);
+       if (!qp->pri.smac) {
+               smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac);
+               if (smac_index >= 0) {
+                       qp->pri.candidate_smac_index = smac_index;
+                       qp->pri.candidate_smac = u64_mac;
+                       qp->pri.candidate_smac_port = qp->port;
+                       context->pri_path.grh_mylmc = 0x80 | (u8) smac_index;
+               } else {
+                       return -ENOENT;
+               }
+       }
+       return 0;
+}
+
 static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                               const struct ib_qp_attr *attr, int attr_mask,
                               enum ib_qp_state cur_state, enum ib_qp_state new_state)
@@ -1403,7 +1504,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
        }
 
        if (attr_mask & IB_QP_AV) {
-               if (mlx4_set_path(dev, attr, attr_mask, &context->pri_path,
+               if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path,
                                  attr_mask & IB_QP_PORT ?
                                  attr->port_num : qp->port))
                        goto out;
@@ -1426,7 +1527,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                    dev->dev->caps.pkey_table_len[attr->alt_port_num])
                        goto out;
 
-               if (mlx4_set_alt_path(dev, attr, attr_mask, &context->alt_path,
+               if (mlx4_set_alt_path(dev, attr, attr_mask, qp,
+                                     &context->alt_path,
                                      attr->alt_port_num))
                        goto out;
 
@@ -1532,6 +1634,20 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
                                context->pri_path.fl = 0x80;
                        context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE;
                }
+               if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) ==
+                   IB_LINK_LAYER_ETHERNET) {
+                       if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI ||
+                           qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI)
+                               context->pri_path.feup = 1 << 7; /* don't fsm */
+                       /* handle smac_index */
+                       if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD ||
+                           qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
+                           qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
+                               err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
+                               if (err)
+                                       return -EINVAL;
+                       }
+               }
        }
 
        if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET)
@@ -1619,28 +1735,113 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
         * If we moved a kernel QP to RESET, clean up all old CQ
         * entries and reinitialize the QP.
         */
-       if (new_state == IB_QPS_RESET && !ibqp->uobject) {
-               mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
-                                ibqp->srq ? to_msrq(ibqp->srq): NULL);
-               if (send_cq != recv_cq)
-                       mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+       if (new_state == IB_QPS_RESET) {
+               if (!ibqp->uobject) {
+                       mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
+                                        ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+                       if (send_cq != recv_cq)
+                               mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL);
+
+                       qp->rq.head = 0;
+                       qp->rq.tail = 0;
+                       qp->sq.head = 0;
+                       qp->sq.tail = 0;
+                       qp->sq_next_wqe = 0;
+                       if (qp->rq.wqe_cnt)
+                               *qp->db.db  = 0;
 
-               qp->rq.head = 0;
-               qp->rq.tail = 0;
-               qp->sq.head = 0;
-               qp->sq.tail = 0;
-               qp->sq_next_wqe = 0;
-               if (qp->rq.wqe_cnt)
-                       *qp->db.db  = 0;
+                       if (qp->flags & MLX4_IB_QP_NETIF)
+                               mlx4_ib_steer_qp_reg(dev, qp, 0);
+               }
+               if (qp->pri.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+                       qp->pri.smac = 0;
+               }
+               if (qp->alt.smac) {
+                       mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+                       qp->alt.smac = 0;
+               }
+               if (qp->pri.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid);
+                       qp->pri.vid = 0xFFFF;
+                       qp->pri.candidate_vid = 0xFFFF;
+                       qp->pri.update_vid = 0;
+               }
 
-               if (qp->flags & MLX4_IB_QP_NETIF)
-                       mlx4_ib_steer_qp_reg(dev, qp, 0);
+               if (qp->alt.vid < 0x1000) {
+                       mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid);
+                       qp->alt.vid = 0xFFFF;
+                       qp->alt.candidate_vid = 0xFFFF;
+                       qp->alt.update_vid = 0;
+               }
        }
-
 out:
        if (err && steer_qp)
                mlx4_ib_steer_qp_reg(dev, qp, 0);
        kfree(context);
+       if (qp->pri.candidate_smac) {
+               if (err) {
+                       mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac);
+               } else {
+                       if (qp->pri.smac)
+                               mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac);
+                       qp->pri.smac = qp->pri.candidate_smac;
+                       qp->pri.smac_index = qp->pri.candidate_smac_index;
+                       qp->pri.smac_port = qp->pri.candidate_smac_port;
+               }
+               qp->pri.candidate_smac = 0;
+               qp->pri.candidate_smac_index = 0;
+               qp->pri.candidate_smac_port = 0;
+       }
+       if (qp->alt.candidate_smac) {
+               if (err) {
+                       mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->alt.candidate_smac);
+               } else {
+                       if (qp->alt.smac)
+                               mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac);
+                       qp->alt.smac = qp->alt.candidate_smac;
+                       qp->alt.smac_index = qp->alt.candidate_smac_index;
+                       qp->alt.smac_port = qp->alt.candidate_smac_port;
+               }
+               qp->alt.candidate_smac = 0;
+               qp->alt.candidate_smac_index = 0;
+               qp->alt.candidate_smac_port = 0;
+       }
+
+       if (qp->pri.update_vid) {
+               if (err) {
+                       if (qp->pri.candidate_vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port,
+                                                    qp->pri.candidate_vid);
+               } else {
+                       if (qp->pri.vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port,
+                                                    qp->pri.vid);
+                       qp->pri.vid = qp->pri.candidate_vid;
+                       qp->pri.vlan_port = qp->pri.candidate_vlan_port;
+                       qp->pri.vlan_index =  qp->pri.candidate_vlan_index;
+               }
+               qp->pri.candidate_vid = 0xFFFF;
+               qp->pri.update_vid = 0;
+       }
+
+       if (qp->alt.update_vid) {
+               if (err) {
+                       if (qp->alt.candidate_vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port,
+                                                    qp->alt.candidate_vid);
+               } else {
+                       if (qp->alt.vid < 0x1000)
+                               mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port,
+                                                    qp->alt.vid);
+                       qp->alt.vid = qp->alt.candidate_vid;
+                       qp->alt.vlan_port = qp->alt.candidate_vlan_port;
+                       qp->alt.vlan_index =  qp->alt.candidate_vlan_index;
+               }
+               qp->alt.candidate_vid = 0xFFFF;
+               qp->alt.update_vid = 0;
+       }
+
        return err;
 }
 
@@ -1842,9 +2043,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 {
        struct ib_device *ib_dev = sqp->qp.ibqp.device;
        struct mlx4_wqe_mlx_seg *mlx = wqe;
+       struct mlx4_wqe_ctrl_seg *ctrl = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
        struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
-       struct net_device *ndev;
        union ib_gid sgid;
        u16 pkey;
        int send_size;
@@ -1868,12 +2069,11 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                        /* When multi-function is enabled, the ib_core gid
                         * indexes don't necessarily match the hw ones, so
                         * we must use our own cache */
-                       sgid.global.subnet_prefix =
-                               to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-                               subnet_prefix;
-                       sgid.global.interface_id =
-                               to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1].
-                               guid_cache[ah->av.ib.gid_index];
+                       err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev,
+                                                          be32_to_cpu(ah->av.ib.port_pd) >> 24,
+                                                          ah->av.ib.gid_index, &sgid.raw[0]);
+                       if (err)
+                               return err;
                } else  {
                        err = ib_get_cached_gid(ib_dev,
                                                be32_to_cpu(ah->av.ib.port_pd) >> 24,
@@ -1902,6 +2102,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                sqp->ud_header.grh.flow_label    =
                        ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff);
                sqp->ud_header.grh.hop_limit     = ah->av.ib.hop_limit;
+               if (is_eth)
+                       memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16);
+               else {
                if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) {
                        /* When multi-function is enabled, the ib_core gid
                         * indexes don't necessarily match the hw ones, so
@@ -1917,6 +2120,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
                                          be32_to_cpu(ah->av.ib.port_pd) >> 24,
                                          ah->av.ib.gid_index,
                                          &sqp->ud_header.grh.source_gid);
+               }
                memcpy(sqp->ud_header.grh.destination_gid.raw,
                       ah->av.ib.dgid, 16);
        }
@@ -1949,16 +2153,23 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 
        if (is_eth) {
                u8 *smac;
+               struct in6_addr in6;
+
                u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13;
 
                mlx->sched_prio = cpu_to_be16(pcp);
 
                memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
                /* FIXME: cache smac value? */
-               ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1];
-               if (!ndev)
-                       return -ENODEV;
-               smac = ndev->dev_addr;
+               memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2);
+               memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4);
+               memcpy(&in6, sgid.raw, sizeof(in6));
+
+               if (!mlx4_is_mfunc(to_mdev(ib_dev)->dev))
+                       smac = to_mdev(sqp->qp.ibqp.device)->
+                               iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+               else    /* use the src mac of the tunnel */
+                       smac = ah->av.eth.s_mac;
                memcpy(sqp->ud_header.eth.smac_h, smac, 6);
                if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
                        mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
@@ -2190,6 +2401,8 @@ static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_
        hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn);
        hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index);
        hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+       memcpy(hdr.mac, ah->av.eth.mac, 6);
+       hdr.vlan = ah->av.eth.vlan;
 
        spc = MLX4_INLINE_ALIGN -
                ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1));
index db2ea31df8325175d764051849f55631134148b5..5a38e43eca650c6cb736a5cee6e290e357aeb9ed 100644 (file)
@@ -627,6 +627,7 @@ static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave)
        int port;
        struct kobject *p, *t;
        struct mlx4_port *mport;
+       struct mlx4_active_ports actv_ports;
 
        get_name(dev, name, slave, sizeof name);
 
@@ -649,7 +650,11 @@ static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave)
                goto err_ports;
        }
 
+       actv_ports = mlx4_get_active_ports(dev->dev, slave);
+
        for (port = 1; port <= dev->dev->caps.num_ports; ++port) {
+               if (!test_bit(port - 1, actv_ports.ports))
+                       continue;
                err = add_port(dev, port, slave);
                if (err)
                        goto err_add;
index 8e6aebfaf8a4cdb5c8cc503c24ac1701e1731c3c..10df386c63447c9757fa22bfc97c433b59ea3895 100644 (file)
@@ -1,6 +1,6 @@
 config MLX5_INFINIBAND
        tristate "Mellanox Connect-IB HCA support"
-       depends on NETDEVICES && ETHERNET && PCI && X86
+       depends on NETDEVICES && ETHERNET && PCI
        select NET_VENDOR_MELLANOX
        select MLX5_CORE
        ---help---
index 9660d093f8cf14cdb686f2b432f6eca96519fb8b..bf900579ac08b4cae5ac09320b5189727b292485 100644 (file)
@@ -46,8 +46,8 @@
 #include "mlx5_ib.h"
 
 #define DRIVER_NAME "mlx5_ib"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver");
@@ -261,8 +261,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev,
        props->device_cap_flags    = IB_DEVICE_CHANGE_PHY_PORT |
                IB_DEVICE_PORT_ACTIVE_EVENT             |
                IB_DEVICE_SYS_IMAGE_GUID                |
-               IB_DEVICE_RC_RNR_NAK_GEN                |
-               IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;
+               IB_DEVICE_RC_RNR_NAK_GEN;
        flags = dev->mdev.caps.flags;
        if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR)
                props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
@@ -536,24 +535,38 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
                                                  struct ib_udata *udata)
 {
        struct mlx5_ib_dev *dev = to_mdev(ibdev);
-       struct mlx5_ib_alloc_ucontext_req req;
+       struct mlx5_ib_alloc_ucontext_req_v2 req;
        struct mlx5_ib_alloc_ucontext_resp resp;
        struct mlx5_ib_ucontext *context;
        struct mlx5_uuar_info *uuari;
        struct mlx5_uar *uars;
        int gross_uuars;
        int num_uars;
+       int ver;
        int uuarn;
        int err;
        int i;
+       int reqlen;
 
        if (!dev->ib_active)
                return ERR_PTR(-EAGAIN);
 
-       err = ib_copy_from_udata(&req, udata, sizeof(req));
+       memset(&req, 0, sizeof(req));
+       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))
+               ver = 2;
+       else
+               return ERR_PTR(-EINVAL);
+
+       err = ib_copy_from_udata(&req, udata, reqlen);
        if (err)
                return ERR_PTR(err);
 
+       if (req.flags || req.reserved)
+               return ERR_PTR(-EINVAL);
+
        if (req.total_num_uuars > MLX5_MAX_UUARS)
                return ERR_PTR(-ENOMEM);
 
@@ -626,6 +639,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
        if (err)
                goto out_uars;
 
+       uuari->ver = ver;
        uuari->num_low_latency_uuars = req.num_low_latency_uuars;
        uuari->uars = uars;
        uuari->num_uars = num_uars;
index ae37fb9bf2627c7507dfb7b6a75e369e5b5fe29f..7dfe8a1c84cff141a2bee714e6367f5500334390 100644 (file)
@@ -216,7 +216,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_raddr_seg) +
+                       sizeof(struct mlx5_wqe_umr_ctrl_seg) +
+                       sizeof(struct mlx5_mkey_seg);
                break;
 
        case IB_QPT_UD:
@@ -428,11 +430,17 @@ static int alloc_uuar(struct mlx5_uuar_info *uuari,
                break;
 
        case MLX5_IB_LATENCY_CLASS_MEDIUM:
-               uuarn = alloc_med_class_uuar(uuari);
+               if (uuari->ver < 2)
+                       uuarn = -ENOMEM;
+               else
+                       uuarn = alloc_med_class_uuar(uuari);
                break;
 
        case MLX5_IB_LATENCY_CLASS_HIGH:
-               uuarn = alloc_high_class_uuar(uuari);
+               if (uuari->ver < 2)
+                       uuarn = -ENOMEM;
+               else
+                       uuarn = alloc_high_class_uuar(uuari);
                break;
 
        case MLX5_IB_LATENCY_CLASS_FAST_PATH:
@@ -657,8 +665,8 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev,
        int err;
 
        uuari = &dev->mdev.priv.uuari;
-       if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK)
-               qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK;
+       if (init_attr->create_flags)
+               return -EINVAL;
 
        if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR)
                lc = MLX5_IB_LATENCY_CLASS_FAST_PATH;
index 32a2a5dfc52308549b8e9457da44041936c38d70..0f4f8e42a17fe5f067d68782f21598980451c48f 100644 (file)
@@ -62,6 +62,13 @@ struct mlx5_ib_alloc_ucontext_req {
        __u32   num_low_latency_uuars;
 };
 
+struct mlx5_ib_alloc_ucontext_req_v2 {
+       __u32   total_num_uuars;
+       __u32   num_low_latency_uuars;
+       __u32   flags;
+       __u32   reserved;
+};
+
 struct mlx5_ib_alloc_ucontext_resp {
        __u32   qp_tab_size;
        __u32   bf_reg_size;
index 429141078eec632d2409b75f267193f4fb242f96..353c7b05a90a102db8fc22be79187918004334cc 100644 (file)
@@ -675,8 +675,11 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
        INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status);
 
        /* Initialize network devices */
-       if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL)
+       netdev = nes_netdev_init(nesdev, mmio_regs);
+       if (netdev == NULL) {
+               ret = -ENOMEM;
                goto bail7;
+       }
 
        /* Register network device */
        ret = register_netdev(netdev);
index 2ca86ca818bdf04d68a3f21c0cd74fa092c36504..1a8a945efa60e8fdb6683572d0d39e77f7dba36f 100644 (file)
@@ -127,7 +127,7 @@ static int ocrdma_addr_event(unsigned long event, struct net_device *netdev,
 
        is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN;
        if (is_vlan)
-               netdev = vlan_dev_real_dev(netdev);
+               netdev = rdma_vlan_dev_real_dev(netdev);
 
        rcu_read_lock();
        list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
index aa92f40c9d50e739a14b0f19fd5e183f63ab964a..e0cc201be41a96df4c177ffa9517fec12988ac7d 100644 (file)
@@ -176,7 +176,7 @@ int ocrdma_query_port(struct ib_device *ibdev,
        props->port_cap_flags =
            IB_PORT_CM_SUP |
            IB_PORT_REINIT_SUP |
-           IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP;
+           IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_IP_BASED_GIDS;
        props->gid_tbl_len = OCRDMA_MAX_SGID;
        props->pkey_tbl_len = 1;
        props->bad_pkey_cntr = 0;
@@ -1416,7 +1416,7 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
                                          OCRDMA_QP_PARAMS_HOP_LMT_MASK) >>
                                                OCRDMA_QP_PARAMS_HOP_LMT_SHIFT;
        qp_attr->ah_attr.grh.traffic_class = (params.tclass_sq_psn &
-                                             OCRDMA_QP_PARAMS_SQ_PSN_MASK) >>
+                                             OCRDMA_QP_PARAMS_TCLASS_MASK) >>
                                                OCRDMA_QP_PARAMS_TCLASS_SHIFT;
 
        qp_attr->ah_attr.ah_flags = IB_AH_GRH;
index 5bfc02f450e6a69251632db17fb6ff699dfe8c10..d1bd21319d7d2ec128442042448ce101111938a3 100644 (file)
@@ -2395,6 +2395,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd)
        qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a);
        qib_write_kreg(dd, kr_scratch, 0ULL);
 
+       /* ensure previous Tx parameters are not still forced */
+       qib_write_kreg_port(ppd, krp_tx_deemph_override,
+               SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0,
+               reset_tx_deemphasis_override));
+
        if (qib_compat_ddr_negotiate) {
                ppd->cpspec->ibdeltainprog = 1;
                ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd,
index 7ecc6061f1f4d5f915edb0e3994b2dcdc327de83..f8dfd76be89fbfdcb94559ed58cda9a3d8c591b2 100644 (file)
@@ -629,6 +629,7 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
 {
        enum usnic_transport_type trans_type = qp_flow->trans_type;
        int err;
+       uint16_t port_num = 0;
 
        switch (trans_type) {
        case USNIC_TRANSPORT_ROCE_CUSTOM:
@@ -637,9 +638,15 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow,
        case USNIC_TRANSPORT_IPV4_UDP:
                err = usnic_transport_sock_get_addr(qp_flow->udp.sock,
                                                        NULL, NULL,
-                                                       (uint16_t *) id);
+                                                       &port_num);
                if (err)
                        return err;
+               /*
+                * Copy port_num to stack first and then to *id,
+                * so that the short to int cast works for little
+                * and big endian systems.
+                */
+               *id = port_num;
                break;
        default:
                usnic_err("Unsupported transport %u\n", trans_type);
index 538822684d5ba537ce2f11e9366fae0766fd4a6f..334f34b1cd46533b0b1dc6cdec9c9f0f30c2af76 100644 (file)
@@ -610,11 +610,12 @@ void iser_snd_completion(struct iser_tx_desc *tx_desc,
                ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr,
                                        ISER_HEADERS_LEN, DMA_TO_DEVICE);
                kmem_cache_free(ig.desc_cache, tx_desc);
+               tx_desc = NULL;
        }
 
        atomic_dec(&ib_conn->post_send_buf_count);
 
-       if (tx_desc->type == ISCSI_TX_CONTROL) {
+       if (tx_desc && tx_desc->type == ISCSI_TX_CONTROL) {
                /* this arithmetic is legal by libiscsi dd_data allocation */
                task = (void *) ((long)(void *)tx_desc -
                                  sizeof(struct iscsi_task));
index afe95674008be88104d384923129d40fda9f75e8..ca37edef27910cc188ab89a6e626ce29d6d5a344 100644 (file)
@@ -652,9 +652,13 @@ static int iser_disconnected_handler(struct rdma_cm_id *cma_id)
        /* getting here when the state is UP means that the conn is being *
         * terminated asynchronously from the iSCSI layer's perspective.  */
        if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
-                                     ISER_CONN_TERMINATING))
-               iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
-                                  ISCSI_ERR_CONN_FAILED);
+                                       ISER_CONN_TERMINATING)){
+               if (ib_conn->iser_conn)
+                       iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
+                                          ISCSI_ERR_CONN_FAILED);
+               else
+                       iser_err("iscsi_iser connection isn't bound\n");
+       }
 
        /* Complete the termination process if no posts are pending */
        if (ib_conn->post_recv_buf_count == 0 &&
index 2b161be3c1a346e3a7203a7f88a624dac4df1cee..8ee228e9ab5aa28b85ee2893a92b3ab243c35388 100644 (file)
@@ -453,6 +453,7 @@ isert_conn_create_fastreg_pool(struct isert_conn *isert_conn)
                if (ret) {
                        pr_err("Failed to create fastreg descriptor err=%d\n",
                               ret);
+                       kfree(fr_desc);
                        goto err;
                }
 
@@ -491,12 +492,11 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        isert_conn->state = ISER_CONN_INIT;
        INIT_LIST_HEAD(&isert_conn->conn_accept_node);
        init_completion(&isert_conn->conn_login_comp);
-       init_waitqueue_head(&isert_conn->conn_wait);
-       init_waitqueue_head(&isert_conn->conn_wait_comp_err);
+       init_completion(&isert_conn->conn_wait);
+       init_completion(&isert_conn->conn_wait_comp_err);
        kref_init(&isert_conn->conn_kref);
        kref_get(&isert_conn->conn_kref);
        mutex_init(&isert_conn->conn_mutex);
-       mutex_init(&isert_conn->conn_comp_mutex);
        spin_lock_init(&isert_conn->conn_lock);
 
        cma_id->context = isert_conn;
@@ -687,11 +687,11 @@ isert_disconnect_work(struct work_struct *work)
 
        pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
        mutex_lock(&isert_conn->conn_mutex);
-       isert_conn->state = ISER_CONN_DOWN;
+       if (isert_conn->state == ISER_CONN_UP)
+               isert_conn->state = ISER_CONN_TERMINATING;
 
        if (isert_conn->post_recv_buf_count == 0 &&
            atomic_read(&isert_conn->post_send_buf_count) == 0) {
-               pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
                mutex_unlock(&isert_conn->conn_mutex);
                goto wake_up;
        }
@@ -711,7 +711,7 @@ isert_disconnect_work(struct work_struct *work)
        mutex_unlock(&isert_conn->conn_mutex);
 
 wake_up:
-       wake_up(&isert_conn->conn_wait);
+       complete(&isert_conn->conn_wait);
        isert_put_conn(isert_conn);
 }
 
@@ -887,16 +887,17 @@ isert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
         * Coalesce send completion interrupts by only setting IB_SEND_SIGNALED
         * bit for every ISERT_COMP_BATCH_COUNT number of ib_post_send() calls.
         */
-       mutex_lock(&isert_conn->conn_comp_mutex);
-       if (coalesce &&
+       mutex_lock(&isert_conn->conn_mutex);
+       if (coalesce && isert_conn->state == ISER_CONN_UP &&
            ++isert_conn->conn_comp_batch < ISERT_COMP_BATCH_COUNT) {
+               tx_desc->llnode_active = true;
                llist_add(&tx_desc->comp_llnode, &isert_conn->conn_comp_llist);
-               mutex_unlock(&isert_conn->conn_comp_mutex);
+               mutex_unlock(&isert_conn->conn_mutex);
                return;
        }
        isert_conn->conn_comp_batch = 0;
        tx_desc->comp_llnode_batch = llist_del_all(&isert_conn->conn_comp_llist);
-       mutex_unlock(&isert_conn->conn_comp_mutex);
+       mutex_unlock(&isert_conn->conn_mutex);
 
        send_wr->send_flags = IB_SEND_SIGNALED;
 }
@@ -1463,7 +1464,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_SCSI_CMD:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                if (cmd->data_direction == DMA_TO_DEVICE)
@@ -1475,7 +1476,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_SCSI_TMFUNC:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                transport_generic_free_cmd(&cmd->se_cmd, 0);
@@ -1485,7 +1486,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
        case ISCSI_OP_TEXT:
                spin_lock_bh(&conn->cmd_lock);
                if (!list_empty(&cmd->i_conn_node))
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                /*
@@ -1548,6 +1549,7 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
        iscsit_stop_dataout_timer(cmd);
        device->unreg_rdma_mem(isert_cmd, isert_conn);
        cmd->write_data_done = wr->cur_rdma_length;
+       wr->send_wr_num = 0;
 
        pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
        spin_lock_bh(&cmd->istate_lock);
@@ -1588,7 +1590,7 @@ isert_do_control_comp(struct work_struct *work)
                pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
                /*
                 * Call atomic_dec(&isert_conn->post_send_buf_count)
-                * from isert_free_conn()
+                * from isert_wait_conn()
                 */
                isert_conn->logout_posted = true;
                iscsit_logout_post_handler(cmd, cmd->conn);
@@ -1612,6 +1614,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                          struct ib_device *ib_dev)
 {
        struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
+       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
 
        if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
            cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
@@ -1623,7 +1626,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                queue_work(isert_comp_wq, &isert_cmd->comp_work);
                return;
        }
-       atomic_dec(&isert_conn->post_send_buf_count);
+       atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
 
        cmd->i_state = ISTATE_SENT_STATUS;
        isert_completion_put(tx_desc, isert_cmd, ib_dev);
@@ -1661,7 +1664,7 @@ __isert_send_completion(struct iser_tx_desc *tx_desc,
        case ISER_IB_RDMA_READ:
                pr_debug("isert_send_completion: Got ISER_IB_RDMA_READ:\n");
 
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
                isert_completion_rdma_read(tx_desc, isert_cmd);
                break;
        default:
@@ -1690,31 +1693,76 @@ isert_send_completion(struct iser_tx_desc *tx_desc,
 }
 
 static void
-isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
+isert_cq_drain_comp_llist(struct isert_conn *isert_conn, struct ib_device *ib_dev)
+{
+       struct llist_node *llnode;
+       struct isert_rdma_wr *wr;
+       struct iser_tx_desc *t;
+
+       mutex_lock(&isert_conn->conn_mutex);
+       llnode = llist_del_all(&isert_conn->conn_comp_llist);
+       isert_conn->conn_comp_batch = 0;
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       while (llnode) {
+               t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+               llnode = llist_next(llnode);
+               wr = &t->isert_cmd->rdma_wr;
+
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+               isert_completion_put(t, t->isert_cmd, ib_dev);
+       }
+}
+
+static void
+isert_cq_tx_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
 {
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+       struct llist_node *llnode = tx_desc->comp_llnode_batch;
+       struct isert_rdma_wr *wr;
+       struct iser_tx_desc *t;
 
-       if (tx_desc) {
-               struct isert_cmd *isert_cmd = tx_desc->isert_cmd;
+       while (llnode) {
+               t = llist_entry(llnode, struct iser_tx_desc, comp_llnode);
+               llnode = llist_next(llnode);
+               wr = &t->isert_cmd->rdma_wr;
 
-               if (!isert_cmd)
-                       isert_unmap_tx_desc(tx_desc, ib_dev);
-               else
-                       isert_completion_put(tx_desc, isert_cmd, ib_dev);
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
+               isert_completion_put(t, t->isert_cmd, ib_dev);
        }
+       tx_desc->comp_llnode_batch = NULL;
 
-       if (isert_conn->post_recv_buf_count == 0 &&
-           atomic_read(&isert_conn->post_send_buf_count) == 0) {
-               pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-               pr_debug("Calling wake_up from isert_cq_comp_err\n");
+       if (!isert_cmd)
+               isert_unmap_tx_desc(tx_desc, ib_dev);
+       else
+               isert_completion_put(tx_desc, isert_cmd, ib_dev);
+}
 
-               mutex_lock(&isert_conn->conn_mutex);
-               if (isert_conn->state != ISER_CONN_DOWN)
-                       isert_conn->state = ISER_CONN_TERMINATING;
-               mutex_unlock(&isert_conn->conn_mutex);
+static void
+isert_cq_rx_comp_err(struct isert_conn *isert_conn)
+{
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct iscsi_conn *conn = isert_conn->conn;
 
-               wake_up(&isert_conn->conn_wait_comp_err);
+       if (isert_conn->post_recv_buf_count)
+               return;
+
+       isert_cq_drain_comp_llist(isert_conn, ib_dev);
+
+       if (conn->sess) {
+               target_sess_cmd_list_set_waiting(conn->sess->se_sess);
+               target_wait_for_sess_cmds(conn->sess->se_sess);
        }
+
+       while (atomic_read(&isert_conn->post_send_buf_count))
+               msleep(3000);
+
+       mutex_lock(&isert_conn->conn_mutex);
+       isert_conn->state = ISER_CONN_DOWN;
+       mutex_unlock(&isert_conn->conn_mutex);
+
+       complete(&isert_conn->conn_wait_comp_err);
 }
 
 static void
@@ -1739,8 +1787,14 @@ isert_cq_tx_work(struct work_struct *work)
                        pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
                        pr_debug("TX wc.status: 0x%08x\n", wc.status);
                        pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
-                       atomic_dec(&isert_conn->post_send_buf_count);
-                       isert_cq_comp_err(tx_desc, isert_conn);
+
+                       if (wc.wr_id != ISER_FASTREG_LI_WRID) {
+                               if (tx_desc->llnode_active)
+                                       continue;
+
+                               atomic_dec(&isert_conn->post_send_buf_count);
+                               isert_cq_tx_comp_err(tx_desc, isert_conn);
+                       }
                }
        }
 
@@ -1783,7 +1837,7 @@ isert_cq_rx_work(struct work_struct *work)
                                         wc.vendor_err);
                        }
                        isert_conn->post_recv_buf_count--;
-                       isert_cq_comp_err(NULL, isert_conn);
+                       isert_cq_rx_comp_err(isert_conn);
                }
        }
 
@@ -2201,6 +2255,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 
        if (!fr_desc->valid) {
                memset(&inv_wr, 0, sizeof(inv_wr));
+               inv_wr.wr_id = ISER_FASTREG_LI_WRID;
                inv_wr.opcode = IB_WR_LOCAL_INV;
                inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
                wr = &inv_wr;
@@ -2211,6 +2266,7 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 
        /* Prepare FASTREG WR */
        memset(&fr_wr, 0, sizeof(fr_wr));
+       fr_wr.wr_id = ISER_FASTREG_LI_WRID;
        fr_wr.opcode = IB_WR_FAST_REG_MR;
        fr_wr.wr.fast_reg.iova_start =
                fr_desc->data_frpl->page_list[0] + page_off;
@@ -2376,12 +2432,12 @@ isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
        isert_init_send_wr(isert_conn, isert_cmd,
                           &isert_cmd->tx_desc.send_wr, true);
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       atomic_add(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
 
        rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
        if (rc) {
                pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num + 1, &isert_conn->post_send_buf_count);
        }
        pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
                 isert_cmd);
@@ -2409,12 +2465,12 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
                return rc;
        }
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       atomic_add(wr->send_wr_num, &isert_conn->post_send_buf_count);
 
        rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
        if (rc) {
                pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+               atomic_sub(wr->send_wr_num, &isert_conn->post_send_buf_count);
        }
        pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
                 isert_cmd);
@@ -2701,22 +2757,11 @@ isert_free_np(struct iscsi_np *np)
        kfree(isert_np);
 }
 
-static int isert_check_state(struct isert_conn *isert_conn, int state)
-{
-       int ret;
-
-       mutex_lock(&isert_conn->conn_mutex);
-       ret = (isert_conn->state == state);
-       mutex_unlock(&isert_conn->conn_mutex);
-
-       return ret;
-}
-
-static void isert_free_conn(struct iscsi_conn *conn)
+static void isert_wait_conn(struct iscsi_conn *conn)
 {
        struct isert_conn *isert_conn = conn->context;
 
-       pr_debug("isert_free_conn: Starting \n");
+       pr_debug("isert_wait_conn: Starting \n");
        /*
         * Decrement post_send_buf_count for special case when called
         * from isert_do_control_comp() -> iscsit_logout_post_handler()
@@ -2726,38 +2771,29 @@ static void isert_free_conn(struct iscsi_conn *conn)
                atomic_dec(&isert_conn->post_send_buf_count);
 
        if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
-               pr_debug("Calling rdma_disconnect from isert_free_conn\n");
+               pr_debug("Calling rdma_disconnect from isert_wait_conn\n");
                rdma_disconnect(isert_conn->conn_cm_id);
        }
        /*
         * Only wait for conn_wait_comp_err if the isert_conn made it
         * into full feature phase..
         */
-       if (isert_conn->state == ISER_CONN_UP) {
-               pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
-                        isert_conn->state);
-               mutex_unlock(&isert_conn->conn_mutex);
-
-               wait_event(isert_conn->conn_wait_comp_err,
-                         (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
-
-               wait_event(isert_conn->conn_wait,
-                         (isert_check_state(isert_conn, ISER_CONN_DOWN)));
-
-               isert_put_conn(isert_conn);
-               return;
-       }
        if (isert_conn->state == ISER_CONN_INIT) {
                mutex_unlock(&isert_conn->conn_mutex);
-               isert_put_conn(isert_conn);
                return;
        }
-       pr_debug("isert_free_conn: wait_event conn_wait %d\n",
-                isert_conn->state);
+       if (isert_conn->state == ISER_CONN_UP)
+               isert_conn->state = ISER_CONN_TERMINATING;
        mutex_unlock(&isert_conn->conn_mutex);
 
-       wait_event(isert_conn->conn_wait,
-                 (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+       wait_for_completion(&isert_conn->conn_wait_comp_err);
+
+       wait_for_completion(&isert_conn->conn_wait);
+}
+
+static void isert_free_conn(struct iscsi_conn *conn)
+{
+       struct isert_conn *isert_conn = conn->context;
 
        isert_put_conn(isert_conn);
 }
@@ -2770,6 +2806,7 @@ static struct iscsit_transport iser_target_transport = {
        .iscsit_setup_np        = isert_setup_np,
        .iscsit_accept_np       = isert_accept_np,
        .iscsit_free_np         = isert_free_np,
+       .iscsit_wait_conn       = isert_wait_conn,
        .iscsit_free_conn       = isert_free_conn,
        .iscsit_get_login_rx    = isert_get_login_rx,
        .iscsit_put_login_tx    = isert_put_login_tx,
index 708a069002f3530e00002c5d1e454c1823119bb4..f6ae7f5dd4082768f3b6f0dfb36c1d45506b5eb6 100644 (file)
@@ -6,6 +6,7 @@
 
 #define ISERT_RDMA_LISTEN_BACKLOG      10
 #define ISCSI_ISER_SG_TABLESIZE                256
+#define ISER_FASTREG_LI_WRID           0xffffffffffffffffULL
 
 enum isert_desc_type {
        ISCSI_TX_CONTROL,
@@ -45,6 +46,7 @@ struct iser_tx_desc {
        struct isert_cmd *isert_cmd;
        struct llist_node *comp_llnode_batch;
        struct llist_node comp_llnode;
+       bool            llnode_active;
        struct ib_send_wr send_wr;
 } __packed;
 
@@ -116,8 +118,8 @@ struct isert_conn {
        struct isert_device     *conn_device;
        struct work_struct      conn_logout_work;
        struct mutex            conn_mutex;
-       wait_queue_head_t       conn_wait;
-       wait_queue_head_t       conn_wait_comp_err;
+       struct completion       conn_wait;
+       struct completion       conn_wait_comp_err;
        struct kref             conn_kref;
        struct list_head        conn_fr_pool;
        int                     conn_fr_pool_size;
@@ -126,7 +128,6 @@ struct isert_conn {
 #define ISERT_COMP_BATCH_COUNT 8
        int                     conn_comp_batch;
        struct llist_head       conn_comp_llist;
-       struct mutex            conn_comp_mutex;
 };
 
 #define ISERT_MAX_CQ 64
index 520a7e5a490b1b61042cad7acead955bbed2b759..0e537d8d0e4774312d632f68f0cedd0aaa406b7d 100644 (file)
@@ -3666,9 +3666,9 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size(
        unsigned long val;
        int ret;
 
-       ret = strict_strtoul(page, 0, &val);
+       ret = kstrtoul(page, 0, &val);
        if (ret < 0) {
-               pr_err("strict_strtoul() failed with ret: %d\n", ret);
+               pr_err("kstrtoul() failed with ret: %d\n", ret);
                return -EINVAL;
        }
        if (val > MAX_SRPT_RDMA_SIZE) {
@@ -3706,9 +3706,9 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size(
        unsigned long val;
        int ret;
 
-       ret = strict_strtoul(page, 0, &val);
+       ret = kstrtoul(page, 0, &val);
        if (ret < 0) {
-               pr_err("strict_strtoul() failed with ret: %d\n", ret);
+               pr_err("kstrtoul() failed with ret: %d\n", ret);
                return -EINVAL;
        }
        if (val > MAX_SRPT_RSP_SIZE) {
@@ -3746,9 +3746,9 @@ static ssize_t srpt_tpg_attrib_store_srp_sq_size(
        unsigned long val;
        int ret;
 
-       ret = strict_strtoul(page, 0, &val);
+       ret = kstrtoul(page, 0, &val);
        if (ret < 0) {
-               pr_err("strict_strtoul() failed with ret: %d\n", ret);
+               pr_err("kstrtoul() failed with ret: %d\n", ret);
                return -EINVAL;
        }
        if (val > MAX_SRPT_SRQ_SIZE) {
@@ -3793,7 +3793,7 @@ static ssize_t srpt_tpg_store_enable(
        unsigned long tmp;
         int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                printk(KERN_ERR "Unable to extract srpt_tpg_store_enable\n");
                return -EINVAL;
index bb3b57bea8ba4578df5d29c72230882ac29bd62a..5ef7fcf0e2509b8196cf69a993247febae4c20b7 100644 (file)
@@ -76,8 +76,18 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned off)
        struct adp5588_kpad *kpad = container_of(chip, struct adp5588_kpad, gc);
        unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
        unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
+       int val;
 
-       return !!(adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank) & bit);
+       mutex_lock(&kpad->gpio_lock);
+
+       if (kpad->dir[bank] & bit)
+               val = kpad->dat_out[bank];
+       else
+               val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
+
+       mutex_unlock(&kpad->gpio_lock);
+
+       return !!(val & bit);
 }
 
 static void adp5588_gpio_set_value(struct gpio_chip *chip,
index 7a04f54ef961fda20385251413fdee4490669ef6..ef2e281b0a43b641a1dbc6f5dd7fcb9190477d24 100644 (file)
@@ -37,7 +37,6 @@ static void arizona_haptics_work(struct work_struct *work)
                                                       struct arizona_haptics,
                                                       work);
        struct arizona *arizona = haptics->arizona;
-       struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex;
        int ret;
 
        if (!haptics->arizona->dapm) {
@@ -67,13 +66,10 @@ static void arizona_haptics_work(struct work_struct *work)
                        return;
                }
 
-               mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
                ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
 
@@ -81,21 +77,14 @@ static void arizona_haptics_work(struct work_struct *work)
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
-
-               mutex_unlock(dapm_mutex);
-
        } else {
                /* This disable sequence will be a noop if already enabled */
-               mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
                ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
 
@@ -103,12 +92,9 @@ static void arizona_haptics_work(struct work_struct *work)
                if (ret != 0) {
                        dev_err(arizona->dev, "Failed to sync DAPM: %d\n",
                                ret);
-                       mutex_unlock(dapm_mutex);
                        return;
                }
 
-               mutex_unlock(dapm_mutex);
-
                ret = regmap_update_bits(arizona->regmap,
                                         ARIZONA_HAPTICS_CONTROL_1,
                                         ARIZONA_HAP_CTRL_MASK,
@@ -155,16 +141,11 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
 static void arizona_haptics_close(struct input_dev *input)
 {
        struct arizona_haptics *haptics = input_get_drvdata(input);
-       struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex;
 
        cancel_work_sync(&haptics->work);
 
-       mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
        if (haptics->arizona->dapm)
                snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS");
-
-       mutex_unlock(dapm_mutex);
 }
 
 static int arizona_haptics_probe(struct platform_device *pdev)
index 1f695f229ea8988001da801bb60db7b6d939f293..184c8f21ab59a9736feb262f79331cae878af1ff 100644 (file)
@@ -27,29 +27,32 @@ struct da9052_onkey {
 
 static void da9052_onkey_query(struct da9052_onkey *onkey)
 {
-       int key_stat;
+       int ret;
 
-       key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
-       if (key_stat < 0) {
+       ret = da9052_reg_read(onkey->da9052, DA9052_STATUS_A_REG);
+       if (ret < 0) {
                dev_err(onkey->da9052->dev,
-                       "Failed to read onkey event %d\n", key_stat);
+                       "Failed to read onkey event err=%d\n", ret);
        } else {
                /*
                 * Since interrupt for deassertion of ONKEY pin is not
                 * generated, onkey event state determines the onkey
                 * button state.
                 */
-               key_stat &= DA9052_EVENTB_ENONKEY;
-               input_report_key(onkey->input, KEY_POWER, key_stat);
+               bool pressed = !(ret & DA9052_STATUSA_NONKEY);
+
+               input_report_key(onkey->input, KEY_POWER, pressed);
                input_sync(onkey->input);
-       }
 
-       /*
-        * Interrupt is generated only when the ONKEY pin is asserted.
-        * Hence the deassertion of the pin is simulated through work queue.
-        */
-       if (key_stat)
-               schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
+               /*
+                * Interrupt is generated only when the ONKEY pin
+                * is asserted.  Hence the deassertion of the pin
+                * is simulated through work queue.
+                */
+               if (pressed)
+                       schedule_delayed_work(&onkey->work,
+                                               msecs_to_jiffies(50));
+       }
 }
 
 static void da9052_onkey_work(struct work_struct *work)
index 87095e2f5153c7dedeae38a18cd10efaa62a9e0c..8af34ffe208b16eff1ab240de45967fb84b6610f 100644 (file)
@@ -409,7 +409,6 @@ static int cypress_set_input_params(struct input_dev *input,
        __clear_bit(REL_X, input->relbit);
        __clear_bit(REL_Y, input->relbit);
 
-       __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
        __set_bit(EV_KEY, input->evbit);
        __set_bit(BTN_LEFT, input->keybit);
        __set_bit(BTN_RIGHT, input->keybit);
index 26386f9d25696841584f4b7f698a3cc8727fdc54..d8d49d10f9bb60d477124bba603fb9f61be1efdb 100644 (file)
@@ -265,11 +265,22 @@ static int synaptics_identify(struct psmouse *psmouse)
  * Read touchpad resolution and maximum reported coordinates
  * Resolution is left zero if touchpad does not support the query
  */
+
+static const int *quirk_min_max;
+
 static int synaptics_resolution(struct psmouse *psmouse)
 {
        struct synaptics_data *priv = psmouse->private;
        unsigned char resp[3];
 
+       if (quirk_min_max) {
+               priv->x_min = quirk_min_max[0];
+               priv->x_max = quirk_min_max[1];
+               priv->y_min = quirk_min_max[2];
+               priv->y_max = quirk_min_max[3];
+               return 0;
+       }
+
        if (SYN_ID_MAJOR(priv->identity) < 4)
                return 0;
 
@@ -1485,10 +1496,54 @@ static const struct dmi_system_id olpc_dmi_table[] __initconst = {
        { }
 };
 
+static const struct dmi_system_id min_max_dmi_table[] __initconst = {
+#if defined(CONFIG_DMI)
+       {
+               /* Lenovo ThinkPad Helix */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Helix"),
+               },
+               .driver_data = (int []){1024, 5052, 2258, 4832},
+       },
+       {
+               /* Lenovo ThinkPad X240 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X240"),
+               },
+               .driver_data = (int []){1232, 5710, 1156, 4696},
+       },
+       {
+               /* Lenovo ThinkPad T440s */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T440"),
+               },
+               .driver_data = (int []){1024, 5112, 2024, 4832},
+       },
+       {
+               /* Lenovo ThinkPad T540p */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T540"),
+               },
+               .driver_data = (int []){1024, 5056, 2058, 4832},
+       },
+#endif
+       { }
+};
+
 void __init synaptics_module_init(void)
 {
+       const struct dmi_system_id *min_max_dmi;
+
        impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table);
        broken_olpc_ec = dmi_check_system(olpc_dmi_table);
+
+       min_max_dmi = dmi_first_match(min_max_dmi_table);
+       if (min_max_dmi)
+               quirk_min_max = min_max_dmi->driver_data;
 }
 
 static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
index 8911850c94445fa5adf3b41de168293e5adf7721..1d9ab39af29f7c5d6ab2504fd2403ff725358a5d 100644 (file)
@@ -79,7 +79,6 @@
 
 #define ARM_SMMU_PTE_CONT_SIZE         (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
 #define ARM_SMMU_PTE_CONT_MASK         (~(ARM_SMMU_PTE_CONT_SIZE - 1))
-#define ARM_SMMU_PTE_HWTABLE_SIZE      (PTRS_PER_PTE * sizeof(pte_t))
 
 /* Stage-1 PTE */
 #define ARM_SMMU_PTE_AP_UNPRIV         (((pteval_t)1) << 6)
 #define ARM_SMMU_GR1_CBAR(n)           (0x0 + ((n) << 2))
 #define CBAR_VMID_SHIFT                        0
 #define CBAR_VMID_MASK                 0xff
+#define CBAR_S1_BPSHCFG_SHIFT          8
+#define CBAR_S1_BPSHCFG_MASK           3
+#define CBAR_S1_BPSHCFG_NSH            3
 #define CBAR_S1_MEMATTR_SHIFT          12
 #define CBAR_S1_MEMATTR_MASK           0xf
 #define CBAR_S1_MEMATTR_WB             0xf
@@ -393,7 +395,7 @@ struct arm_smmu_domain {
        struct arm_smmu_cfg             root_cfg;
        phys_addr_t                     output_mask;
 
-       struct mutex                    lock;
+       spinlock_t                      lock;
 };
 
 static DEFINE_SPINLOCK(arm_smmu_devices_lock);
@@ -632,6 +634,28 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+                                  size_t size)
+{
+       unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+
+       /* Ensure new page tables are visible to the hardware walker */
+       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) {
+               dsb();
+       } else {
+               /*
+                * If the SMMU can't walk tables in the CPU caches, treat them
+                * like non-coherent DMA since we need to flush the new entries
+                * all the way out to memory. There's no possibility of
+                * recursion here as the SMMU table walker will not be wired
+                * through another SMMU.
+                */
+               dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+                               DMA_TO_DEVICE);
+       }
+}
+
 static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
 {
        u32 reg;
@@ -650,11 +674,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        if (smmu->version == 1)
              reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
 
-       /* Use the weakest memory type, so it is overridden by the pte */
-       if (stage1)
-               reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
-       else
+       /*
+        * Use the weakest shareability/memory types, so they are
+        * overridden by the ttbcr/pte.
+        */
+       if (stage1) {
+               reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) |
+                       (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+       } else {
                reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
+       }
        writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
 
        if (smmu->version > 1) {
@@ -715,6 +744,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        }
 
        /* TTBR0 */
+       arm_smmu_flush_pgtable(smmu, root_cfg->pgd,
+                              PTRS_PER_PGD * sizeof(pgd_t));
        reg = __pa(root_cfg->pgd);
        writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
        reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
@@ -901,7 +932,7 @@ static int arm_smmu_domain_init(struct iommu_domain *domain)
                goto out_free_domain;
        smmu_domain->root_cfg.pgd = pgd;
 
-       mutex_init(&smmu_domain->lock);
+       spin_lock_init(&smmu_domain->lock);
        domain->priv = smmu_domain;
        return 0;
 
@@ -1128,6 +1159,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        struct arm_smmu_domain *smmu_domain = domain->priv;
        struct arm_smmu_device *device_smmu = dev->archdata.iommu;
        struct arm_smmu_master *master;
+       unsigned long flags;
 
        if (!device_smmu) {
                dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
@@ -1138,7 +1170,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
         * Sanity check the domain. We don't currently support domains
         * that cross between different SMMU chains.
         */
-       mutex_lock(&smmu_domain->lock);
+       spin_lock_irqsave(&smmu_domain->lock, flags);
        if (!smmu_domain->leaf_smmu) {
                /* Now that we have a master, we can finalise the domain */
                ret = arm_smmu_init_domain_context(domain, dev);
@@ -1153,7 +1185,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
                        dev_name(device_smmu->dev));
                goto err_unlock;
        }
-       mutex_unlock(&smmu_domain->lock);
+       spin_unlock_irqrestore(&smmu_domain->lock, flags);
 
        /* Looks ok, so add the device to the domain */
        master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
@@ -1163,7 +1195,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
        return arm_smmu_domain_add_master(smmu_domain, master);
 
 err_unlock:
-       mutex_unlock(&smmu_domain->lock);
+       spin_unlock_irqrestore(&smmu_domain->lock, flags);
        return ret;
 }
 
@@ -1177,23 +1209,6 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
                arm_smmu_domain_remove_master(smmu_domain, master);
 }
 
-static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
-                                  size_t size)
-{
-       unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
-
-       /*
-        * If the SMMU can't walk tables in the CPU caches, treat them
-        * like non-coherent DMA since we need to flush the new entries
-        * all the way out to memory. There's no possibility of recursion
-        * here as the SMMU table walker will not be wired through another
-        * SMMU.
-        */
-       if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
-               dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
-                            DMA_TO_DEVICE);
-}
-
 static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
                                             unsigned long end)
 {
@@ -1210,12 +1225,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
 
        if (pmd_none(*pmd)) {
                /* Allocate a new set of tables */
-               pgtable_t table = alloc_page(PGALLOC_GFP);
+               pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO);
                if (!table)
                        return -ENOMEM;
 
-               arm_smmu_flush_pgtable(smmu, page_address(table),
-                                      ARM_SMMU_PTE_HWTABLE_SIZE);
+               arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE);
                if (!pgtable_page_ctor(table)) {
                        __free_page(table);
                        return -ENOMEM;
@@ -1317,9 +1331,15 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
 
 #ifndef __PAGETABLE_PMD_FOLDED
        if (pud_none(*pud)) {
-               pmd = pmd_alloc_one(NULL, addr);
+               pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
                if (!pmd)
                        return -ENOMEM;
+
+               arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE);
+               pud_populate(NULL, pud, pmd);
+               arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+
+               pmd += pmd_index(addr);
        } else
 #endif
                pmd = pmd_offset(pud, addr);
@@ -1328,8 +1348,6 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
                next = pmd_addr_end(addr, end);
                ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
                                              flags, stage);
-               pud_populate(NULL, pud, pmd);
-               arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
                phys += next - addr;
        } while (pmd++, addr = next, addr < end);
 
@@ -1346,9 +1364,15 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
 
 #ifndef __PAGETABLE_PUD_FOLDED
        if (pgd_none(*pgd)) {
-               pud = pud_alloc_one(NULL, addr);
+               pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
                if (!pud)
                        return -ENOMEM;
+
+               arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE);
+               pgd_populate(NULL, pgd, pud);
+               arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+
+               pud += pud_index(addr);
        } else
 #endif
                pud = pud_offset(pgd, addr);
@@ -1357,8 +1381,6 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
                next = pud_addr_end(addr, end);
                ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
                                              flags, stage);
-               pgd_populate(NULL, pud, pgd);
-               arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
                phys += next - addr;
        } while (pud++, addr = next, addr < end);
 
@@ -1375,6 +1397,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
        pgd_t *pgd = root_cfg->pgd;
        struct arm_smmu_device *smmu = root_cfg->smmu;
+       unsigned long irqflags;
 
        if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
                stage = 2;
@@ -1397,7 +1420,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        if (paddr & ~output_mask)
                return -ERANGE;
 
-       mutex_lock(&smmu_domain->lock);
+       spin_lock_irqsave(&smmu_domain->lock, irqflags);
        pgd += pgd_index(iova);
        end = iova + size;
        do {
@@ -1413,11 +1436,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
        } while (pgd++, iova != end);
 
 out_unlock:
-       mutex_unlock(&smmu_domain->lock);
-
-       /* Ensure new page tables are visible to the hardware walker */
-       if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
-               dsb();
+       spin_unlock_irqrestore(&smmu_domain->lock, irqflags);
 
        return ret;
 }
@@ -1987,8 +2006,10 @@ static int __init arm_smmu_init(void)
        if (!iommu_present(&platform_bus_type))
                bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
 
+#ifdef CONFIG_ARM_AMBA
        if (!iommu_present(&amba_bustype))
                bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+#endif
 
        return 0;
 }
index d97fbe4fb9b1358f0f7bea574edd6c8cd73502df..80fffba7f12dfd77dcff90d06a9783613d131827 100644 (file)
@@ -354,8 +354,8 @@ DEBUG_FOPS(mem);
                        return -ENOMEM;                                 \
        }
 
-#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
-#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 0600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400)
 
 static int iommu_debug_register(struct device *dev, void *data)
 {
index 92c41ab4dbfd619b5458338c3e6b6563019b150c..2cb474ad8809faa2fadaf5b08a7b06b087e73794 100644 (file)
@@ -515,7 +515,7 @@ static int meta_intc_set_affinity(struct irq_data *data,
         * one cpu (the interrupt code doesn't support it), so we just
         * pick the first cpu we find in 'cpumask'.
         */
-       cpu = cpumask_any(cpumask);
+       cpu = cpumask_any_and(cpumask, cpu_online_mask);
        thread = cpu_2_hwthread_id[cpu];
 
        metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr);
index 8e94d7a3b20d277d127adf15441ea0b53879c606..c16c186d97d35f4246fa2acbd17942789922d6d7 100644 (file)
@@ -201,7 +201,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data,
         * one cpu (the interrupt code doesn't support it), so we just
         * pick the first cpu we find in 'cpumask'.
         */
-       cpu = cpumask_any(cpumask);
+       cpu = cpumask_any_and(cpumask, cpu_online_mask);
        thread = cpu_2_hwthread_id[cpu];
 
        metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)),
index e51d40031884b1d75f12d659e2f040f391a7ad73..8e41be62812e1663df05b58f75c52ecfdc7b844f 100644 (file)
@@ -111,7 +111,8 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);
 static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
        struct irq_domain *d = irq_get_handler_data(irq);
-       struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq);
+
+       struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
        u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
                   gc->mask_cache;
 
@@ -123,6 +124,19 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
        }
 }
 
+/*
+ * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register.
+ * To avoid interrupt events on stale irqs, we clear them before unmask.
+ */
+static unsigned int orion_bridge_irq_startup(struct irq_data *d)
+{
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
+       ct->chip.irq_ack(d);
+       ct->chip.irq_unmask(d);
+       return 0;
+}
+
 static int __init orion_bridge_irq_init(struct device_node *np,
                                        struct device_node *parent)
 {
@@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np,
        }
 
        ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name,
-                            handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
+                            handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE);
        if (ret) {
                pr_err("%s: unable to alloc irq domain gc\n", np->name);
                return ret;
@@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np,
 
        gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE;
        gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK;
+       gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup;
        gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit;
        gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
        gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
 
-       /* mask all interrupts */
+       /* mask and clear all interrupts */
        writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK);
+       writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE);
 
        irq_set_handler_data(irq, domain);
        irq_set_chained_handler(irq, orion_bridge_irq_handler);
index b4147c0b14b79e40de0a0c613fce54fdffcc5976..c3a1b061838da5f5b42aee00f5087e1e11c87b71 100644 (file)
@@ -796,7 +796,7 @@ static void __exit act2000_exit(void)
        act2000_card *last;
        while (card) {
                unregister_card(card);
-               del_timer(&card->ptimer);
+               del_timer_sync(&card->ptimer);
                card = card->next;
        }
        card = cards;
index f046865800405664ae73ec6dc761635327b7b55a..9816c51eb5c240be8c19b9c26bbd25d50fbca652 100644 (file)
@@ -16,9 +16,17 @@ config CAPI_TRACE
          This will increase the size of the kernelcapi module by 20 KB.
          If unsure, say Y.
 
+config ISDN_CAPI_CAPI20
+       tristate "CAPI2.0 /dev/capi support"
+       help
+         This option will provide the CAPI 2.0 interface to userspace
+         applications via /dev/capi20. Applications should use the
+         standardized libcapi20 to access this functionality.  You should say
+         Y/M here.
+
 config ISDN_CAPI_MIDDLEWARE
        bool "CAPI2.0 Middleware support"
-       depends on TTY
+       depends on ISDN_CAPI_CAPI20 && TTY
        help
          This option will enhance the capabilities of the /dev/capi20
          interface.  It will provide a means of moving a data connection,
@@ -26,14 +34,6 @@ config ISDN_CAPI_MIDDLEWARE
          device.  If you want to use pppd with pppdcapiplugin to dial up to
          your ISP, say Y here.
 
-config ISDN_CAPI_CAPI20
-       tristate "CAPI2.0 /dev/capi support"
-       help
-         This option will provide the CAPI 2.0 interface to userspace
-         applications via /dev/capi20. Applications should use the
-         standardized libcapi20 to access this functionality.  You should say
-         Y/M here.
-
 config ISDN_CAPI_CAPIDRV
        tristate "CAPI2.0 capidrv interface support"
        depends on ISDN_I4L
index fb4f1bac0133faa6783b252432fd7ecfdafc3343..1c5dc345e7c50fe07196b5dc2b4963e4d9207b0b 100644 (file)
@@ -86,12 +86,13 @@ isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off)
        struct divert_info *inf;
        int len;
 
-       if (!*((struct divert_info **) file->private_data)) {
+       if (!(inf = *((struct divert_info **) file->private_data))) {
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
-               interruptible_sleep_on(&(rd_queue));
+               wait_event_interruptible(rd_queue, (inf =
+                       *((struct divert_info **) file->private_data)));
        }
-       if (!(inf = *((struct divert_info **) file->private_data)))
+       if (!inf)
                return (0);
 
        inf->usage_cnt--;       /* new usage count */
index 2be1c8a3bb5f2b7fd84f0d3cd039fb8dc5da3dd0..d8ef64da26f1fe6e0a25c5515401079ed19ff3cb 100644 (file)
@@ -509,7 +509,8 @@ static void
 set_arcofi(struct IsdnCardState *cs, int bc) {
        cs->dc.isac.arcofi_bc = bc;
        arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5);
-       interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+       wait_event_interruptible(cs->dc.isac.arcofi_wait,
+                                cs->dc.isac.arcofi_state == ARCOFI_NOP);
 }
 
 static int
@@ -528,7 +529,8 @@ check_arcofi(struct IsdnCardState *cs)
                }
        cs->dc.isac.arcofi_bc = 0;
        arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION);
-       interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+       wait_event_interruptible(cs->dc.isac.arcofi_wait,
+                                cs->dc.isac.arcofi_state == ARCOFI_NOP);
        if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) {
                debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp);
                p = cs->dc.isac.mon_rx;
@@ -595,7 +597,8 @@ check_arcofi(struct IsdnCardState *cs)
                               Elsa_Types[cs->subtyp],
                               cs->hw.elsa.base + 8);
                arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0);
-               interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
+               wait_event_interruptible(cs->dc.isac.arcofi_wait,
+                                cs->dc.isac.arcofi_state == ARCOFI_NOP);
                return (1);
        }
        return (0);
index 3f84dd8f1757d8b645af7bf6b3088b7ce084d320..a2a358c1dc8e59fe5b69f99891c8d3130717df8b 100644 (file)
@@ -573,7 +573,8 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
                test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag);
                bcs->cs->dc.isac.arcofi_bc = st->l1.bc;
                arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0);
-               interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait);
+               wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait,
+                                bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP);
                bcs->cs->hw.elsa.MFlag = 1;
        } else {
                printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr);
index af1b020a81f1814eb28b8fea83fca30b3b4332fc..b420f8bd862e454df2cc08f4da84b8bc7ef76e57 100644 (file)
@@ -810,7 +810,7 @@ prfeatureind(char *dest, u_char *p)
        dp += sprintf(dp, "    octet 3  ");
        dp += prbits(dp, *p, 8, 8);
        *dp++ = '\n';
-       if (!(*p++ & 80)) {
+       if (!(*p++ & 0x80)) {
                dp += sprintf(dp, "    octet 4  ");
                dp += prbits(dp, *p++, 8, 8);
                *dp++ = '\n';
index b61e8d5e84ad022e566f5bfa191ddcb392f3df7b..7b5fd8fb1761d1912be615ee14571e420dc4c92b 100644 (file)
@@ -175,14 +175,15 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off)
        int len;
        hysdn_card *card = PDE_DATA(file_inode(file));
 
-       if (!*((struct log_data **) file->private_data)) {
+       if (!(inf = *((struct log_data **) file->private_data))) {
                struct procdata *pd = card->proclog;
                if (file->f_flags & O_NONBLOCK)
                        return (-EAGAIN);
 
-               interruptible_sleep_on(&(pd->rd_queue));
+               wait_event_interruptible(pd->rd_queue, (inf =
+                               *((struct log_data **) file->private_data)));
        }
-       if (!(inf = *((struct log_data **) file->private_data)))
+       if (!inf)
                return (0);
 
        inf->usage_cnt--;       /* new usage count */
index 9bb12ba3191fbdac568f9352f77dc05b66d051cc..9b856e1890d1ebc4f7c82ebb6b045357abe5324b 100644 (file)
@@ -777,7 +777,8 @@ isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue
                return 0;
        if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) {
                if (sleep)
-                       interruptible_sleep_on(sleep);
+                       wait_event_interruptible(*sleep,
+                               !skb_queue_empty(&dev->drv[di]->rpqueue[channel]));
                else
                        return 0;
        }
@@ -1072,7 +1073,8 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
                                retval = -EAGAIN;
                                goto out;
                        }
-                       interruptible_sleep_on(&(dev->info_waitq));
+                       wait_event_interruptible(dev->info_waitq,
+                                                file->private_data);
                }
                p = isdn_statstr();
                file->private_data = NULL;
@@ -1128,7 +1130,8 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off)
                                retval = -EAGAIN;
                                goto out;
                        }
-                       interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+                       wait_event_interruptible(dev->drv[drvidx]->st_waitq,
+                                                dev->drv[drvidx]->stavail);
                }
                if (dev->drv[drvidx]->interface->readstat) {
                        if (count > dev->drv[drvidx]->stavail)
@@ -1188,8 +1191,8 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
                        goto out;
                }
                chidx = isdn_minor2chan(minor);
-               while ((retval = isdn_writebuf_stub(drvidx, chidx, buf, count)) == 0)
-                       interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
+               wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
+                       (retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
                goto out;
        }
        if (minor <= ISDN_MINOR_CTRLMAX) {
@@ -2378,7 +2381,7 @@ static void __exit isdn_exit(void)
        }
        isdn_tty_exit();
        unregister_chrdev(ISDN_MAJOR, "isdn");
-       del_timer(&dev->timer);
+       del_timer_sync(&dev->timer);
        /* call vfree with interrupts enabled, else it will hang */
        vfree(dev);
        printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
index 38ceac5053a0ba79df766c16889cf5f384b582f4..a5da511e3c9ae4f381ae1526d2ab2779039aba9a 100644 (file)
@@ -378,10 +378,15 @@ isdn_ppp_release(int min, struct file *file)
        is->slcomp = NULL;
 #endif
 #ifdef CONFIG_IPPP_FILTER
-       kfree(is->pass_filter);
-       is->pass_filter = NULL;
-       kfree(is->active_filter);
-       is->active_filter = NULL;
+       if (is->pass_filter) {
+               sk_unattached_filter_destroy(is->pass_filter);
+               is->pass_filter = NULL;
+       }
+
+       if (is->active_filter) {
+               sk_unattached_filter_destroy(is->active_filter);
+               is->active_filter = NULL;
+       }
 #endif
 
 /* TODO: if this was the previous master: link the stuff to the new master */
@@ -629,25 +634,41 @@ isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
 #ifdef CONFIG_IPPP_FILTER
        case PPPIOCSPASS:
        {
+               struct sock_fprog fprog;
                struct sock_filter *code;
-               int len = get_filter(argp, &code);
+               int err, len = get_filter(argp, &code);
+
                if (len < 0)
                        return len;
-               kfree(is->pass_filter);
-               is->pass_filter = code;
-               is->pass_len = len;
-               break;
+
+               fprog.len = len;
+               fprog.filter = code;
+
+               if (is->pass_filter)
+                       sk_unattached_filter_destroy(is->pass_filter);
+               err = sk_unattached_filter_create(&is->pass_filter, &fprog);
+               kfree(code);
+
+               return err;
        }
        case PPPIOCSACTIVE:
        {
+               struct sock_fprog fprog;
                struct sock_filter *code;
-               int len = get_filter(argp, &code);
+               int err, len = get_filter(argp, &code);
+
                if (len < 0)
                        return len;
-               kfree(is->active_filter);
-               is->active_filter = code;
-               is->active_len = len;
-               break;
+
+               fprog.len = len;
+               fprog.filter = code;
+
+               if (is->active_filter)
+                       sk_unattached_filter_destroy(is->active_filter);
+               err = sk_unattached_filter_create(&is->active_filter, &fprog);
+               kfree(code);
+
+               return err;
        }
 #endif /* CONFIG_IPPP_FILTER */
        default:
@@ -1147,14 +1168,14 @@ isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *
        }
 
        if (is->pass_filter
-           && sk_run_filter(skb, is->pass_filter) == 0) {
+           && SK_RUN_FILTER(is->pass_filter, skb) == 0) {
                if (is->debug & 0x2)
                        printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
                kfree_skb(skb);
                return;
        }
        if (!(is->active_filter
-             && sk_run_filter(skb, is->active_filter) == 0)) {
+             && SK_RUN_FILTER(is->active_filter, skb) == 0)) {
                if (is->debug & 0x2)
                        printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
                lp->huptimer = 0;
@@ -1293,14 +1314,14 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev)
        }
 
        if (ipt->pass_filter
-           && sk_run_filter(skb, ipt->pass_filter) == 0) {
+           && SK_RUN_FILTER(ipt->pass_filter, skb) == 0) {
                if (ipt->debug & 0x4)
                        printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
                kfree_skb(skb);
                goto unlock;
        }
        if (!(ipt->active_filter
-             && sk_run_filter(skb, ipt->active_filter) == 0)) {
+             && SK_RUN_FILTER(ipt->active_filter, skb) == 0)) {
                if (ipt->debug & 0x4)
                        printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n");
                lp->huptimer = 0;
@@ -1490,9 +1511,9 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
        }
 
        drop |= is->pass_filter
-               && sk_run_filter(skb, is->pass_filter) == 0;
+               && SK_RUN_FILTER(is->pass_filter, skb) == 0;
        drop |= is->active_filter
-               && sk_run_filter(skb, is->active_filter) == 0;
+               && SK_RUN_FILTER(is->active_filter, skb) == 0;
 
        skb_push(skb, IPPP_MAX_HEADER - 4);
        return drop;
index 1eaf622739037dc26960f4b3d2ae5ba165830d21..f02cc506fbfa795938fc9dcdfa6e8931df734575 100644 (file)
@@ -796,6 +796,7 @@ static void set_running_timeout(unsigned long ptr)
 #endif
        dev = (struct pcbit_dev *) ptr;
 
+       dev->l2_state = L2_DOWN;
        wake_up_interruptible(&dev->set_running_wq);
 }
 
@@ -818,7 +819,8 @@ static int set_protocol_running(struct pcbit_dev *dev)
 
        add_timer(&dev->set_running_timer);
 
-       interruptible_sleep_on(&dev->set_running_wq);
+       wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING ||
+                                       dev->l2_state == L2_DOWN);
 
        del_timer(&dev->set_running_timer);
 
@@ -842,8 +844,6 @@ static int set_protocol_running(struct pcbit_dev *dev)
                printk(KERN_DEBUG "pcbit: initialization failed\n");
                printk(KERN_DEBUG "pcbit: firmware not loaded\n");
 
-               dev->l2_state = L2_DOWN;
-
 #ifdef DEBUG
                printk(KERN_DEBUG "Bank3 = %02x\n",
                       readb(dev->sh_mem + BANK3));
index 92acc81f844d161a7e47d9477c2e49e941929d58..d6f19b168e8a1a6101fd11dea5de140eed90dffb 100644 (file)
@@ -390,8 +390,8 @@ static void __exit sc_exit(void)
                /*
                 * kill the timers
                 */
-               del_timer(&(sc_adapter[i]->reset_timer));
-               del_timer(&(sc_adapter[i]->stat_timer));
+               del_timer_sync(&(sc_adapter[i]->reset_timer));
+               del_timer_sync(&(sc_adapter[i]->stat_timer));
 
                /*
                 * Tell I4L we're toast
index 9a06fe8837666036fe04afbde6d5e2adf8de6256..95ad936e60482477c1f87c0aa654fded90d06ba5 100644 (file)
@@ -254,16 +254,6 @@ config DM_THIN_PROVISIONING
        ---help---
          Provides thin provisioning and snapshots that share a data store.
 
-config DM_DEBUG_BLOCK_STACK_TRACING
-       boolean "Keep stack trace of persistent data block lock holders"
-       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
-       select STACKTRACE
-       ---help---
-         Enable this for messages that may help debug problems with the
-         block manager locking used by thin provisioning and caching.
-
-         If unsure, say N.
-
 config DM_CACHE
        tristate "Cache target (EXPERIMENTAL)"
        depends on BLK_DEV_DM
index 0c707e4f4eafc32adcdb3fec5539b2dbe0998a7a..a4c7306ff43de4f1a928962251ffaea384dcb287 100644 (file)
@@ -210,7 +210,9 @@ BITMASK(GC_MARK,     struct bucket, gc_mark, 0, 2);
 #define GC_MARK_RECLAIMABLE    0
 #define GC_MARK_DIRTY          1
 #define GC_MARK_METADATA       2
-BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, 13);
+#define GC_SECTORS_USED_SIZE   13
+#define MAX_GC_SECTORS_USED    (~(~0ULL << GC_SECTORS_USED_SIZE))
+BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, GC_SECTORS_USED_SIZE);
 BITMASK(GC_MOVE, struct bucket, gc_mark, 15, 1);
 
 #include "journal.h"
index 4f6b5940e609b4f53c248bf65762ef8f99c7258c..3f74b4b0747b9fec3fcb7ad02cfed9ff1baa2f63 100644 (file)
@@ -23,7 +23,7 @@ void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set)
        for (k = i->start; k < bset_bkey_last(i); k = next) {
                next = bkey_next(k);
 
-               printk(KERN_ERR "block %u key %zi/%u: ", set,
+               printk(KERN_ERR "block %u key %li/%u: ", set,
                       (uint64_t *) k - i->d, i->keys);
 
                if (b->ops->key_dump)
@@ -1185,9 +1185,12 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter,
        struct bset *out = (void *) __get_free_pages(__GFP_NOWARN|GFP_NOIO,
                                                     order);
        if (!out) {
+               struct page *outp;
+
                BUG_ON(order > state->page_order);
 
-               out = page_address(mempool_alloc(state->pool, GFP_NOIO));
+               outp = mempool_alloc(state->pool, GFP_NOIO);
+               out = page_address(outp);
                used_mempool = true;
                order = state->page_order;
        }
index 98cc0a810a366a466253d250baba5c2564e9fab7..5f9c2a665ca5079bd372646f70de2117a77b995a 100644 (file)
@@ -1167,7 +1167,7 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
                /* guard against overflow */
                SET_GC_SECTORS_USED(g, min_t(unsigned,
                                             GC_SECTORS_USED(g) + KEY_SIZE(k),
-                                            (1 << 14) - 1));
+                                            MAX_GC_SECTORS_USED));
 
                BUG_ON(!GC_SECTORS_USED(g));
        }
@@ -1805,7 +1805,7 @@ static bool btree_insert_key(struct btree *b, struct bkey *k,
 
 static size_t insert_u64s_remaining(struct btree *b)
 {
-       ssize_t ret = bch_btree_keys_u64s_remaining(&b->keys);
+       long ret = bch_btree_keys_u64s_remaining(&b->keys);
 
        /*
         * Might land in the middle of an existing extent and have to split it
index c3ead586dc274d35124689b03572b4f740719a57..416d1a3e028e03a34a9d03e31b9e6fa583c9b357 100644 (file)
@@ -194,7 +194,7 @@ err:
        mutex_unlock(&b->c->bucket_lock);
        bch_extent_to_text(buf, sizeof(buf), k);
        btree_bug(b,
-"inconsistent btree pointer %s: bucket %li pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+"inconsistent btree pointer %s: bucket %zi pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
                  buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
                  g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
        return true;
index 72cd213f213f9e806dc9a0360000ffffe6466896..5d5d031cf3813247adb89653f2fe5fcd227ce764 100644 (file)
@@ -353,14 +353,14 @@ static void bch_data_insert_start(struct closure *cl)
        struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
        struct bio *bio = op->bio, *n;
 
-       if (op->bypass)
-               return bch_data_invalidate(cl);
-
        if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) {
                set_gc_sectors(op->c);
                wake_up_gc(op->c);
        }
 
+       if (op->bypass)
+               return bch_data_invalidate(cl);
+
        /*
         * Journal writes are marked REQ_FLUSH; if the original write was a
         * flush, it'll wait on the journal write.
index c6ab69333a6dfde7761e9e2b05c16574f5c52480..d8458d477a1282110a8c685859ecc66dcf947057 100644 (file)
@@ -416,7 +416,7 @@ static int btree_bset_stats(struct btree_op *b_op, struct btree *b)
        return MAP_CONTINUE;
 }
 
-int bch_bset_print_stats(struct cache_set *c, char *buf)
+static int bch_bset_print_stats(struct cache_set *c, char *buf)
 {
        struct bset_stats_op op;
        int ret;
index 1e018e986610a57ef9f82a818aa1f70a8c364e30..0e385e40909e74fcde4da4ee5d785149101ad9cb 100644 (file)
@@ -872,7 +872,7 @@ static void mq_destroy(struct dm_cache_policy *p)
 {
        struct mq_policy *mq = to_mq_policy(p);
 
-       kfree(mq->table);
+       vfree(mq->table);
        epool_exit(&mq->cache_pool);
        epool_exit(&mq->pre_cache_pool);
        kfree(mq);
@@ -1245,7 +1245,7 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
 
        mq->nr_buckets = next_power(from_cblock(cache_size) / 2, 16);
        mq->hash_bits = ffs(mq->nr_buckets) - 1;
-       mq->table = kzalloc(sizeof(*mq->table) * mq->nr_buckets, GFP_KERNEL);
+       mq->table = vzalloc(sizeof(*mq->table) * mq->nr_buckets);
        if (!mq->table)
                goto bad_alloc_table;
 
index ffd472e015caa918facaed4f65a621c0f61e58a9..074b9c8e4cf0840dd0d64014776dc297c2d82da6 100644 (file)
@@ -289,6 +289,7 @@ struct per_bio_data {
        bool tick:1;
        unsigned req_nr:2;
        struct dm_deferred_entry *all_io_entry;
+       struct dm_hook_info hook_info;
 
        /*
         * writethrough fields.  These MUST remain at the end of this
@@ -297,7 +298,6 @@ struct per_bio_data {
         */
        struct cache *cache;
        dm_cblock_t cblock;
-       struct dm_hook_info hook_info;
        struct dm_bio_details bio_details;
 };
 
@@ -671,15 +671,16 @@ static void remap_to_cache(struct cache *cache, struct bio *bio,
                           dm_cblock_t cblock)
 {
        sector_t bi_sector = bio->bi_iter.bi_sector;
+       sector_t block = from_cblock(cblock);
 
        bio->bi_bdev = cache->cache_dev->bdev;
        if (!block_size_is_power_of_two(cache))
                bio->bi_iter.bi_sector =
-                       (from_cblock(cblock) * cache->sectors_per_block) +
+                       (block * cache->sectors_per_block) +
                        sector_div(bi_sector, cache->sectors_per_block);
        else
                bio->bi_iter.bi_sector =
-                       (from_cblock(cblock) << cache->sectors_per_block_shift) |
+                       (block << cache->sectors_per_block_shift) |
                        (bi_sector & (cache->sectors_per_block - 1));
 }
 
@@ -978,12 +979,13 @@ static void issue_copy_real(struct dm_cache_migration *mg)
        int r;
        struct dm_io_region o_region, c_region;
        struct cache *cache = mg->cache;
+       sector_t cblock = from_cblock(mg->cblock);
 
        o_region.bdev = cache->origin_dev->bdev;
        o_region.count = cache->sectors_per_block;
 
        c_region.bdev = cache->cache_dev->bdev;
-       c_region.sector = from_cblock(mg->cblock) * cache->sectors_per_block;
+       c_region.sector = cblock * cache->sectors_per_block;
        c_region.count = cache->sectors_per_block;
 
        if (mg->writeback || mg->demote) {
@@ -1010,13 +1012,15 @@ static void overwrite_endio(struct bio *bio, int err)
        struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
        unsigned long flags;
 
+       dm_unhook_bio(&pb->hook_info, bio);
+
        if (err)
                mg->err = true;
 
+       mg->requeue_holder = false;
+
        spin_lock_irqsave(&cache->lock, flags);
        list_add_tail(&mg->list, &cache->completed_migrations);
-       dm_unhook_bio(&pb->hook_info, bio);
-       mg->requeue_holder = false;
        spin_unlock_irqrestore(&cache->lock, flags);
 
        wake_worker(cache);
@@ -2461,20 +2465,18 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
        bool discarded_block;
        struct dm_bio_prison_cell *cell;
        struct policy_result lookup_result;
-       struct per_bio_data *pb;
+       struct per_bio_data *pb = init_per_bio_data(bio, pb_data_size);
 
-       if (from_oblock(block) > from_oblock(cache->origin_blocks)) {
+       if (unlikely(from_oblock(block) >= from_oblock(cache->origin_blocks))) {
                /*
                 * This can only occur if the io goes to a partial block at
                 * the end of the origin device.  We don't cache these.
                 * Just remap to the origin and carry on.
                 */
-               remap_to_origin_clear_discard(cache, bio, block);
+               remap_to_origin(cache, bio);
                return DM_MAPIO_REMAPPED;
        }
 
-       pb = init_per_bio_data(bio, pb_data_size);
-
        if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
                defer_bio(cache, bio);
                return DM_MAPIO_SUBMITTED;
index b2b8a10e842784de5454e2639474f1a208b4b3f1..3842ac738f98ff324f5e1152f08fb546a5bb47fa 100644 (file)
@@ -201,29 +201,28 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
 /*
  * Functions for getting the pages from a bvec.
  */
-static void bio_get_page(struct dpages *dp,
-                 struct page **p, unsigned long *len, unsigned *offset)
+static void bio_get_page(struct dpages *dp, struct page **p,
+                        unsigned long *len, unsigned *offset)
 {
-       struct bio *bio = dp->context_ptr;
-       struct bio_vec bvec = bio_iovec(bio);
-       *p = bvec.bv_page;
-       *len = bvec.bv_len;
-       *offset = bvec.bv_offset;
+       struct bio_vec *bvec = dp->context_ptr;
+       *p = bvec->bv_page;
+       *len = bvec->bv_len - dp->context_u;
+       *offset = bvec->bv_offset + dp->context_u;
 }
 
 static void bio_next_page(struct dpages *dp)
 {
-       struct bio *bio = dp->context_ptr;
-       struct bio_vec bvec = bio_iovec(bio);
-
-       bio_advance(bio, bvec.bv_len);
+       struct bio_vec *bvec = dp->context_ptr;
+       dp->context_ptr = bvec + 1;
+       dp->context_u = 0;
 }
 
 static void bio_dp_init(struct dpages *dp, struct bio *bio)
 {
        dp->get_page = bio_get_page;
        dp->next_page = bio_next_page;
-       dp->context_ptr = bio;
+       dp->context_ptr = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter);
+       dp->context_u = bio->bi_iter.bi_bvec_done;
 }
 
 /*
index 6eb9dc9ef8f36c4b709df6f3b46170598964e88d..422a9fdeb53e641d97acec4793ab00747dde9b1d 100644 (file)
@@ -1626,8 +1626,11 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
        /*
         * Only pass ioctls through if the device sizes match exactly.
         */
-       if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
-               r = scsi_verify_blk_ioctl(NULL, cmd);
+       if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) {
+               int err = scsi_verify_blk_ioctl(NULL, cmd);
+               if (err)
+                       r = err;
+       }
 
        if (r == -ENOTCONN && !fatal_signal_pending(current))
                queue_work(kmultipathd, &m->process_queued_ios);
index f284e0bfb25fca869855f390f2d8d7a5519a0864..7dfdb5c746d6f31960902350c33b7457485caadb 100644 (file)
@@ -1244,6 +1244,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error)
 
                        dm_bio_restore(bd, bio);
                        bio_record->details.bi_bdev = NULL;
+
+                       atomic_inc(&bio->bi_remaining);
+
                        queue_bio(ms, bio, rw);
                        return DM_ENDIO_INCOMPLETE;
                }
index afc3d017de4c6a479f418df9197a62677539752d..d6e88178d22cff0e88fb8b21cb20558f51e8d6a1 100644 (file)
@@ -546,6 +546,9 @@ static int read_exceptions(struct pstore *ps,
                r = insert_exceptions(ps, area, callback, callback_context,
                                      &full);
 
+               if (!full)
+                       memcpy(ps->area, area, ps->store->chunk_size << SECTOR_SHIFT);
+
                dm_bufio_release(bp);
 
                dm_bufio_forget(client, chunk);
index 7da34766555284486e39a08306f88a876deeefc3..fb9efc829182d4cce55c9c8cfac1e850e65abe79 100644 (file)
@@ -76,7 +76,7 @@
 
 #define THIN_SUPERBLOCK_MAGIC 27022010
 #define THIN_SUPERBLOCK_LOCATION 0
-#define THIN_VERSION 1
+#define THIN_VERSION 2
 #define THIN_METADATA_CACHE_SIZE 64
 #define SECTOR_TO_BLOCK_SHIFT 3
 
@@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd)
 
        disk_super->data_mapping_root = cpu_to_le64(pmd->root);
        disk_super->device_details_root = cpu_to_le64(pmd->details_root);
-       disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+       disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE);
        disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT);
        disk_super->data_block_size = cpu_to_le32(pmd->data_block_size);
 
@@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f
 {
        int r;
 
-       pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE,
+       pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT,
                                          THIN_METADATA_CACHE_SIZE,
                                          THIN_MAX_CONCURRENT_LOCKS);
        if (IS_ERR(pmd->bm)) {
@@ -1489,6 +1489,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td)
        return r;
 }
 
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd)
+{
+       bool r = false;
+       struct dm_thin_device *td, *tmp;
+
+       down_read(&pmd->root_lock);
+       list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) {
+               if (td->changed) {
+                       r = td->changed;
+                       break;
+               }
+       }
+       up_read(&pmd->root_lock);
+
+       return r;
+}
+
 bool dm_thin_aborted_changes(struct dm_thin_device *td)
 {
        bool r;
@@ -1738,3 +1755,38 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
 
        return r;
 }
+
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd)
+{
+       int r;
+       struct dm_block *sblock;
+       struct thin_disk_superblock *disk_super;
+
+       down_write(&pmd->root_lock);
+       pmd->flags |= THIN_METADATA_NEEDS_CHECK_FLAG;
+
+       r = superblock_lock(pmd, &sblock);
+       if (r) {
+               DMERR("couldn't read superblock");
+               goto out;
+       }
+
+       disk_super = dm_block_data(sblock);
+       disk_super->flags = cpu_to_le32(pmd->flags);
+
+       dm_bm_unlock(sblock);
+out:
+       up_write(&pmd->root_lock);
+       return r;
+}
+
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
+{
+       bool needs_check;
+
+       down_read(&pmd->root_lock);
+       needs_check = pmd->flags & THIN_METADATA_NEEDS_CHECK_FLAG;
+       up_read(&pmd->root_lock);
+
+       return needs_check;
+}
index 9a368567632f9733f04bc0a1aebfbc3d871f13df..e3c857db195a7453d192f5f55cfb766a046a789a 100644 (file)
@@ -9,16 +9,14 @@
 
 #include "persistent-data/dm-block-manager.h"
 #include "persistent-data/dm-space-map.h"
+#include "persistent-data/dm-space-map-metadata.h"
 
-#define THIN_METADATA_BLOCK_SIZE 4096
+#define THIN_METADATA_BLOCK_SIZE DM_SM_METADATA_BLOCK_SIZE
 
 /*
  * The metadata device is currently limited in size.
- *
- * We have one block of index, which can hold 255 index entries.  Each
- * index entry contains allocation info about 16k metadata blocks.
  */
-#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT)))
+#define THIN_METADATA_MAX_SECTORS DM_SM_METADATA_MAX_SECTORS
 
 /*
  * A metadata device larger than 16GB triggers a warning.
 
 /*----------------------------------------------------------------*/
 
+/*
+ * Thin metadata superblock flags.
+ */
+#define THIN_METADATA_NEEDS_CHECK_FLAG (1 << 0)
+
 struct dm_pool_metadata;
 struct dm_thin_device;
 
@@ -161,6 +164,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block);
  */
 bool dm_thin_changed_this_transaction(struct dm_thin_device *td);
 
+bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd);
+
 bool dm_thin_aborted_changes(struct dm_thin_device *td);
 
 int dm_thin_get_highest_mapped_block(struct dm_thin_device *td,
@@ -202,6 +207,12 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
                                        dm_sm_threshold_fn fn,
                                        void *context);
 
+/*
+ * Updates the superblock immediately.
+ */
+int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd);
+bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+
 /*----------------------------------------------------------------*/
 
 #endif
index faaf944597ab7669b90f3ecb85152fbcd16cbe33..be70d38745f7a7f5da51bd4ba83a29afe851b238 100644 (file)
@@ -130,10 +130,11 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
 struct dm_thin_new_mapping;
 
 /*
- * The pool runs in 3 modes.  Ordered in degraded order for comparisons.
+ * The pool runs in 4 modes.  Ordered in degraded order for comparisons.
  */
 enum pool_mode {
        PM_WRITE,               /* metadata may be changed */
+       PM_OUT_OF_DATA_SPACE,   /* metadata may be changed, though data may not be allocated */
        PM_READ_ONLY,           /* metadata may not be changed */
        PM_FAIL,                /* all I/O fails */
 };
@@ -198,7 +199,6 @@ struct pool {
 };
 
 static enum pool_mode get_pool_mode(struct pool *pool);
-static void out_of_data_space(struct pool *pool);
 static void metadata_operation_failed(struct pool *pool, const char *op, int r);
 
 /*
@@ -226,6 +226,7 @@ struct thin_c {
 
        struct pool *pool;
        struct dm_thin_device *td;
+       bool requeue_mode:1;
 };
 
 /*----------------------------------------------------------------*/
@@ -369,14 +370,18 @@ struct dm_thin_endio_hook {
        struct dm_thin_new_mapping *overwrite_mapping;
 };
 
-static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
+static void requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 {
        struct bio *bio;
        struct bio_list bios;
+       unsigned long flags;
 
        bio_list_init(&bios);
+
+       spin_lock_irqsave(&tc->pool->lock, flags);
        bio_list_merge(&bios, master);
        bio_list_init(master);
+       spin_unlock_irqrestore(&tc->pool->lock, flags);
 
        while ((bio = bio_list_pop(&bios))) {
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -391,12 +396,26 @@ static void __requeue_bio_list(struct thin_c *tc, struct bio_list *master)
 static void requeue_io(struct thin_c *tc)
 {
        struct pool *pool = tc->pool;
+
+       requeue_bio_list(tc, &pool->deferred_bios);
+       requeue_bio_list(tc, &pool->retry_on_resume_list);
+}
+
+static void error_retry_list(struct pool *pool)
+{
+       struct bio *bio;
        unsigned long flags;
+       struct bio_list bios;
+
+       bio_list_init(&bios);
 
        spin_lock_irqsave(&pool->lock, flags);
-       __requeue_bio_list(tc, &pool->deferred_bios);
-       __requeue_bio_list(tc, &pool->retry_on_resume_list);
+       bio_list_merge(&bios, &pool->retry_on_resume_list);
+       bio_list_init(&pool->retry_on_resume_list);
        spin_unlock_irqrestore(&pool->lock, flags);
+
+       while ((bio = bio_list_pop(&bios)))
+               bio_io_error(bio);
 }
 
 /*
@@ -925,13 +944,15 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
        }
 }
 
+static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
+
 static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
 {
        int r;
        dm_block_t free_blocks;
        struct pool *pool = tc->pool;
 
-       if (get_pool_mode(pool) != PM_WRITE)
+       if (WARN_ON(get_pool_mode(pool) != PM_WRITE))
                return -EINVAL;
 
        r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
@@ -958,7 +979,7 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
                }
 
                if (!free_blocks) {
-                       out_of_data_space(pool);
+                       set_pool_mode(pool, PM_OUT_OF_DATA_SPACE);
                        return -ENOSPC;
                }
        }
@@ -988,15 +1009,32 @@ static void retry_on_resume(struct bio *bio)
        spin_unlock_irqrestore(&pool->lock, flags);
 }
 
-static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+static bool should_error_unserviceable_bio(struct pool *pool)
 {
-       /*
-        * When pool is read-only, no cell locking is needed because
-        * nothing is changing.
-        */
-       WARN_ON_ONCE(get_pool_mode(pool) != PM_READ_ONLY);
+       enum pool_mode m = get_pool_mode(pool);
 
-       if (pool->pf.error_if_no_space)
+       switch (m) {
+       case PM_WRITE:
+               /* Shouldn't get here */
+               DMERR_LIMIT("bio unserviceable, yet pool is in PM_WRITE mode");
+               return true;
+
+       case PM_OUT_OF_DATA_SPACE:
+               return pool->pf.error_if_no_space;
+
+       case PM_READ_ONLY:
+       case PM_FAIL:
+               return true;
+       default:
+               /* Shouldn't get here */
+               DMERR_LIMIT("bio unserviceable, yet pool has an unknown mode");
+               return true;
+       }
+}
+
+static void handle_unserviceable_bio(struct pool *pool, struct bio *bio)
+{
+       if (should_error_unserviceable_bio(pool))
                bio_io_error(bio);
        else
                retry_on_resume(bio);
@@ -1007,11 +1045,20 @@ static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *c
        struct bio *bio;
        struct bio_list bios;
 
+       if (should_error_unserviceable_bio(pool)) {
+               cell_error(pool, cell);
+               return;
+       }
+
        bio_list_init(&bios);
        cell_release(pool, cell, &bios);
 
-       while ((bio = bio_list_pop(&bios)))
-               handle_unserviceable_bio(pool, bio);
+       if (should_error_unserviceable_bio(pool))
+               while ((bio = bio_list_pop(&bios)))
+                       bio_io_error(bio);
+       else
+               while ((bio = bio_list_pop(&bios)))
+                       retry_on_resume(bio);
 }
 
 static void process_discard(struct thin_c *tc, struct bio *bio)
@@ -1296,6 +1343,11 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
        }
 }
 
+static void process_bio_success(struct thin_c *tc, struct bio *bio)
+{
+       bio_endio(bio, 0);
+}
+
 static void process_bio_fail(struct thin_c *tc, struct bio *bio)
 {
        bio_io_error(bio);
@@ -1328,6 +1380,11 @@ static void process_deferred_bios(struct pool *pool)
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
                struct thin_c *tc = h->tc;
 
+               if (tc->requeue_mode) {
+                       bio_endio(bio, DM_ENDIO_REQUEUE);
+                       continue;
+               }
+
                /*
                 * If we've got no free new_mapping structs, and processing
                 * this bio might require one, we pause until there are some
@@ -1357,7 +1414,8 @@ static void process_deferred_bios(struct pool *pool)
        bio_list_init(&pool->deferred_flush_bios);
        spin_unlock_irqrestore(&pool->lock, flags);
 
-       if (bio_list_empty(&bios) && !need_commit_due_to_time(pool))
+       if (bio_list_empty(&bios) &&
+           !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool)))
                return;
 
        if (commit(pool)) {
@@ -1393,51 +1451,134 @@ static void do_waker(struct work_struct *ws)
 
 /*----------------------------------------------------------------*/
 
+struct noflush_work {
+       struct work_struct worker;
+       struct thin_c *tc;
+
+       atomic_t complete;
+       wait_queue_head_t wait;
+};
+
+static void complete_noflush_work(struct noflush_work *w)
+{
+       atomic_set(&w->complete, 1);
+       wake_up(&w->wait);
+}
+
+static void do_noflush_start(struct work_struct *ws)
+{
+       struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+       w->tc->requeue_mode = true;
+       requeue_io(w->tc);
+       complete_noflush_work(w);
+}
+
+static void do_noflush_stop(struct work_struct *ws)
+{
+       struct noflush_work *w = container_of(ws, struct noflush_work, worker);
+       w->tc->requeue_mode = false;
+       complete_noflush_work(w);
+}
+
+static void noflush_work(struct thin_c *tc, void (*fn)(struct work_struct *))
+{
+       struct noflush_work w;
+
+       INIT_WORK(&w.worker, fn);
+       w.tc = tc;
+       atomic_set(&w.complete, 0);
+       init_waitqueue_head(&w.wait);
+
+       queue_work(tc->pool->wq, &w.worker);
+
+       wait_event(w.wait, atomic_read(&w.complete));
+}
+
+/*----------------------------------------------------------------*/
+
 static enum pool_mode get_pool_mode(struct pool *pool)
 {
        return pool->pf.mode;
 }
 
+static void notify_of_pool_mode_change(struct pool *pool, const char *new_mode)
+{
+       dm_table_event(pool->ti->table);
+       DMINFO("%s: switching pool to %s mode",
+              dm_device_name(pool->pool_md), new_mode);
+}
+
 static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
 {
-       int r;
-       enum pool_mode old_mode = pool->pf.mode;
+       struct pool_c *pt = pool->ti->private;
+       bool needs_check = dm_pool_metadata_needs_check(pool->pmd);
+       enum pool_mode old_mode = get_pool_mode(pool);
+
+       /*
+        * Never allow the pool to transition to PM_WRITE mode if user
+        * intervention is required to verify metadata and data consistency.
+        */
+       if (new_mode == PM_WRITE && needs_check) {
+               DMERR("%s: unable to switch pool to write mode until repaired.",
+                     dm_device_name(pool->pool_md));
+               if (old_mode != new_mode)
+                       new_mode = old_mode;
+               else
+                       new_mode = PM_READ_ONLY;
+       }
+       /*
+        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
+        * not going to recover without a thin_repair.  So we never let the
+        * pool move out of the old mode.
+        */
+       if (old_mode == PM_FAIL)
+               new_mode = old_mode;
 
        switch (new_mode) {
        case PM_FAIL:
                if (old_mode != new_mode)
-                       DMERR("%s: switching pool to failure mode",
-                             dm_device_name(pool->pool_md));
+                       notify_of_pool_mode_change(pool, "failure");
                dm_pool_metadata_read_only(pool->pmd);
                pool->process_bio = process_bio_fail;
                pool->process_discard = process_bio_fail;
                pool->process_prepared_mapping = process_prepared_mapping_fail;
                pool->process_prepared_discard = process_prepared_discard_fail;
+
+               error_retry_list(pool);
                break;
 
        case PM_READ_ONLY:
                if (old_mode != new_mode)
-                       DMERR("%s: switching pool to read-only mode",
-                             dm_device_name(pool->pool_md));
-               r = dm_pool_abort_metadata(pool->pmd);
-               if (r) {
-                       DMERR("%s: aborting transaction failed",
-                             dm_device_name(pool->pool_md));
-                       new_mode = PM_FAIL;
-                       set_pool_mode(pool, new_mode);
-               } else {
-                       dm_pool_metadata_read_only(pool->pmd);
-                       pool->process_bio = process_bio_read_only;
-                       pool->process_discard = process_discard;
-                       pool->process_prepared_mapping = process_prepared_mapping_fail;
-                       pool->process_prepared_discard = process_prepared_discard_passdown;
-               }
+                       notify_of_pool_mode_change(pool, "read-only");
+               dm_pool_metadata_read_only(pool->pmd);
+               pool->process_bio = process_bio_read_only;
+               pool->process_discard = process_bio_success;
+               pool->process_prepared_mapping = process_prepared_mapping_fail;
+               pool->process_prepared_discard = process_prepared_discard_passdown;
+
+               error_retry_list(pool);
+               break;
+
+       case PM_OUT_OF_DATA_SPACE:
+               /*
+                * Ideally we'd never hit this state; the low water mark
+                * would trigger userland to extend the pool before we
+                * completely run out of data space.  However, many small
+                * IOs to unprovisioned space can consume data space at an
+                * alarming rate.  Adjust your low water mark if you're
+                * frequently seeing this mode.
+                */
+               if (old_mode != new_mode)
+                       notify_of_pool_mode_change(pool, "out-of-data-space");
+               pool->process_bio = process_bio_read_only;
+               pool->process_discard = process_discard;
+               pool->process_prepared_mapping = process_prepared_mapping;
+               pool->process_prepared_discard = process_prepared_discard_passdown;
                break;
 
        case PM_WRITE:
                if (old_mode != new_mode)
-                       DMINFO("%s: switching pool to write mode",
-                              dm_device_name(pool->pool_md));
+                       notify_of_pool_mode_change(pool, "write");
                dm_pool_metadata_read_write(pool->pmd);
                pool->process_bio = process_bio;
                pool->process_discard = process_discard;
@@ -1447,32 +1588,35 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
        }
 
        pool->pf.mode = new_mode;
+       /*
+        * The pool mode may have changed, sync it so bind_control_target()
+        * doesn't cause an unexpected mode transition on resume.
+        */
+       pt->adjusted_pf.mode = new_mode;
 }
 
-/*
- * Rather than calling set_pool_mode directly, use these which describe the
- * reason for mode degradation.
- */
-static void out_of_data_space(struct pool *pool)
+static void abort_transaction(struct pool *pool)
 {
-       DMERR_LIMIT("%s: no free data space available.",
-                   dm_device_name(pool->pool_md));
-       set_pool_mode(pool, PM_READ_ONLY);
+       const char *dev_name = dm_device_name(pool->pool_md);
+
+       DMERR_LIMIT("%s: aborting current metadata transaction", dev_name);
+       if (dm_pool_abort_metadata(pool->pmd)) {
+               DMERR("%s: failed to abort metadata transaction", dev_name);
+               set_pool_mode(pool, PM_FAIL);
+       }
+
+       if (dm_pool_metadata_set_needs_check(pool->pmd)) {
+               DMERR("%s: failed to set 'needs_check' flag in metadata", dev_name);
+               set_pool_mode(pool, PM_FAIL);
+       }
 }
 
 static void metadata_operation_failed(struct pool *pool, const char *op, int r)
 {
-       dm_block_t free_blocks;
-
        DMERR_LIMIT("%s: metadata operation '%s' failed: error = %d",
                    dm_device_name(pool->pool_md), op, r);
 
-       if (r == -ENOSPC &&
-           !dm_pool_get_free_metadata_block_count(pool->pmd, &free_blocks) &&
-           !free_blocks)
-               DMERR_LIMIT("%s: no free metadata space available.",
-                           dm_device_name(pool->pool_md));
-
+       abort_transaction(pool);
        set_pool_mode(pool, PM_READ_ONLY);
 }
 
@@ -1523,6 +1667,11 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
 
        thin_hook_bio(tc, bio);
 
+       if (tc->requeue_mode) {
+               bio_endio(bio, DM_ENDIO_REQUEUE);
+               return DM_MAPIO_SUBMITTED;
+       }
+
        if (get_pool_mode(tc->pool) == PM_FAIL) {
                bio_io_error(bio);
                return DM_MAPIO_SUBMITTED;
@@ -1686,7 +1835,7 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        /*
         * We want to make sure that a pool in PM_FAIL mode is never upgraded.
         */
-       enum pool_mode old_mode = pool->pf.mode;
+       enum pool_mode old_mode = get_pool_mode(pool);
        enum pool_mode new_mode = pt->adjusted_pf.mode;
 
        /*
@@ -1700,16 +1849,6 @@ static int bind_control_target(struct pool *pool, struct dm_target *ti)
        pool->pf = pt->adjusted_pf;
        pool->low_water_blocks = pt->low_water_blocks;
 
-       /*
-        * If we were in PM_FAIL mode, rollback of metadata failed.  We're
-        * not going to recover without a thin_repair.  So we never let the
-        * pool move out of the old mode.  On the other hand a PM_READ_ONLY
-        * may have been due to a lack of metadata or data space, and may
-        * now work (ie. if the underlying devices have been resized).
-        */
-       if (old_mode == PM_FAIL)
-               new_mode = old_mode;
-
        set_pool_mode(pool, new_mode);
 
        return 0;
@@ -1999,16 +2138,27 @@ static void metadata_low_callback(void *context)
        dm_table_event(pool->ti->table);
 }
 
-static sector_t get_metadata_dev_size(struct block_device *bdev)
+static sector_t get_dev_size(struct block_device *bdev)
+{
+       return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+}
+
+static void warn_if_metadata_device_too_big(struct block_device *bdev)
 {
-       sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT;
+       sector_t metadata_dev_size = get_dev_size(bdev);
        char buffer[BDEVNAME_SIZE];
 
-       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) {
+       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING)
                DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.",
                       bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS);
-               metadata_dev_size = THIN_METADATA_MAX_SECTORS_WARNING;
-       }
+}
+
+static sector_t get_metadata_dev_size(struct block_device *bdev)
+{
+       sector_t metadata_dev_size = get_dev_size(bdev);
+
+       if (metadata_dev_size > THIN_METADATA_MAX_SECTORS)
+               metadata_dev_size = THIN_METADATA_MAX_SECTORS;
 
        return metadata_dev_size;
 }
@@ -2017,7 +2167,7 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev)
 {
        sector_t metadata_dev_size = get_metadata_dev_size(bdev);
 
-       sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT);
+       sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE);
 
        return metadata_dev_size;
 }
@@ -2095,12 +2245,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv)
                ti->error = "Error opening metadata block device";
                goto out_unlock;
        }
-
-       /*
-        * Run for the side-effect of possibly issuing a warning if the
-        * device is too big.
-        */
-       (void) get_metadata_dev_size(metadata_dev->bdev);
+       warn_if_metadata_device_too_big(metadata_dev->bdev);
 
        r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev);
        if (r) {
@@ -2246,6 +2391,12 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
                return -EINVAL;
 
        } else if (data_size > sb_data_size) {
+               if (dm_pool_metadata_needs_check(pool->pmd)) {
+                       DMERR("%s: unable to grow the data device until repaired.",
+                             dm_device_name(pool->pool_md));
+                       return 0;
+               }
+
                if (sb_data_size)
                        DMINFO("%s: growing the data device from %llu to %llu blocks",
                               dm_device_name(pool->pool_md),
@@ -2287,6 +2438,13 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
                return -EINVAL;
 
        } else if (metadata_dev_size > sb_metadata_dev_size) {
+               if (dm_pool_metadata_needs_check(pool->pmd)) {
+                       DMERR("%s: unable to grow the metadata device until repaired.",
+                             dm_device_name(pool->pool_md));
+                       return 0;
+               }
+
+               warn_if_metadata_device_too_big(pool->md_dev);
                DMINFO("%s: growing the metadata device from %llu to %llu blocks",
                       dm_device_name(pool->pool_md),
                       sb_metadata_dev_size, metadata_dev_size);
@@ -2673,7 +2831,9 @@ static void pool_status(struct dm_target *ti, status_type_t type,
                else
                        DMEMIT("- ");
 
-               if (pool->pf.mode == PM_READ_ONLY)
+               if (pool->pf.mode == PM_OUT_OF_DATA_SPACE)
+                       DMEMIT("out_of_data_space ");
+               else if (pool->pf.mode == PM_READ_ONLY)
                        DMEMIT("ro ");
                else
                        DMEMIT("rw ");
@@ -2787,7 +2947,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2894,6 +3054,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        if (get_pool_mode(tc->pool) == PM_FAIL) {
                ti->error = "Couldn't open thin device, Pool is in fail mode";
+               r = -EINVAL;
                goto bad_thin_open;
        }
 
@@ -2905,7 +3066,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
        if (r)
-               goto bad_thin_open;
+               goto bad_target_max_io_len;
 
        ti->num_flush_bios = 1;
        ti->flush_supported = true;
@@ -2926,6 +3087,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        return 0;
 
+bad_target_max_io_len:
+       dm_pool_close_thin_device(tc->td);
 bad_thin_open:
        __pool_dec(tc->pool);
 bad_pool_lookup:
@@ -2986,10 +3149,23 @@ static int thin_endio(struct dm_target *ti, struct bio *bio, int err)
        return 0;
 }
 
-static void thin_postsuspend(struct dm_target *ti)
+static void thin_presuspend(struct dm_target *ti)
 {
+       struct thin_c *tc = ti->private;
+
        if (dm_noflush_suspending(ti))
-               requeue_io((struct thin_c *)ti->private);
+               noflush_work(tc, do_noflush_start);
+}
+
+static void thin_postsuspend(struct dm_target *ti)
+{
+       struct thin_c *tc = ti->private;
+
+       /*
+        * The dm_noflush_suspending flag has been cleared by now, so
+        * unfortunately we must always run this.
+        */
+       noflush_work(tc, do_noflush_stop);
 }
 
 /*
@@ -3074,12 +3250,13 @@ static int thin_iterate_devices(struct dm_target *ti,
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 10, 0},
+       .version = {1, 11, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
        .map = thin_map,
        .end_io = thin_endio,
+       .presuspend = thin_presuspend,
        .postsuspend = thin_postsuspend,
        .status = thin_status,
        .iterate_devices = thin_iterate_devices,
index 19b268795415b4a1eaf519001511275774a7f96e..0c2dec7aec20fd798d45b24d92156b3f85f4aae0 100644 (file)
@@ -6,3 +6,13 @@ config DM_PERSISTENT_DATA
        ---help---
         Library providing immutable on-disk data structure support for
         device-mapper targets such as the thin provisioning target.
+
+config DM_DEBUG_BLOCK_STACK_TRACING
+       boolean "Keep stack trace of persistent data block lock holders"
+       depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
+       select STACKTRACE
+       ---help---
+        Enable this for messages that may help debug problems with the
+        block manager locking used by thin provisioning and caching.
+
+        If unsure, say N.
index 536782e3bcb757427763868fbf86fcb0bd92e273..786b689bdfc7fe0c42d9a651a2369ffadcdc2382 100644 (file)
@@ -91,6 +91,69 @@ struct block_op {
        dm_block_t block;
 };
 
+struct bop_ring_buffer {
+       unsigned begin;
+       unsigned end;
+       struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
+};
+
+static void brb_init(struct bop_ring_buffer *brb)
+{
+       brb->begin = 0;
+       brb->end = 0;
+}
+
+static bool brb_empty(struct bop_ring_buffer *brb)
+{
+       return brb->begin == brb->end;
+}
+
+static unsigned brb_next(struct bop_ring_buffer *brb, unsigned old)
+{
+       unsigned r = old + 1;
+       return (r >= (sizeof(brb->bops) / sizeof(*brb->bops))) ? 0 : r;
+}
+
+static int brb_push(struct bop_ring_buffer *brb,
+                   enum block_op_type type, dm_block_t b)
+{
+       struct block_op *bop;
+       unsigned next = brb_next(brb, brb->end);
+
+       /*
+        * We don't allow the last bop to be filled, this way we can
+        * differentiate between full and empty.
+        */
+       if (next == brb->begin)
+               return -ENOMEM;
+
+       bop = brb->bops + brb->end;
+       bop->type = type;
+       bop->block = b;
+
+       brb->end = next;
+
+       return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+{
+       struct block_op *bop;
+
+       if (brb_empty(brb))
+               return -ENODATA;
+
+       bop = brb->bops + brb->begin;
+       result->type = bop->type;
+       result->block = bop->block;
+
+       brb->begin = brb_next(brb, brb->begin);
+
+       return 0;
+}
+
+/*----------------------------------------------------------------*/
+
 struct sm_metadata {
        struct dm_space_map sm;
 
@@ -101,25 +164,20 @@ struct sm_metadata {
 
        unsigned recursion_count;
        unsigned allocated_this_transaction;
-       unsigned nr_uncommitted;
-       struct block_op uncommitted[MAX_RECURSIVE_ALLOCATIONS];
+       struct bop_ring_buffer uncommitted;
 
        struct threshold threshold;
 };
 
 static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b)
 {
-       struct block_op *op;
+       int r = brb_push(&smm->uncommitted, type, b);
 
-       if (smm->nr_uncommitted == MAX_RECURSIVE_ALLOCATIONS) {
+       if (r) {
                DMERR("too many recursive allocations");
                return -ENOMEM;
        }
 
-       op = smm->uncommitted + smm->nr_uncommitted++;
-       op->type = type;
-       op->block = b;
-
        return 0;
 }
 
@@ -158,11 +216,17 @@ static int out(struct sm_metadata *smm)
                return -ENOMEM;
        }
 
-       if (smm->recursion_count == 1 && smm->nr_uncommitted) {
-               while (smm->nr_uncommitted && !r) {
-                       smm->nr_uncommitted--;
-                       r = commit_bop(smm, smm->uncommitted +
-                                      smm->nr_uncommitted);
+       if (smm->recursion_count == 1) {
+               while (!brb_empty(&smm->uncommitted)) {
+                       struct block_op bop;
+
+                       r = brb_pop(&smm->uncommitted, &bop);
+                       if (r) {
+                               DMERR("bug in bop ring buffer");
+                               break;
+                       }
+
+                       r = commit_bop(smm, &bop);
                        if (r)
                                break;
                }
@@ -217,7 +281,8 @@ static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
 static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
                                 uint32_t *result)
 {
-       int r, i;
+       int r;
+       unsigned i;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        unsigned adjustment = 0;
 
@@ -225,8 +290,10 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
         * We may have some uncommitted adjustments to add.  This list
         * should always be really short.
         */
-       for (i = 0; i < smm->nr_uncommitted; i++) {
-               struct block_op *op = smm->uncommitted + i;
+       for (i = smm->uncommitted.begin;
+            i != smm->uncommitted.end;
+            i = brb_next(&smm->uncommitted, i)) {
+               struct block_op *op = smm->uncommitted.bops + i;
 
                if (op->block != b)
                        continue;
@@ -254,7 +321,8 @@ static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
 static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
                                              dm_block_t b, int *result)
 {
-       int r, i, adjustment = 0;
+       int r, adjustment = 0;
+       unsigned i;
        struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
        uint32_t rc;
 
@@ -262,8 +330,11 @@ static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
         * We may have some uncommitted adjustments to add.  This list
         * should always be really short.
         */
-       for (i = 0; i < smm->nr_uncommitted; i++) {
-               struct block_op *op = smm->uncommitted + i;
+       for (i = smm->uncommitted.begin;
+            i != smm->uncommitted.end;
+            i = brb_next(&smm->uncommitted, i)) {
+
+               struct block_op *op = smm->uncommitted.bops + i;
 
                if (op->block != b)
                        continue;
@@ -671,7 +742,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        smm->begin = superblock + 1;
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
-       smm->nr_uncommitted = 0;
+       brb_init(&smm->uncommitted);
        threshold_init(&smm->threshold);
 
        memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
@@ -680,6 +751,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
        if (r)
                return r;
 
+       if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
+               nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
        r = sm_ll_extend(&smm->ll, nr_blocks);
        if (r)
                return r;
@@ -713,7 +786,7 @@ int dm_sm_metadata_open(struct dm_space_map *sm,
        smm->begin = 0;
        smm->recursion_count = 0;
        smm->allocated_this_transaction = 0;
-       smm->nr_uncommitted = 0;
+       brb_init(&smm->uncommitted);
        threshold_init(&smm->threshold);
 
        memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
index 39bba0801cf2ff092a593e6ccb283f949918cc89..64df923974d86a0ad4d22d59ebdb7fd7f6ecee3f 100644 (file)
@@ -9,6 +9,17 @@
 
 #include "dm-transaction-manager.h"
 
+#define DM_SM_METADATA_BLOCK_SIZE (4096 >> SECTOR_SHIFT)
+
+/*
+ * The metadata device is currently limited in size.
+ *
+ * We have one block of index, which can hold 255 index entries.  Each
+ * index entry contains allocation info about ~16k metadata blocks.
+ */
+#define DM_SM_METADATA_MAX_BLOCKS (255 * ((1 << 14) - 64))
+#define DM_SM_METADATA_MAX_SECTORS (DM_SM_METADATA_MAX_BLOCKS * DM_SM_METADATA_BLOCK_SIZE)
+
 /*
  * Unfortunately we have to use two-phase construction due to the cycle
  * between the tm and sm.
index fd3a2a14b587da5e3bb5046b0017ed7bd46f67a1..4a6ca1cb2e78539679b96a00b89542f6f0eab8f0 100644 (file)
@@ -1953,11 +1953,15 @@ static int process_checks(struct r1bio *r1_bio)
        for (i = 0; i < conf->raid_disks * 2; i++) {
                int j;
                int size;
+               int uptodate;
                struct bio *b = r1_bio->bios[i];
                if (b->bi_end_io != end_sync_read)
                        continue;
-               /* fixup the bio for reuse */
+               /* fixup the bio for reuse, but preserve BIO_UPTODATE */
+               uptodate = test_bit(BIO_UPTODATE, &b->bi_flags);
                bio_reset(b);
+               if (!uptodate)
+                       clear_bit(BIO_UPTODATE, &b->bi_flags);
                b->bi_vcnt = vcnt;
                b->bi_iter.bi_size = r1_bio->sectors << 9;
                b->bi_iter.bi_sector = r1_bio->sector +
@@ -1990,11 +1994,14 @@ static int process_checks(struct r1bio *r1_bio)
                int j;
                struct bio *pbio = r1_bio->bios[primary];
                struct bio *sbio = r1_bio->bios[i];
+               int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags);
 
                if (sbio->bi_end_io != end_sync_read)
                        continue;
+               /* Now we can 'fixup' the BIO_UPTODATE flag */
+               set_bit(BIO_UPTODATE, &sbio->bi_flags);
 
-               if (test_bit(BIO_UPTODATE, &sbio->bi_flags)) {
+               if (uptodate) {
                        for (j = vcnt; j-- ; ) {
                                struct page *p, *s;
                                p = pbio->bi_io_vec[j].bv_page;
@@ -2009,7 +2016,7 @@ static int process_checks(struct r1bio *r1_bio)
                if (j >= 0)
                        atomic64_add(r1_bio->sectors, &mddev->resync_mismatches);
                if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
-                             && test_bit(BIO_UPTODATE, &sbio->bi_flags))) {
+                             && uptodate)) {
                        /* No need to write to this device. */
                        sbio->bi_end_io = NULL;
                        rdev_dec_pending(conf->mirrors[i].rdev, mddev);
index f1feadeb7bb2d1b68a6592d946516e4036c7e939..16f5c21963db5391ed25fd1e185ab8399f353e74 100644 (file)
@@ -5514,23 +5514,43 @@ raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks)
        return sectors * (raid_disks - conf->max_degraded);
 }
 
+static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+{
+       safe_put_page(percpu->spare_page);
+       kfree(percpu->scribble);
+       percpu->spare_page = NULL;
+       percpu->scribble = NULL;
+}
+
+static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu)
+{
+       if (conf->level == 6 && !percpu->spare_page)
+               percpu->spare_page = alloc_page(GFP_KERNEL);
+       if (!percpu->scribble)
+               percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
+
+       if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) {
+               free_scratch_buffer(conf, percpu);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 static void raid5_free_percpu(struct r5conf *conf)
 {
-       struct raid5_percpu *percpu;
        unsigned long cpu;
 
        if (!conf->percpu)
                return;
 
-       get_online_cpus();
-       for_each_possible_cpu(cpu) {
-               percpu = per_cpu_ptr(conf->percpu, cpu);
-               safe_put_page(percpu->spare_page);
-               kfree(percpu->scribble);
-       }
 #ifdef CONFIG_HOTPLUG_CPU
        unregister_cpu_notifier(&conf->cpu_notify);
 #endif
+
+       get_online_cpus();
+       for_each_possible_cpu(cpu)
+               free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
        put_online_cpus();
 
        free_percpu(conf->percpu);
@@ -5557,15 +5577,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               if (conf->level == 6 && !percpu->spare_page)
-                       percpu->spare_page = alloc_page(GFP_KERNEL);
-               if (!percpu->scribble)
-                       percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
-
-               if (!percpu->scribble ||
-                   (conf->level == 6 && !percpu->spare_page)) {
-                       safe_put_page(percpu->spare_page);
-                       kfree(percpu->scribble);
+               if (alloc_scratch_buffer(conf, percpu)) {
                        pr_err("%s: failed memory allocation for cpu%ld\n",
                               __func__, cpu);
                        return notifier_from_errno(-ENOMEM);
@@ -5573,10 +5585,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               safe_put_page(percpu->spare_page);
-               kfree(percpu->scribble);
-               percpu->spare_page = NULL;
-               percpu->scribble = NULL;
+               free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
                break;
        default:
                break;
@@ -5588,40 +5597,29 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
 static int raid5_alloc_percpu(struct r5conf *conf)
 {
        unsigned long cpu;
-       struct page *spare_page;
-       struct raid5_percpu __percpu *allcpus;
-       void *scribble;
-       int err;
+       int err = 0;
 
-       allcpus = alloc_percpu(struct raid5_percpu);
-       if (!allcpus)
+       conf->percpu = alloc_percpu(struct raid5_percpu);
+       if (!conf->percpu)
                return -ENOMEM;
-       conf->percpu = allcpus;
+
+#ifdef CONFIG_HOTPLUG_CPU
+       conf->cpu_notify.notifier_call = raid456_cpu_notify;
+       conf->cpu_notify.priority = 0;
+       err = register_cpu_notifier(&conf->cpu_notify);
+       if (err)
+               return err;
+#endif
 
        get_online_cpus();
-       err = 0;
        for_each_present_cpu(cpu) {
-               if (conf->level == 6) {
-                       spare_page = alloc_page(GFP_KERNEL);
-                       if (!spare_page) {
-                               err = -ENOMEM;
-                               break;
-                       }
-                       per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
-               }
-               scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
-               if (!scribble) {
-                       err = -ENOMEM;
+               err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu));
+               if (err) {
+                       pr_err("%s: failed memory allocation for cpu%ld\n",
+                              __func__, cpu);
                        break;
                }
-               per_cpu_ptr(conf->percpu, cpu)->scribble = scribble;
        }
-#ifdef CONFIG_HOTPLUG_CPU
-       conf->cpu_notify.notifier_call = raid456_cpu_notify;
-       conf->cpu_notify.priority = 0;
-       if (err == 0)
-               err = register_cpu_notifier(&conf->cpu_notify);
-#endif
        put_online_cpus();
 
        return err;
index a60c188c2bd937255f60f42920e4b9fbba68cb88..04bd3b6de40188bebf7f083750ed547c38265ec2 100644 (file)
@@ -754,19 +754,19 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
                                 unsigned long arg)
 {
        int ret;
-       mutex_lock(&i2o_cfg_mutex);
        switch (cmd) {
        case I2OGETIOPS:
                ret = i2o_cfg_ioctl(file, cmd, arg);
                break;
        case I2OPASSTHRU32:
+               mutex_lock(&i2o_cfg_mutex);
                ret = i2o_cfg_passthru32(file, cmd, arg);
+               mutex_unlock(&i2o_cfg_mutex);
                break;
        default:
                ret = -ENOIOCTLCMD;
                break;
        }
-       mutex_unlock(&i2o_cfg_mutex);
        return ret;
 }
 
index 13af7e50021eedd5767aa296cfe46118f55f49ac..8103e4362132a24486961bf3ac6fd80980210107 100644 (file)
@@ -53,17 +53,25 @@ static int da9055_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the PMIC and CODEC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 ids for PMIC
+ * and CODEC, which must be different to operate together.
+ */
 static struct i2c_device_id da9055_i2c_id[] = {
-       {"da9055", 0},
+       {"da9055-pmic", 0},
        { }
 };
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 
 static struct i2c_driver da9055_i2c_driver = {
        .probe = da9055_i2c_probe,
        .remove = da9055_i2c_remove,
        .id_table = da9055_i2c_id,
        .driver = {
-               .name = "da9055",
+               .name = "da9055-pmic",
                .owner = THIS_MODULE,
        },
 };
index ac514fb2b8779ef6a1b7395bcd6c26cc45aefdc2..71aa14a6bfbbb4ffd061aeb91df739fc70684446 100644 (file)
@@ -173,6 +173,7 @@ static const struct i2c_device_id max14577_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max14577_i2c_id);
 
+#ifdef CONFIG_PM_SLEEP
 static int max14577_suspend(struct device *dev)
 {
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -208,6 +209,7 @@ static int max14577_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static struct of_device_id max14577_dt_match[] = {
        { .compatible = "maxim,max14577", },
index be88a3bf7b857a5b19f7e9d95b1be42c7e58b2d3..5adede0fb04c8c5a82f7804d3138ab1f7a74f334 100644 (file)
@@ -164,15 +164,15 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata(
        return pd;
 }
 
-static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c,
                                                const struct i2c_device_id *id)
 {
        if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node);
-               return (int)match->data;
+               return (unsigned long)match->data;
        }
-       return (int)id->driver_data;
+       return id->driver_data;
 }
 
 static int max8997_i2c_probe(struct i2c_client *i2c,
index 612ca404e1502d6c736eaf239d9b721e522664f9..5d5e186b5d8bbbfed035725480fb85dc52a0fdb4 100644 (file)
@@ -169,16 +169,16 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
        return pd;
 }
 
-static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long max8998_i2c_get_driver_data(struct i2c_client *i2c,
                                                const struct i2c_device_id *id)
 {
        if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(max8998_dt_match, i2c->dev.of_node);
-               return (int)(long)match->data;
+               return (unsigned long)match->data;
        }
 
-       return (int)id->driver_data;
+       return id->driver_data;
 }
 
 static int max8998_i2c_probe(struct i2c_client *i2c,
index a139798b806546b751b37f22e4d3e8044f3e2422..714e2135210ec2ddc989efcd44f3e800b80f5bcf 100644 (file)
@@ -315,6 +315,7 @@ static int sec_pmic_remove(struct i2c_client *i2c)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int sec_pmic_suspend(struct device *dev)
 {
        struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
@@ -349,6 +350,7 @@ static int sec_pmic_resume(struct device *dev)
 
        return 0;
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
 
index 966cf65c5c363f63d907048fe4bb31b3d30bbbac..3cc4c7084b9244dcc18dd42a7ab77a3550e59ddb 100644 (file)
@@ -158,7 +158,7 @@ static int tps65217_probe(struct i2c_client *client,
 {
        struct tps65217 *tps;
        unsigned int version;
-       unsigned int chip_id = ids->driver_data;
+       unsigned long chip_id = ids->driver_data;
        const struct of_device_id *match;
        bool status_off = false;
        int ret;
@@ -170,7 +170,7 @@ static int tps65217_probe(struct i2c_client *client,
                                "Failed to find matching dt id\n");
                        return -EINVAL;
                }
-               chip_id = (unsigned int)(unsigned long)match->data;
+               chip_id = (unsigned long)match->data;
                status_off = of_property_read_bool(client->dev.of_node,
                                        "ti,pmic-shutdown-controller");
        }
index ba04f1bc70eb52988ce27b5f4e45195e8b216b82..e6fab94e2c8a0fb1eed8df339833e36f2dd7c38b 100644 (file)
@@ -636,7 +636,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
        if (i2c->dev.of_node) {
                of_id = of_match_device(wm8994_of_match, &i2c->dev);
                if (of_id)
-                       wm8994->type = (int)of_id->data;
+                       wm8994->type = (enum wm8994_type)of_id->data;
        } else {
                wm8994->type = id->driver_data;
        }
index 8f8a6b327cdb83dd494823a77a50c98078738b38..2c2c9cc75231d7c9182a47fa43d22c5d99d58627 100644 (file)
@@ -787,6 +787,7 @@ static int genwqe_pin_mem(struct genwqe_file *cfile, struct genwqe_mem *m)
        if (rc != 0) {
                dev_err(&pci_dev->dev,
                        "[%s] genwqe_user_vmap rc=%d\n", __func__, rc);
+               kfree(dma_map);
                return rc;
        }
 
index 1ee2b9492a82527d508b4396647f75823956e28c..89a557972d1b926abe915760366d6602c1efa0cf 100644 (file)
@@ -666,7 +666,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
                goto err;
 
        cb->fop_type = MEI_FOP_READ;
-       cl->read_cb = cb;
        if (dev->hbuf_is_ready) {
                dev->hbuf_is_ready = false;
                if (mei_hbm_cl_flow_control_req(dev, cl)) {
@@ -678,6 +677,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
        } else {
                list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
        }
+
+       cl->read_cb = cb;
+
        return rets;
 err:
        mei_io_cb_free(cb);
@@ -908,7 +910,6 @@ void mei_cl_all_disconnect(struct mei_device *dev)
        list_for_each_entry_safe(cl, next, &dev->file_list, link) {
                cl->state = MEI_FILE_DISCONNECTED;
                cl->mei_flow_ctrl_creds = 0;
-               cl->read_cb = NULL;
                cl->timer_count = 0;
        }
 }
@@ -942,8 +943,16 @@ void mei_cl_all_wakeup(struct mei_device *dev)
 void mei_cl_all_write_clear(struct mei_device *dev)
 {
        struct mei_cl_cb *cb, *next;
+       struct list_head *list;
+
+       list = &dev->write_list.list;
+       list_for_each_entry_safe(cb, next, list, list) {
+               list_del(&cb->list);
+               mei_io_cb_free(cb);
+       }
 
-       list_for_each_entry_safe(cb, next, &dev->write_list.list, list) {
+       list = &dev->write_waiting_list.list;
+       list_for_each_entry_safe(cb, next, list, list) {
                list_del(&cb->list);
                mei_io_cb_free(cb);
        }
index 752ff873f891bb3dc502305506f3f782ede28296..7e1ef0ebbb800bfcf00d7d07aaff02f7a5af7b4a 100644 (file)
@@ -156,7 +156,8 @@ static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov,
 static int _mic_virtio_copy(struct mic_vdev *mvdev,
        struct mic_copy_desc *copy)
 {
-       int ret = 0, iovcnt = copy->iovcnt;
+       int ret = 0;
+       u32 iovcnt = copy->iovcnt;
        struct iovec iov;
        struct iovec __user *u_iov = copy->iov;
        void __user *ubuf = NULL;
index 9b2062d173279438a92b6f1ba548404fe4c429b0..2bef3f76032aa117d8bc2fa06451e832118acce1 100644 (file)
@@ -139,8 +139,11 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum,
 
        ubuf += sizeof(hdr);
        ubufcch = ubuf;
-       if (gru_user_copy_handle(&ubuf, cch))
-               goto fail;
+       if (gru_user_copy_handle(&ubuf, cch)) {
+               if (cch_locked)
+                       unlock_cch_handle(cch);
+               return -EFAULT;
+       }
        if (cch_locked)
                ubufcch->delresp = 0;
        bytes = sizeof(hdr) + GRU_CACHE_LINE_BYTES;
@@ -179,10 +182,6 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum,
                ret = -EFAULT;
 
        return ret ? ret : bytes;
-
-fail:
-       unlock_cch_handle(cch);
-       return -EFAULT;
 }
 
 int gru_dump_chiplet_request(unsigned long arg)
index b9e2000969f025894be4bcae2c6950d699ded3a9..95c894482fddf443d4516ffad39c54adda5be754 100644 (file)
@@ -240,7 +240,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
 
        nid = cpu_to_node(cpu);
        page = alloc_pages_exact_node(nid,
-                                     GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                                     GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                      pg_order);
        if (page == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
index 357bbc54fe4b6f423aa2dcc86ca3a23624748a6b..3e049c13429cfbe730179724053796cc65ba62de 100644 (file)
@@ -197,7 +197,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
        struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
 
        if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
-               limit = dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
+               limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
 
        mq->card = card;
        mq->queue = blk_init_queue(mmc_request_fn, lock);
index 59eba5d2c68574fae787d36d2bd9e5ed29eb9f25..9715a7ba164a042abbba49fd842e9400a677d6fe 100644 (file)
@@ -1584,7 +1584,7 @@ read_retry:
                        }
 
                        if (mtd->ecc_stats.failed - ecc_failures) {
-                               if (retry_mode + 1 <= chip->read_retries) {
+                               if (retry_mode + 1 < chip->read_retries) {
                                        retry_mode++;
                                        ret = nand_setup_read_retry(mtd,
                                                        retry_mode);
index ef4190a02b7bd591af7c97be8ee1e3caecf6f83c..bf642ceef68172b4575d8e9d3263320e0fc7095a 100644 (file)
@@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        int                             i;
        dma_cap_mask_t                  mask;
        unsigned                        sig;
+       unsigned                        oob_index;
        struct resource                 *res;
        struct mtd_part_parser_data     ppdata = {};
 
@@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev)
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
                if (nand_chip->options & NAND_BUSWIDTH_16)
-                       ecclayout->eccpos[0]    = BADBLOCK_MARKER_LENGTH;
+                       oob_index               = BADBLOCK_MARKER_LENGTH;
                else
-                       ecclayout->eccpos[0]    = 1;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+                       oob_index               = 1;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+                       ecclayout->eccpos[i]    = oob_index;
+               /* no reserved-marker in ecclayout for this ecc-scheme */
+               ecclayout->oobfree->offset      =
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                break;
 
        case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
@@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+                       ecclayout->eccpos[i] = oob_index;
+                       if (((i + 1) % nand_chip->ecc.bytes) == 0)
+                               oob_index++;
+               }
+               /* include reserved-marker in ecclayout->oobfree calculation */
+               ecclayout->oobfree->offset      = 1 +
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
                nand_chip->ecc.priv             = nand_bch_init(mtd,
                                                        nand_chip->ecc.size,
@@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+                       ecclayout->eccpos[i]    = oob_index;
+               /* reserved marker already included in ecclayout->eccbytes */
+               ecclayout->oobfree->offset      =
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* This ECC scheme requires ELM H/W block */
                if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) {
                        pr_err("nand: error: could not initialize ELM\n");
@@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) {
+                       ecclayout->eccpos[i] = oob_index;
+                       if (((i + 1) % nand_chip->ecc.bytes) == 0)
+                               oob_index++;
+               }
+               /* include reserved-marker in ecclayout->oobfree calculation */
+               ecclayout->oobfree->offset      = 1 +
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                /* software bch library is used for locating errors */
                nand_chip->ecc.priv             = nand_bch_init(mtd,
                                                        nand_chip->ecc.size,
@@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev)
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
                                                        nand_chip->ecc.size);
-               ecclayout->eccpos[0]            = BADBLOCK_MARKER_LENGTH;
-               ecclayout->oobfree->offset      = ecclayout->eccpos[0] +
-                                                       ecclayout->eccbytes;
+               oob_index                       = BADBLOCK_MARKER_LENGTH;
+               for (i = 0; i < ecclayout->eccbytes; i++, oob_index++)
+                       ecclayout->eccpos[i]    = oob_index;
+               /* reserved marker already included in ecclayout->eccbytes */
+               ecclayout->oobfree->offset      =
+                               ecclayout->eccpos[ecclayout->eccbytes - 1] + 1;
                break;
 #else
                pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n");
@@ -1972,11 +1994,8 @@ static int omap_nand_probe(struct platform_device *pdev)
                goto return_error;
        }
 
-       /* populate remaining ECC layout data */
-       ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH +
-                                                       ecclayout->eccbytes);
-       for (i = 1; i < ecclayout->eccbytes; i++)
-               ecclayout->eccpos[i] = ecclayout->eccpos[0] + i;
+       /* all OOB bytes from oobfree->offset till end off OOB are free */
+       ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset;
        /* check if NAND device's OOB is enough to store ECC signatures */
        if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) {
                pr_err("not enough OOB bytes required = %d, available=%d\n",
index ead861307b3c57aac13bbb187a958a8910062904..c5dad652614d747df33477dbd414c472572aefe5 100644 (file)
@@ -463,8 +463,8 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
                                }
                        }
                        if (found_orphan) {
-                               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                                list_del(&tmp_aeb->u.list);
+                               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                        }
 
                        new_aeb = kmem_cache_alloc(ai->aeb_slab_cache,
@@ -846,16 +846,16 @@ fail_bad:
        ret = UBI_BAD_FASTMAP;
 fail:
        list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) {
-               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                list_del(&tmp_aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
        }
        list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) {
-               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                list_del(&tmp_aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
        }
        list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) {
-               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
                list_del(&tmp_aeb->u.list);
+               kmem_cache_free(ai->aeb_slab_cache, tmp_aeb);
        }
 
        return ret;
index f342278539d50cfb58b0cfea45894bb1c63babd2..89402c3b64f8406ebc0e81a7d79fb341fa57df3d 100644 (file)
@@ -139,7 +139,7 @@ config MACVTAP
          This adds a specialized tap character device driver that is based
          on the MAC-VLAN network interface, called macvtap. A macvtap device
          can be added in the same way as a macvlan device, using 'type
-         macvlan', and then be accessed through the tap user space interface.
+         macvtap', and then be accessed through the tap user space interface.
 
          To compile this driver as a module, choose M here: the module
          will be called macvtap.
@@ -177,11 +177,6 @@ config NETCONSOLE_DYNAMIC
 config NETPOLL
        def_bool NETCONSOLE
 
-config NETPOLL_TRAP
-       bool "Netpoll traffic trapping"
-       default n
-       depends on NETPOLL
-
 config NET_POLL_CONTROLLER
        def_bool NETPOLL
 
index cce1f1bf90b4324e6e2f20e5da6ef53a307bd296..b667a51ed21517a3ee6cf2be6ab4c7e306a713a2 100644 (file)
@@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg)
  */
 static inline void __disable_port(struct port *port)
 {
-       bond_set_slave_inactive_flags(port->slave);
+       bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER);
 }
 
 /**
@@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port)
        struct slave *slave = port->slave;
 
        if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev))
-               bond_set_slave_active_flags(slave);
+               bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER);
 }
 
 /**
@@ -768,11 +768,11 @@ static int ad_lacpdu_send(struct port *port)
 
        lacpdu_header = (struct lacpdu_header *)skb_put(skb, length);
 
-       memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+       ether_addr_copy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr);
        /* Note: source address is set to be the member's PERMANENT address,
         * because we use it to identify loopback lacpdus in receive.
         */
-       memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+       ether_addr_copy(lacpdu_header->hdr.h_source, slave->perm_hwaddr);
        lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
        lacpdu_header->lacpdu = port->lacpdu;
@@ -810,11 +810,11 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
 
        marker_header = (struct bond_marker_header *)skb_put(skb, length);
 
-       memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN);
+       ether_addr_copy(marker_header->hdr.h_dest, lacpdu_mcast_addr);
        /* Note: source address is set to be the member's PERMANENT address,
         * because we use it to identify loopback MARKERs in receive.
         */
-       memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN);
+       ether_addr_copy(marker_header->hdr.h_source, slave->perm_hwaddr);
        marker_header->hdr.h_proto = PKT_TYPE_LACPDU;
 
        marker_header->marker = *marker;
@@ -1079,7 +1079,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
                        /* detect loopback situation */
                        if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system),
                                              &(port->actor_system))) {
-                               pr_err("%s: An illegal loopback occurred on adapter (%s).\nCheck the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
+                               pr_err("%s: An illegal loopback occurred on adapter (%s)\n"
+                                      "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n",
                                       port->slave->bond->dev->name,
                                       port->slave->dev->name);
                                return;
@@ -1283,11 +1284,11 @@ static void ad_port_selection_logic(struct port *port)
                        /* meaning: the port was related to an aggregator
                         * but was not on the aggregator port list
                         */
-                       pr_warn("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
-                               port->slave->bond->dev->name,
-                               port->actor_port_number,
-                               port->slave->dev->name,
-                               port->aggregator->aggregator_identifier);
+                       pr_warn_ratelimited("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n",
+                                           port->slave->bond->dev->name,
+                                           port->actor_port_number,
+                                           port->slave->dev->name,
+                                           port->aggregator->aggregator_identifier);
                }
        }
        /* search on all aggregators for a suitable aggregator for this port */
@@ -1444,9 +1445,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best,
                break;
 
        default:
-               pr_warn("%s: Impossible agg select mode %d\n",
-                       curr->slave->bond->dev->name,
-                       __get_agg_selection_mode(curr->lag_ports));
+               pr_warn_ratelimited("%s: Impossible agg select mode %d\n",
+                                   curr->slave->bond->dev->name,
+                                   __get_agg_selection_mode(curr->lag_ports));
                break;
        }
 
@@ -1559,9 +1560,9 @@ static void ad_agg_selection_logic(struct aggregator *agg)
 
                /* check if any partner replys */
                if (best->is_individual) {
-                       pr_warn("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
-                               best->slave ?
-                               best->slave->bond->dev->name : "NULL");
+                       pr_warn_ratelimited("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n",
+                                           best->slave ?
+                                           best->slave->bond->dev->name : "NULL");
                }
 
                best->is_active = 1;
@@ -1796,8 +1797,6 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout)
        BOND_AD_INFO(bond).agg_select_timer = timeout;
 }
 
-static u16 aggregator_identifier;
-
 /**
  * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures
  * @bond: bonding struct to work on
@@ -1811,7 +1810,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution)
        if (!MAC_ADDRESS_EQUAL(&(BOND_AD_INFO(bond).system.sys_mac_addr),
                                bond->dev->dev_addr)) {
 
-               aggregator_identifier = 0;
+               BOND_AD_INFO(bond).aggregator_identifier = 0;
 
                BOND_AD_INFO(bond).system.sys_priority = 0xFFFF;
                BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr);
@@ -1880,7 +1879,7 @@ void bond_3ad_bind_slave(struct slave *slave)
                ad_initialize_agg(aggregator);
 
                aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr);
-               aggregator->aggregator_identifier = (++aggregator_identifier);
+               aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier;
                aggregator->slave = slave;
                aggregator->is_active = 0;
                aggregator->num_of_ports = 0;
@@ -1950,7 +1949,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
                         * new aggregator
                         */
                        if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) {
-                               pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n",
+                               pr_debug("Some port(s) related to LAG %d - replacing with LAG %d\n",
                                         aggregator->aggregator_identifier,
                                         new_aggregator->aggregator_identifier);
 
@@ -2064,6 +2063,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        struct list_head *iter;
        struct slave *slave;
        struct port *port;
+       bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
        read_lock(&bond->lock);
        rcu_read_lock();
@@ -2081,8 +2081,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
                /* select the active aggregator for the bond */
                if (port) {
                        if (!port->slave) {
-                               pr_warn("%s: Warning: bond's first port is uninitialized\n",
-                                       bond->dev->name);
+                               pr_warn_ratelimited("%s: Warning: bond's first port is uninitialized\n",
+                                                   bond->dev->name);
                                goto re_arm;
                        }
 
@@ -2096,8 +2096,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        bond_for_each_slave_rcu(bond, slave, iter) {
                port = &(SLAVE_AD_INFO(slave).port);
                if (!port->slave) {
-                       pr_warn("%s: Warning: Found an uninitialized port\n",
-                               bond->dev->name);
+                       pr_warn_ratelimited("%s: Warning: Found an uninitialized port\n",
+                                           bond->dev->name);
                        goto re_arm;
                }
 
@@ -2121,8 +2121,19 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
        }
 
 re_arm:
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               if (slave->should_notify) {
+                       should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+                       break;
+               }
+       }
        rcu_read_unlock();
        read_unlock(&bond->lock);
+
+       if (should_notify_rtnl && rtnl_trylock()) {
+               bond_slave_state_notify(bond);
+               rtnl_unlock();
+       }
        queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
 }
 
@@ -2147,8 +2158,8 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
                port = &(SLAVE_AD_INFO(slave).port);
 
                if (!port->slave) {
-                       pr_warn("%s: Warning: port of slave %s is uninitialized\n",
-                               slave->dev->name, slave->bond->dev->name);
+                       pr_warn_ratelimited("%s: Warning: port of slave %s is uninitialized\n",
+                                           slave->dev->name, slave->bond->dev->name);
                        return ret;
                }
 
@@ -2300,9 +2311,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
                port->actor_oper_port_key = (port->actor_admin_port_key &=
                                             ~AD_SPEED_KEY_BITS);
        }
-       pr_debug("Port %d changed link status to %s",
-               port->actor_port_number,
-               (link == BOND_LINK_UP) ? "UP" : "DOWN");
+       pr_debug("Port %d changed link status to %s\n",
+                port->actor_port_number,
+                link == BOND_LINK_UP ? "UP" : "DOWN");
        /* there is no need to reselect a new aggregator, just signal the
         * state machines to reinitialize
         */
@@ -2380,17 +2391,16 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond,
                }
        }
 
-       if (aggregator) {
-               ad_info->aggregator_id = aggregator->aggregator_identifier;
-               ad_info->ports = aggregator->num_of_ports;
-               ad_info->actor_key = aggregator->actor_oper_aggregator_key;
-               ad_info->partner_key = aggregator->partner_oper_aggregator_key;
-               memcpy(ad_info->partner_system,
-                      aggregator->partner_system.mac_addr_value, ETH_ALEN);
-               return 0;
-       }
+       if (!aggregator)
+               return -1;
 
-       return -1;
+       ad_info->aggregator_id = aggregator->aggregator_identifier;
+       ad_info->ports = aggregator->num_of_ports;
+       ad_info->actor_key = aggregator->actor_oper_aggregator_key;
+       ad_info->partner_key = aggregator->partner_oper_aggregator_key;
+       ether_addr_copy(ad_info->partner_system,
+                       aggregator->partner_system.mac_addr_value);
+       return 0;
 }
 
 /* Wrapper used to hold bond->lock so no slave manipulation can occur */
@@ -2469,7 +2479,7 @@ out:
        return NETDEV_TX_OK;
 err_free:
        /* no suitable interface, frame not sent */
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        goto out;
 }
 
index 13dc9d3c5e3460e2e0e4f01e2ab1df2a962d60e2..bb03b1df2f3e799da32d82ca2a5226c8bd031647 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_ether.h>
 
-// General definitions
+/* General definitions */
 #define PKT_TYPE_LACPDU         cpu_to_be16(ETH_P_SLOW)
 #define AD_TIMER_INTERVAL       100 /*msec*/
 
@@ -47,54 +47,54 @@ enum {
        BOND_AD_COUNT = 2,
 };
 
-// rx machine states(43.4.11 in the 802.3ad standard)
+/* rx machine states(43.4.11 in the 802.3ad standard) */
 typedef enum {
        AD_RX_DUMMY,
-       AD_RX_INITIALIZE,     // rx Machine
-       AD_RX_PORT_DISABLED,  // rx Machine
-       AD_RX_LACP_DISABLED,  // rx Machine
-       AD_RX_EXPIRED,        // rx Machine
-       AD_RX_DEFAULTED,      // rx Machine
-       AD_RX_CURRENT         // rx Machine
+       AD_RX_INITIALIZE,       /* rx Machine */
+       AD_RX_PORT_DISABLED,    /* rx Machine */
+       AD_RX_LACP_DISABLED,    /* rx Machine */
+       AD_RX_EXPIRED,          /* rx Machine */
+       AD_RX_DEFAULTED,        /* rx Machine */
+       AD_RX_CURRENT           /* rx Machine */
 } rx_states_t;
 
-// periodic machine states(43.4.12 in the 802.3ad standard)
+/* periodic machine states(43.4.12 in the 802.3ad standard) */
 typedef enum {
        AD_PERIODIC_DUMMY,
-       AD_NO_PERIODIC,        // periodic machine
-       AD_FAST_PERIODIC,      // periodic machine
-       AD_SLOW_PERIODIC,      // periodic machine
-       AD_PERIODIC_TX     // periodic machine
+       AD_NO_PERIODIC,         /* periodic machine */
+       AD_FAST_PERIODIC,       /* periodic machine */
+       AD_SLOW_PERIODIC,       /* periodic machine */
+       AD_PERIODIC_TX          /* periodic machine */
 } periodic_states_t;
 
-// mux machine states(43.4.13 in the 802.3ad standard)
+/* mux machine states(43.4.13 in the 802.3ad standard) */
 typedef enum {
        AD_MUX_DUMMY,
-       AD_MUX_DETACHED,       // mux machine
-       AD_MUX_WAITING,        // mux machine
-       AD_MUX_ATTACHED,       // mux machine
-       AD_MUX_COLLECTING_DISTRIBUTING // mux machine
+       AD_MUX_DETACHED,        /* mux machine */
+       AD_MUX_WAITING,         /* mux machine */
+       AD_MUX_ATTACHED,        /* mux machine */
+       AD_MUX_COLLECTING_DISTRIBUTING  /* mux machine */
 } mux_states_t;
 
-// tx machine states(43.4.15 in the 802.3ad standard)
+/* tx machine states(43.4.15 in the 802.3ad standard) */
 typedef enum {
        AD_TX_DUMMY,
-       AD_TRANSMIT        // tx Machine
+       AD_TRANSMIT             /* tx Machine */
 } tx_states_t;
 
-// rx indication types
+/* rx indication types */
 typedef enum {
-       AD_TYPE_LACPDU = 1,    // type lacpdu
-       AD_TYPE_MARKER     // type marker
+       AD_TYPE_LACPDU = 1,     /* type lacpdu */
+       AD_TYPE_MARKER          /* type marker */
 } pdu_type_t;
 
-// rx marker indication types
+/* rx marker indication types */
 typedef enum {
-       AD_MARKER_INFORMATION_SUBTYPE = 1, // marker imformation subtype
-       AD_MARKER_RESPONSE_SUBTYPE     // marker response subtype
+       AD_MARKER_INFORMATION_SUBTYPE = 1,      /* marker imformation subtype */
+       AD_MARKER_RESPONSE_SUBTYPE              /* marker response subtype */
 } bond_marker_subtype_t;
 
-// timers types(43.4.9 in the 802.3ad standard)
+/* timers types(43.4.9 in the 802.3ad standard) */
 typedef enum {
        AD_CURRENT_WHILE_TIMER,
        AD_ACTOR_CHURN_TIMER,
@@ -105,35 +105,35 @@ typedef enum {
 
 #pragma pack(1)
 
-// Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
+/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */
 typedef struct lacpdu {
-       u8 subtype;                  // = LACP(= 0x01)
+       u8 subtype;             /* = LACP(= 0x01) */
        u8 version_number;
-       u8 tlv_type_actor_info;       // = actor information(type/length/value)
-       u8 actor_information_length; // = 20
+       u8 tlv_type_actor_info; /* = actor information(type/length/value) */
+       u8 actor_information_length;    /* = 20 */
        __be16 actor_system_priority;
        struct mac_addr actor_system;
        __be16 actor_key;
        __be16 actor_port_priority;
        __be16 actor_port;
        u8 actor_state;
-       u8 reserved_3_1[3];          // = 0
-       u8 tlv_type_partner_info;     // = partner information
-       u8 partner_information_length;   // = 20
+       u8 reserved_3_1[3];             /* = 0 */
+       u8 tlv_type_partner_info;       /* = partner information */
+       u8 partner_information_length;  /* = 20 */
        __be16 partner_system_priority;
        struct mac_addr partner_system;
        __be16 partner_key;
        __be16 partner_port_priority;
        __be16 partner_port;
        u8 partner_state;
-       u8 reserved_3_2[3];          // = 0
-       u8 tlv_type_collector_info;       // = collector information
-       u8 collector_information_length; // = 16
+       u8 reserved_3_2[3];             /* = 0 */
+       u8 tlv_type_collector_info;     /* = collector information */
+       u8 collector_information_length;/* = 16 */
        __be16 collector_max_delay;
        u8 reserved_12[12];
-       u8 tlv_type_terminator;      // = terminator
-       u8 terminator_length;        // = 0
-       u8 reserved_50[50];          // = 0
+       u8 tlv_type_terminator;         /* = terminator */
+       u8 terminator_length;           /* = 0 */
+       u8 reserved_50[50];             /* = 0 */
 } __packed lacpdu_t;
 
 typedef struct lacpdu_header {
@@ -141,20 +141,20 @@ typedef struct lacpdu_header {
        struct lacpdu lacpdu;
 } __packed lacpdu_header_t;
 
-// Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard)
+/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */
 typedef struct bond_marker {
-       u8 subtype;              //  = 0x02  (marker PDU)
-       u8 version_number;       //  = 0x01
-       u8 tlv_type;             //  = 0x01  (marker information)
-       //  = 0x02  (marker response information)
-       u8 marker_length;        //  = 0x16
-       u16 requester_port;      //   The number assigned to the port by the requester
-       struct mac_addr requester_system;      //   The requester's system id
-       u32 requester_transaction_id;   //   The transaction id allocated by the requester,
-       u16 pad;                 //  = 0
-       u8 tlv_type_terminator;      //  = 0x00
-       u8 terminator_length;        //  = 0x00
-       u8 reserved_90[90];          //  = 0
+       u8 subtype;             /* = 0x02  (marker PDU) */
+       u8 version_number;      /* = 0x01 */
+       u8 tlv_type;            /* = 0x01  (marker information) */
+       /* = 0x02  (marker response information) */
+       u8 marker_length;       /* = 0x16 */
+       u16 requester_port;     /* The number assigned to the port by the requester */
+       struct mac_addr requester_system;       /* The requester's system id */
+       u32 requester_transaction_id;           /* The transaction id allocated by the requester, */
+       u16 pad;                /* = 0 */
+       u8 tlv_type_terminator; /* = 0x00 */
+       u8 terminator_length;   /* = 0x00 */
+       u8 reserved_90[90];     /* = 0 */
 } __packed bond_marker_t;
 
 typedef struct bond_marker_header {
@@ -173,7 +173,7 @@ struct port;
 #pragma pack(8)
 #endif
 
-// aggregator structure(43.4.5 in the 802.3ad standard)
+/* aggregator structure(43.4.5 in the 802.3ad standard) */
 typedef struct aggregator {
        struct mac_addr aggregator_mac_address;
        u16 aggregator_identifier;
@@ -183,12 +183,12 @@ typedef struct aggregator {
        struct mac_addr partner_system;
        u16 partner_system_priority;
        u16 partner_oper_aggregator_key;
-       u16 receive_state;              // BOOLEAN
-       u16 transmit_state;             // BOOLEAN
+       u16 receive_state;      /* BOOLEAN */
+       u16 transmit_state;     /* BOOLEAN */
        struct port *lag_ports;
-       // ****** PRIVATE PARAMETERS ******
-       struct slave *slave;        // pointer to the bond slave that this aggregator belongs to
-       u16 is_active;      // BOOLEAN. Indicates if this aggregator is active
+       /* ****** PRIVATE PARAMETERS ****** */
+       struct slave *slave;    /* pointer to the bond slave that this aggregator belongs to */
+       u16 is_active;          /* BOOLEAN. Indicates if this aggregator is active */
        u16 num_of_ports;
 } aggregator_t;
 
@@ -201,12 +201,12 @@ struct port_params {
        u16 port_state;
 };
 
-// port structure(43.4.6 in the 802.3ad standard)
+/* port structure(43.4.6 in the 802.3ad standard) */
 typedef struct port {
        u16 actor_port_number;
        u16 actor_port_priority;
-       struct mac_addr actor_system;          // This parameter is added here although it is not specified in the standard, just for simplification
-       u16 actor_system_priority;       // This parameter is added here although it is not specified in the standard, just for simplification
+       struct mac_addr actor_system;   /* This parameter is added here although it is not specified in the standard, just for simplification */
+       u16 actor_system_priority;      /* This parameter is added here although it is not specified in the standard, just for simplification */
        u16 actor_port_aggregator_identifier;
        bool ntt;
        u16 actor_admin_port_key;
@@ -219,24 +219,24 @@ typedef struct port {
 
        bool is_enabled;
 
-       // ****** PRIVATE PARAMETERS ******
-       u16 sm_vars;          // all state machines variables for this port
-       rx_states_t sm_rx_state;        // state machine rx state
-       u16 sm_rx_timer_counter;    // state machine rx timer counter
-       periodic_states_t sm_periodic_state;// state machine periodic state
-       u16 sm_periodic_timer_counter;  // state machine periodic timer counter
-       mux_states_t sm_mux_state;      // state machine mux state
-       u16 sm_mux_timer_counter;   // state machine mux timer counter
-       tx_states_t sm_tx_state;        // state machine tx state
-       u16 sm_tx_timer_counter;    // state machine tx timer counter(allways on - enter to transmit state 3 time per second)
-       struct slave *slave;        // pointer to the bond slave that this port belongs to
-       struct aggregator *aggregator;     // pointer to an aggregator that this port related to
-       struct port *next_port_in_aggregator; // Next port on the linked list of the parent aggregator
-       u32 transaction_id;         // continuous number for identification of Marker PDU's;
-       struct lacpdu lacpdu;          // the lacpdu that will be sent for this port
+       /* ****** PRIVATE PARAMETERS ****** */
+       u16 sm_vars;            /* all state machines variables for this port */
+       rx_states_t sm_rx_state;        /* state machine rx state */
+       u16 sm_rx_timer_counter;        /* state machine rx timer counter */
+       periodic_states_t sm_periodic_state;    /* state machine periodic state */
+       u16 sm_periodic_timer_counter;  /* state machine periodic timer counter */
+       mux_states_t sm_mux_state;      /* state machine mux state */
+       u16 sm_mux_timer_counter;       /* state machine mux timer counter */
+       tx_states_t sm_tx_state;        /* state machine tx state */
+       u16 sm_tx_timer_counter;        /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */
+       struct slave *slave;            /* pointer to the bond slave that this port belongs to */
+       struct aggregator *aggregator;  /* pointer to an aggregator that this port related to */
+       struct port *next_port_in_aggregator;   /* Next port on the linked list of the parent aggregator */
+       u32 transaction_id;             /* continuous number for identification of Marker PDU's; */
+       struct lacpdu lacpdu;           /* the lacpdu that will be sent for this port */
 } port_t;
 
-// system structure
+/* system structure */
 struct ad_system {
        u16 sys_priority;
        struct mac_addr sys_mac_addr;
@@ -246,26 +246,26 @@ struct ad_system {
 #pragma pack()
 #endif
 
-// ================= AD Exported structures to the main bonding code ==================
+/* ========== AD Exported structures to the main bonding code ========== */
 #define BOND_AD_INFO(bond)   ((bond)->ad_info)
 #define SLAVE_AD_INFO(slave) ((slave)->ad_info)
 
 struct ad_bond_info {
-       struct ad_system system;            /* 802.3ad system structure */
-       u32 agg_select_timer;       // Timer to select aggregator after all adapter's hand shakes
+       struct ad_system system;        /* 802.3ad system structure */
+       u32 agg_select_timer;           /* Timer to select aggregator after all adapter's hand shakes */
+       u16 aggregator_identifier;
 };
 
 struct ad_slave_info {
-       struct aggregator aggregator;       // 802.3ad aggregator structure
-       struct port port;                   // 802.3ad port structure
-       spinlock_t state_machine_lock; /* mutex state machines vs.
-                                         incoming LACPDU */
+       struct aggregator aggregator;   /* 802.3ad aggregator structure */
+       struct port port;               /* 802.3ad port structure */
+       spinlock_t state_machine_lock;  /* mutex state machines vs. incoming LACPDU */
        u16 id;
 };
 
-// ================= AD Exported functions to the main bonding code ==================
+/* ========== AD Exported functions to the main bonding code ========== */
 void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution);
-void  bond_3ad_bind_slave(struct slave *slave);
+void bond_3ad_bind_slave(struct slave *slave);
 void bond_3ad_unbind_slave(struct slave *slave);
 void bond_3ad_state_machine_handler(struct work_struct *);
 void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout);
@@ -280,5 +280,5 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
                         struct slave *slave);
 int bond_3ad_set_carrier(struct bonding *bond);
 void bond_3ad_update_lacp_rate(struct bonding *bond);
-#endif //__BOND_3AD_H__
+#endif /* __BOND_3AD_H__ */
 
index a2c47476804dc388406e05b4c425c4be59089add..9f69e818b0009db7881b3f8c862393836e5a604b 100644 (file)
@@ -93,9 +93,8 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
        int i;
        u8 hash = 0;
 
-       for (i = 0; i < hash_size; i++) {
+       for (i = 0; i < hash_size; i++)
                hash ^= hash_start[i];
-       }
 
        return hash;
 }
@@ -190,9 +189,8 @@ static int tlb_initialize(struct bonding *bond)
 
        bond_info->tx_hashtbl = new_hashtbl;
 
-       for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) {
+       for (i = 0; i < TLB_HASH_TABLE_SIZE; i++)
                tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0);
-       }
 
        _unlock_tx_hashtbl_bh(bond);
 
@@ -264,9 +262,8 @@ static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
                        hash_table[hash_index].next = next_index;
                        hash_table[hash_index].prev = TLB_NULL_INDEX;
 
-                       if (next_index != TLB_NULL_INDEX) {
+                       if (next_index != TLB_NULL_INDEX)
                                hash_table[next_index].prev = hash_index;
-                       }
 
                        slave_info->head = hash_index;
                        slave_info->load +=
@@ -274,9 +271,8 @@ static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index,
                }
        }
 
-       if (assigned_slave) {
+       if (assigned_slave)
                hash_table[hash_index].tx_bytes += skb_len;
-       }
 
        return assigned_slave;
 }
@@ -329,7 +325,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
 
        _lock_rx_hashtbl_bh(bond);
 
-       hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
+       hash_index = _simple_hash((u8 *)&(arp->ip_src), sizeof(arp->ip_src));
        client_info = &(bond_info->rx_hashtbl[hash_index]);
 
        if ((client_info->assigned) &&
@@ -337,7 +333,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
            (client_info->ip_dst == arp->ip_src) &&
            (!ether_addr_equal_64bits(client_info->mac_dst, arp->mac_src))) {
                /* update the clients MAC address */
-               memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN);
+               ether_addr_copy(client_info->mac_dst, arp->mac_src);
                client_info->ntt = 1;
                bond_info->rx_ntt = 1;
        }
@@ -451,9 +447,8 @@ static struct slave *__rlb_next_rx_slave(struct bonding *bond)
  */
 static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[])
 {
-       if (!bond->curr_active_slave) {
+       if (!bond->curr_active_slave)
                return;
-       }
 
        if (!bond->alb_info.primary_is_promisc) {
                if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1))
@@ -513,9 +508,8 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
 
        write_lock_bh(&bond->curr_slave_lock);
 
-       if (slave != bond->curr_active_slave) {
+       if (slave != bond->curr_active_slave)
                rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr);
-       }
 
        write_unlock_bh(&bond->curr_slave_lock);
 }
@@ -524,9 +518,8 @@ static void rlb_update_client(struct rlb_client_info *client_info)
 {
        int i;
 
-       if (!client_info->slave) {
+       if (!client_info->slave)
                return;
-       }
 
        for (i = 0; i < RLB_ARP_BURST_SIZE; i++) {
                struct sk_buff *skb;
@@ -574,9 +567,8 @@ static void rlb_update_rx_clients(struct bonding *bond)
                client_info = &(bond_info->rx_hashtbl[hash_index]);
                if (client_info->ntt) {
                        rlb_update_client(client_info);
-                       if (bond_info->rlb_update_retry_counter == 0) {
+                       if (bond_info->rlb_update_retry_counter == 0)
                                client_info->ntt = 0;
-                       }
                }
        }
 
@@ -610,10 +602,10 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
                }
        }
 
-       // update the team's flag only after the whole iteration
+       /* update the team's flag only after the whole iteration */
        if (ntt) {
                bond_info->rx_ntt = 1;
-               //fasten the change
+               /* fasten the change */
                bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY;
        }
 
@@ -677,9 +669,9 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
                        /* the entry is already assigned to this client */
                        if (!ether_addr_equal_64bits(arp->mac_dst, mac_bcast)) {
                                /* update mac address from arp */
-                               memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
+                               ether_addr_copy(client_info->mac_dst, arp->mac_dst);
                        }
-                       memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
+                       ether_addr_copy(client_info->mac_src, arp->mac_src);
 
                        assigned_slave = client_info->slave;
                        if (assigned_slave) {
@@ -719,8 +711,8 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
                 * will be updated with clients actual unicast mac address
                 * upon receiving an arp reply.
                 */
-               memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
-               memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
+               ether_addr_copy(client_info->mac_dst, arp->mac_dst);
+               ether_addr_copy(client_info->mac_src, arp->mac_src);
                client_info->slave = assigned_slave;
 
                if (!ether_addr_equal_64bits(client_info->mac_dst, mac_bcast)) {
@@ -730,7 +722,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
                        client_info->ntt = 0;
                }
 
-               if (!vlan_get_tag(skb, &client_info->vlan_id))
+               if (vlan_get_tag(skb, &client_info->vlan_id))
                        client_info->vlan_id = 0;
 
                if (!client_info->assigned) {
@@ -770,9 +762,8 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
                * rx channel
                */
                tx_slave = rlb_choose_channel(skb, bond);
-               if (tx_slave) {
-                       memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
-               }
+               if (tx_slave)
+                       ether_addr_copy(arp->mac_src, tx_slave->dev->dev_addr);
                pr_debug("Server sent ARP Reply packet\n");
        } else if (arp->op_code == htons(ARPOP_REQUEST)) {
                /* Create an entry in the rx_hashtbl for this client as a
@@ -824,9 +815,8 @@ static void rlb_rebalance(struct bonding *bond)
        }
 
        /* update the team's flag only after the whole iteration */
-       if (ntt) {
+       if (ntt)
                bond_info->rx_ntt = 1;
-       }
        _unlock_rx_hashtbl_bh(bond);
 }
 
@@ -923,7 +913,7 @@ static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash)
 static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp)
 {
        struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
-       u32 ip_src_hash = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
+       u32 ip_src_hash = _simple_hash((u8 *)&(arp->ip_src), sizeof(arp->ip_src));
        u32 index;
 
        _lock_rx_hashtbl_bh(bond);
@@ -957,9 +947,8 @@ static int rlb_initialize(struct bonding *bond)
 
        bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
 
-       for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) {
+       for (i = 0; i < RLB_HASH_TABLE_SIZE; i++)
                rlb_init_table_entry(bond_info->rx_hashtbl + i);
-       }
 
        _unlock_rx_hashtbl_bh(bond);
 
@@ -1014,9 +1003,9 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[],
        char *data;
 
        memset(&pkt, 0, size);
-       memcpy(pkt.mac_dst, mac_addr, ETH_ALEN);
-       memcpy(pkt.mac_src, mac_addr, ETH_ALEN);
-       pkt.type = cpu_to_be16(ETH_P_LOOP);
+       ether_addr_copy(pkt.mac_dst, mac_addr);
+       ether_addr_copy(pkt.mac_src, mac_addr);
+       pkt.type = cpu_to_be16(ETH_P_LOOPBACK);
 
        skb = dev_alloc_skb(size);
        if (!skb)
@@ -1097,7 +1086,7 @@ static void alb_swap_mac_addr(struct slave *slave1, struct slave *slave2)
 {
        u8 tmp_mac_addr[ETH_ALEN];
 
-       memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(tmp_mac_addr, slave1->dev->dev_addr);
        alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr);
        alb_set_slave_mac_addr(slave2, tmp_mac_addr);
 
@@ -1254,9 +1243,9 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav
        if (free_mac_slave) {
                alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr);
 
-               pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
-                          bond->dev->name, slave->dev->name,
-                          free_mac_slave->dev->name);
+               pr_warn("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n",
+                       bond->dev->name, slave->dev->name,
+                       free_mac_slave->dev->name);
 
        } else if (has_bond_addr) {
                pr_err("%s: Error: the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n",
@@ -1294,12 +1283,12 @@ static int alb_set_mac_address(struct bonding *bond, void *addr)
 
        bond_for_each_slave(bond, slave, iter) {
                /* save net_device's current hw address */
-               memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(tmp_addr, slave->dev->dev_addr);
 
                res = dev_set_mac_address(slave->dev, addr);
 
                /* restore net_device's hw address */
-               memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+               ether_addr_copy(slave->dev->dev_addr, tmp_addr);
 
                if (res)
                        goto unwind;
@@ -1315,9 +1304,9 @@ unwind:
        bond_for_each_slave(bond, rollback_slave, iter) {
                if (rollback_slave == slave)
                        break;
-               memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(tmp_addr, rollback_slave->dev->dev_addr);
                dev_set_mac_address(rollback_slave->dev, &sa);
-               memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+               ether_addr_copy(rollback_slave->dev->dev_addr, tmp_addr);
        }
 
        return res;
@@ -1330,9 +1319,8 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled)
        int res;
 
        res = tlb_initialize(bond);
-       if (res) {
+       if (res)
                return res;
-       }
 
        if (rlb_enabled) {
                bond->alb_info.rlb_enabled = 1;
@@ -1355,9 +1343,8 @@ void bond_alb_deinitialize(struct bonding *bond)
 
        tlb_deinitialize(bond);
 
-       if (bond_info->rlb_enabled) {
+       if (bond_info->rlb_enabled)
                rlb_deinitialize(bond);
-       }
 }
 
 int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
@@ -1436,14 +1423,13 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
                        break;
                }
 
-               hash_start = (char*)eth_data->h_dest;
+               hash_start = (char *)eth_data->h_dest;
                hash_size = ETH_ALEN;
                break;
        case ETH_P_ARP:
                do_tx_balance = 0;
-               if (bond_info->rlb_enabled) {
+               if (bond_info->rlb_enabled)
                        tx_slave = rlb_arp_xmit(skb, bond);
-               }
                break;
        default:
                do_tx_balance = 0;
@@ -1463,23 +1449,22 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
 
        if (tx_slave && SLAVE_IS_OK(tx_slave)) {
                if (tx_slave != rcu_dereference(bond->curr_active_slave)) {
-                       memcpy(eth_data->h_source,
-                              tx_slave->dev->dev_addr,
-                              ETH_ALEN);
+                       ether_addr_copy(eth_data->h_source,
+                                       tx_slave->dev->dev_addr);
                }
 
                bond_dev_queue_xmit(bond, skb, tx_slave->dev);
                goto out;
-       } else {
-               if (tx_slave) {
-                       _lock_tx_hashtbl(bond);
-                       __tlb_clear_slave(bond, tx_slave, 0);
-                       _unlock_tx_hashtbl(bond);
-               }
+       }
+
+       if (tx_slave) {
+               _lock_tx_hashtbl(bond);
+               __tlb_clear_slave(bond, tx_slave, 0);
+               _unlock_tx_hashtbl(bond);
        }
 
        /* no suitable interface, frame not sent */
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 out:
        return NETDEV_TX_OK;
 }
@@ -1577,11 +1562,10 @@ void bond_alb_monitor(struct work_struct *work)
                                --bond_info->rlb_update_delay_counter;
                        } else {
                                rlb_update_rx_clients(bond);
-                               if (bond_info->rlb_update_retry_counter) {
+                               if (bond_info->rlb_update_retry_counter)
                                        --bond_info->rlb_update_retry_counter;
-                               } else {
+                               else
                                        bond_info->rx_ntt = 0;
-                               }
                        }
                }
        }
@@ -1598,23 +1582,20 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave)
        int res;
 
        res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr);
-       if (res) {
+       if (res)
                return res;
-       }
 
        res = alb_handle_addr_collision_on_attach(bond, slave);
-       if (res) {
+       if (res)
                return res;
-       }
 
        tlb_init_slave(slave);
 
        /* order a rebalance ASAP */
        bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
 
-       if (bond->alb_info.rlb_enabled) {
+       if (bond->alb_info.rlb_enabled)
                bond->alb_info.rlb_rebalance = 1;
-       }
 
        return 0;
 }
@@ -1645,9 +1626,8 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
 
        if (link == BOND_LINK_DOWN) {
                tlb_clear_slave(bond, slave, 0);
-               if (bond->alb_info.rlb_enabled) {
+               if (bond->alb_info.rlb_enabled)
                        rlb_clear_slave(bond, slave);
-               }
        } else if (link == BOND_LINK_UP) {
                /* order a rebalance ASAP */
                bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;
@@ -1723,14 +1703,14 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave
                struct sockaddr sa;
                u8 tmp_addr[ETH_ALEN];
 
-               memcpy(tmp_addr, new_slave->dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(tmp_addr, new_slave->dev->dev_addr);
 
                memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len);
                sa.sa_family = bond->dev->type;
                /* we don't care if it can't change its mac, best effort */
                dev_set_mac_address(new_slave->dev, &sa);
 
-               memcpy(new_slave->dev->dev_addr, tmp_addr, ETH_ALEN);
+               ether_addr_copy(new_slave->dev->dev_addr, tmp_addr);
        }
 
        /* curr_active_slave must be set before calling alb_swap_mac_addr */
@@ -1759,14 +1739,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
        struct slave *swap_slave;
        int res;
 
-       if (!is_valid_ether_addr(sa->sa_data)) {
+       if (!is_valid_ether_addr(sa->sa_data))
                return -EADDRNOTAVAIL;
-       }
 
        res = alb_set_mac_address(bond, addr);
-       if (res) {
+       if (res)
                return res;
-       }
 
        memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len);
 
@@ -1774,9 +1752,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
         * Otherwise we'll need to pass the new address to it and handle
         * duplications.
         */
-       if (!bond->curr_active_slave) {
+       if (!bond->curr_active_slave)
                return 0;
-       }
 
        swap_slave = bond_slave_has_mac(bond, bond_dev->dev_addr);
 
@@ -1800,8 +1777,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
 
 void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
 {
-       if (bond->alb_info.rlb_enabled) {
+       if (bond->alb_info.rlb_enabled)
                rlb_clear_vlan(bond, vlan_id);
-       }
 }
 
index 5fc4c2351478b21f98ba8ed2d2c329275e30ed39..2d3f7fa541ffe755fc1bf5f9e51aeaa464b4e032 100644 (file)
@@ -69,7 +69,7 @@ void bond_debug_register(struct bonding *bond)
                debugfs_create_dir(bond->dev->name, bonding_debug_root);
 
        if (!bond->debug_dir) {
-               pr_warning("%s: Warning: failed to register to debugfs\n",
+               pr_warn("%s: Warning: failed to register to debugfs\n",
                        bond->dev->name);
                return;
        }
@@ -98,9 +98,8 @@ void bond_debug_reregister(struct bonding *bond)
        if (d) {
                bond->debug_dir = d;
        } else {
-               pr_warning("%s: Warning: failed to reregister, "
-                               "so just unregister old one\n",
-                               bond->dev->name);
+               pr_warn("%s: Warning: failed to reregister, so just unregister old one\n",
+                       bond->dev->name);
                bond_debug_unregister(bond);
        }
 }
@@ -110,8 +109,7 @@ void bond_create_debugfs(void)
        bonding_debug_root = debugfs_create_dir("bonding", NULL);
 
        if (!bonding_debug_root) {
-               pr_warning("Warning: Cannot create bonding directory"
-                               " in debugfs\n");
+               pr_warn("Warning: Cannot create bonding directory in debugfs\n");
        }
 }
 
index 4c08018d7333138a95d0d6a3c72c67131f842ed5..95a6ca7d9e51950078d5c5f6a2e7281ab18621e9 100644 (file)
@@ -673,12 +673,12 @@ static void bond_do_fail_over_mac(struct bonding *bond,
                write_unlock_bh(&bond->curr_slave_lock);
 
                if (old_active) {
-                       memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN);
-                       memcpy(saddr.sa_data, old_active->dev->dev_addr,
-                              ETH_ALEN);
+                       ether_addr_copy(tmp_mac, new_active->dev->dev_addr);
+                       ether_addr_copy(saddr.sa_data,
+                                       old_active->dev->dev_addr);
                        saddr.sa_family = new_active->dev->type;
                } else {
-                       memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN);
+                       ether_addr_copy(saddr.sa_data, bond->dev->dev_addr);
                        saddr.sa_family = bond->dev->type;
                }
 
@@ -692,7 +692,7 @@ static void bond_do_fail_over_mac(struct bonding *bond,
                if (!old_active)
                        goto out;
 
-               memcpy(saddr.sa_data, tmp_mac, ETH_ALEN);
+               ether_addr_copy(saddr.sa_data, tmp_mac);
                saddr.sa_family = old_active->dev->type;
 
                rv = dev_set_mac_address(old_active->dev, &saddr);
@@ -798,11 +798,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                return;
 
        if (new_active) {
-               new_active->jiffies = jiffies;
+               new_active->last_link_up = jiffies;
 
                if (new_active->link == BOND_LINK_BACK) {
                        if (USES_PRIMARY(bond->params.mode)) {
-                               pr_info("%s: making interface %s the new active one %d ms earlier.\n",
+                               pr_info("%s: making interface %s the new active one %d ms earlier\n",
                                        bond->dev->name, new_active->dev->name,
                                        (bond->params.updelay - new_active->delay) * bond->params.miimon);
                        }
@@ -817,7 +817,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                                bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
                } else {
                        if (USES_PRIMARY(bond->params.mode)) {
-                               pr_info("%s: making interface %s the new active one.\n",
+                               pr_info("%s: making interface %s the new active one\n",
                                        bond->dev->name, new_active->dev->name);
                        }
                }
@@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
        if (bond_is_lb(bond)) {
                bond_alb_handle_active_change(bond, new_active);
                if (old_active)
-                       bond_set_slave_inactive_flags(old_active);
+                       bond_set_slave_inactive_flags(old_active,
+                                                     BOND_SLAVE_NOTIFY_NOW);
                if (new_active)
-                       bond_set_slave_active_flags(new_active);
+                       bond_set_slave_active_flags(new_active,
+                                                   BOND_SLAVE_NOTIFY_NOW);
        } else {
                rcu_assign_pointer(bond->curr_active_slave, new_active);
        }
 
        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
                if (old_active)
-                       bond_set_slave_inactive_flags(old_active);
+                       bond_set_slave_inactive_flags(old_active,
+                                                     BOND_SLAVE_NOTIFY_NOW);
 
                if (new_active) {
                        bool should_notify_peers = false;
 
-                       bond_set_slave_active_flags(new_active);
+                       bond_set_slave_active_flags(new_active,
+                                                   BOND_SLAVE_NOTIFY_NOW);
 
                        if (bond->params.fail_over_mac)
                                bond_do_fail_over_mac(bond, new_active,
@@ -906,7 +910,7 @@ void bond_select_active_slave(struct bonding *bond)
                        pr_info("%s: first active interface up!\n",
                                bond->dev->name);
                } else {
-                       pr_info("%s: now running without any active interface !\n",
+                       pr_info("%s: now running without any active interface!\n",
                                bond->dev->name);
                }
        }
@@ -918,12 +922,12 @@ static inline int slave_enable_netpoll(struct slave *slave)
        struct netpoll *np;
        int err = 0;
 
-       np = kzalloc(sizeof(*np), GFP_ATOMIC);
+       np = kzalloc(sizeof(*np), GFP_KERNEL);
        err = -ENOMEM;
        if (!np)
                goto out;
 
-       err = __netpoll_setup(np, slave->dev, GFP_ATOMIC);
+       err = __netpoll_setup(np, slave->dev);
        if (err) {
                kfree(np);
                goto out;
@@ -942,14 +946,6 @@ static inline void slave_disable_netpoll(struct slave *slave)
        slave->np = NULL;
        __netpoll_free_async(np);
 }
-static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
-{
-       if (slave_dev->priv_flags & IFF_DISABLE_NETPOLL)
-               return false;
-       if (!slave_dev->netdev_ops->ndo_poll_controller)
-               return false;
-       return true;
-}
 
 static void bond_poll_controller(struct net_device *bond_dev)
 {
@@ -966,7 +962,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
                        slave_disable_netpoll(slave);
 }
 
-static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
+static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
 {
        struct bonding *bond = netdev_priv(dev);
        struct list_head *iter;
@@ -1115,9 +1111,6 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
        slave = bond_slave_get_rcu(skb->dev);
        bond = slave->bond;
 
-       if (bond->params.arp_interval)
-               slave->dev->last_rx = jiffies;
-
        recv_probe = ACCESS_ONCE(bond->recv_probe);
        if (recv_probe) {
                ret = recv_probe(skb, bond, slave);
@@ -1142,7 +1135,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
                        kfree_skb(skb);
                        return RX_HANDLER_CONSUMED;
                }
-               memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(eth_hdr(skb)->h_dest, bond->dev->dev_addr);
        }
 
        return ret;
@@ -1183,16 +1176,21 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        if (!bond->params.use_carrier &&
            slave_dev->ethtool_ops->get_link == NULL &&
            slave_ops->ndo_do_ioctl == NULL) {
-               pr_warning("%s: Warning: no link monitoring support for %s\n",
-                          bond_dev->name, slave_dev->name);
+               pr_warn("%s: Warning: no link monitoring support for %s\n",
+                       bond_dev->name, slave_dev->name);
        }
 
        /* already enslaved */
        if (slave_dev->flags & IFF_SLAVE) {
-               pr_debug("Error, Device was already enslaved\n");
+               pr_debug("Error: Device was already enslaved\n");
                return -EBUSY;
        }
 
+       if (bond_dev == slave_dev) {
+               pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name);
+               return -EPERM;
+       }
+
        /* vlan challenged mutual exclusion */
        /* no need to lock since we're protected by rtnl_lock */
        if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
@@ -1202,9 +1200,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                               bond_dev->name, slave_dev->name, bond_dev->name);
                        return -EPERM;
                } else {
-                       pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
-                                  bond_dev->name, slave_dev->name,
-                                  slave_dev->name, bond_dev->name);
+                       pr_warn("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
+                               bond_dev->name, slave_dev->name,
+                               slave_dev->name, bond_dev->name);
                }
        } else {
                pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
@@ -1217,7 +1215,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * enslaving it; the old ifenslave will not.
         */
        if ((slave_dev->flags & IFF_UP)) {
-               pr_err("%s is up. This may be due to an out of date ifenslave.\n",
+               pr_err("%s is up - this may be due to an out of date ifenslave\n",
                       slave_dev->name);
                res = -EPERM;
                goto err_undo_flags;
@@ -1261,20 +1259,23 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                                 bond_dev);
                }
        } else if (bond_dev->type != slave_dev->type) {
-               pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it.\n",
-                      slave_dev->name,
-                      slave_dev->type, bond_dev->type);
+               pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it\n",
+                      slave_dev->name, slave_dev->type, bond_dev->type);
                res = -EINVAL;
                goto err_undo_flags;
        }
 
        if (slave_ops->ndo_set_mac_address == NULL) {
                if (!bond_has_slaves(bond)) {
-                       pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.",
-                                  bond_dev->name);
-                       bond->params.fail_over_mac = BOND_FOM_ACTIVE;
+                       pr_warn("%s: Warning: The first slave device specified does not support setting the MAC address\n",
+                               bond_dev->name);
+                       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
+                               bond->params.fail_over_mac = BOND_FOM_ACTIVE;
+                               pr_warn("%s: Setting fail_over_mac to active for active-backup mode\n",
+                                       bond_dev->name);
+                       }
                } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
-                       pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active.\n",
+                       pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n",
                               bond_dev->name);
                        res = -EOPNOTSUPP;
                        goto err_undo_flags;
@@ -1313,9 +1314,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
         * that need it, and for restoring it upon release, and then
         * set it to the master's address
         */
-       memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr);
 
-       if (!bond->params.fail_over_mac) {
+       if (!bond->params.fail_over_mac ||
+           bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
                /*
                 * Set slave to master's mac address.  The application already
                 * set the master's mac address to that of the first slave
@@ -1396,10 +1398,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        bond_update_speed_duplex(new_slave);
 
-       new_slave->last_arp_rx = jiffies -
+       new_slave->last_rx = jiffies -
                (msecs_to_jiffies(bond->params.arp_interval) + 1);
        for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
-               new_slave->target_last_arp_rx[i] = new_slave->last_arp_rx;
+               new_slave->target_last_arp_rx[i] = new_slave->last_rx;
 
        if (bond->params.miimon && !bond->params.use_carrier) {
                link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@@ -1414,12 +1416,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                         * supported); thus, we don't need to change
                         * the messages for netif_carrier.
                         */
-                       pr_warning("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details.\n",
-                              bond_dev->name, slave_dev->name);
+                       pr_warn("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n",
+                               bond_dev->name, slave_dev->name);
                } else if (link_reporting == -1) {
                        /* unable get link status using mii/ethtool */
-                       pr_warning("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface.\n",
-                                  bond_dev->name, slave_dev->name);
+                       pr_warn("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n",
+                               bond_dev->name, slave_dev->name);
                }
        }
 
@@ -1443,10 +1445,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        if (new_slave->link != BOND_LINK_DOWN)
-               new_slave->jiffies = jiffies;
+               new_slave->last_link_up = jiffies;
        pr_debug("Initial state of slave_dev is BOND_LINK_%s\n",
-               new_slave->link == BOND_LINK_DOWN ? "DOWN" :
-                       (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
+                new_slave->link == BOND_LINK_DOWN ? "DOWN" :
+                (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
 
        if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
                /* if there is a primary slave, remember it */
@@ -1458,14 +1460,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        switch (bond->params.mode) {
        case BOND_MODE_ACTIVEBACKUP:
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave,
+                                             BOND_SLAVE_NOTIFY_NOW);
                break;
        case BOND_MODE_8023AD:
                /* in 802.3ad mode, the internal mechanism
                 * will activate the slaves in the selected
                 * aggregator
                 */
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
                /* if this is the first slave */
                if (!prev_slave) {
                        SLAVE_AD_INFO(new_slave).id = 1;
@@ -1483,7 +1486,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        case BOND_MODE_TLB:
        case BOND_MODE_ALB:
                bond_set_active_slave(new_slave);
-               bond_set_slave_inactive_flags(new_slave);
+               bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
                break;
        default:
                pr_debug("This slave is always active in trunk mode\n");
@@ -1505,10 +1508,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        slave_dev->npinfo = bond->dev->npinfo;
        if (slave_dev->npinfo) {
                if (slave_enable_netpoll(new_slave)) {
-                       read_unlock(&bond->lock);
-                       pr_info("Error, %s: master_dev is using netpoll, "
-                                "but new slave device does not support netpoll.\n",
-                                bond_dev->name);
+                       pr_info("Error, %s: master_dev is using netpoll, but new slave device does not support netpoll\n",
+                               bond_dev->name);
                        res = -EBUSY;
                        goto err_detach;
                }
@@ -1539,15 +1540,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
        bond_set_carrier(bond);
 
        if (USES_PRIMARY(bond->params.mode)) {
+               block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
                bond_select_active_slave(bond);
                write_unlock_bh(&bond->curr_slave_lock);
+               unblock_netpoll_tx();
        }
 
-       pr_info("%s: enslaving %s as a%s interface with a%s link.\n",
+       pr_info("%s: Enslaving %s as %s interface with %s link\n",
                bond_dev->name, slave_dev->name,
-               bond_is_active_slave(new_slave) ? "n active" : " backup",
-               new_slave->link != BOND_LINK_DOWN ? "n up" : " down");
+               bond_is_active_slave(new_slave) ? "an active" : "a backup",
+               new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
 
        /* enslave is successful */
        return 0;
@@ -1567,10 +1570,12 @@ err_detach:
        if (bond->primary_slave == new_slave)
                bond->primary_slave = NULL;
        if (bond->curr_active_slave == new_slave) {
+               block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
                bond_change_active_slave(bond, NULL);
                bond_select_active_slave(bond);
                write_unlock_bh(&bond->curr_slave_lock);
+               unblock_netpoll_tx();
        }
        slave_disable_netpoll(new_slave);
 
@@ -1579,12 +1584,13 @@ err_close:
        dev_close(slave_dev);
 
 err_restore_mac:
-       if (!bond->params.fail_over_mac) {
+       if (!bond->params.fail_over_mac ||
+           bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
                /* XXX TODO - fom follow mode needs to change master's
                 * MAC if this slave's MAC is in use by the bond, or at
                 * least print a warning.
                 */
-               memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+               ether_addr_copy(addr.sa_data, new_slave->perm_hwaddr);
                addr.sa_family = slave_dev->type;
                dev_set_mac_address(slave_dev, &addr);
        }
@@ -1629,7 +1635,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
            !netdev_has_upper_dev(slave_dev, bond_dev)) {
-               pr_err("%s: Error: cannot release %s.\n",
+               pr_err("%s: Error: cannot release %s\n",
                       bond_dev->name, slave_dev->name);
                return -EINVAL;
        }
@@ -1645,9 +1651,6 @@ static int __bond_release_one(struct net_device *bond_dev,
                return -EINVAL;
        }
 
-       /* release the slave from its bond */
-       bond->slave_cnt--;
-
        bond_sysfs_slave_del(slave);
 
        bond_upper_dev_unlink(bond_dev, slave_dev);
@@ -1663,7 +1666,7 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        write_unlock_bh(&bond->lock);
 
-       pr_info("%s: releasing %s interface %s\n",
+       pr_info("%s: Releasing %s interface %s\n",
                bond_dev->name,
                bond_is_active_slave(slave) ? "active" : "backup",
                slave_dev->name);
@@ -1672,13 +1675,14 @@ static int __bond_release_one(struct net_device *bond_dev,
 
        bond->current_arp_slave = NULL;
 
-       if (!all && !bond->params.fail_over_mac) {
+       if (!all && (!bond->params.fail_over_mac ||
+                    bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
                if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) &&
                    bond_has_slaves(bond))
-                       pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n",
-                                  bond_dev->name, slave_dev->name,
-                                  slave->perm_hwaddr,
-                                  bond_dev->name, slave_dev->name);
+                       pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n",
+                               bond_dev->name, slave_dev->name,
+                               slave->perm_hwaddr,
+                               bond_dev->name, slave_dev->name);
        }
 
        if (bond->primary_slave == slave)
@@ -1719,15 +1723,16 @@ static int __bond_release_one(struct net_device *bond_dev,
                eth_hw_addr_random(bond_dev);
 
                if (vlan_uses_dev(bond_dev)) {
-                       pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n",
-                                  bond_dev->name, bond_dev->name);
-                       pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n",
-                                  bond_dev->name);
+                       pr_warn("%s: Warning: clearing HW address of %s while it still has VLANs\n",
+                               bond_dev->name, bond_dev->name);
+                       pr_warn("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs\n",
+                               bond_dev->name);
                }
        }
 
        unblock_netpoll_tx();
        synchronize_rcu();
+       bond->slave_cnt--;
 
        if (!bond_has_slaves(bond)) {
                call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev);
@@ -1737,7 +1742,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        bond_compute_features(bond);
        if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
            (old_features & NETIF_F_VLAN_CHALLENGED))
-               pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
+               pr_info("%s: last VLAN challenged slave %s left bond %s - VLAN blocking is removed\n",
                        bond_dev->name, slave_dev->name, bond_dev->name);
 
        /* must do this from outside any spinlocks */
@@ -1769,9 +1774,10 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* close slave before restoring its mac address */
        dev_close(slave_dev);
 
-       if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
+       if (bond->params.fail_over_mac != BOND_FOM_ACTIVE ||
+           bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
                /* restore original ("permanent") mac address */
-               memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+               ether_addr_copy(addr.sa_data, slave->perm_hwaddr);
                addr.sa_family = slave_dev->type;
                dev_set_mac_address(slave_dev, &addr);
        }
@@ -1804,7 +1810,7 @@ static int  bond_release_and_destroy(struct net_device *bond_dev,
        ret = bond_release(bond_dev, slave_dev);
        if (ret == 0 && !bond_has_slaves(bond)) {
                bond_dev->priv_flags |= IFF_DISABLE_NETPOLL;
-               pr_info("%s: destroying bond %s.\n",
+               pr_info("%s: Destroying bond %s\n",
                        bond_dev->name, bond_dev->name);
                unregister_netdevice(bond_dev);
        }
@@ -1818,9 +1824,7 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
        info->bond_mode = bond->params.mode;
        info->miimon = bond->params.miimon;
 
-       read_lock(&bond->lock);
        info->num_slaves = bond->slave_cnt;
-       read_unlock(&bond->lock);
 
        return 0;
 }
@@ -1832,7 +1836,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
        int i = 0, res = -ENODEV;
        struct slave *slave;
 
-       read_lock(&bond->lock);
        bond_for_each_slave(bond, slave, iter) {
                if (i++ == (int)info->slave_id) {
                        res = 0;
@@ -1843,7 +1846,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
                        break;
                }
        }
-       read_unlock(&bond->lock);
 
        return res;
 }
@@ -1873,7 +1875,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                        slave->link = BOND_LINK_FAIL;
                        slave->delay = bond->params.downdelay;
                        if (slave->delay) {
-                               pr_info("%s: link status down for %sinterface %s, disabling it in %d ms.\n",
+                               pr_info("%s: link status down for %sinterface %s, disabling it in %d ms\n",
                                        bond->dev->name,
                                        (bond->params.mode ==
                                         BOND_MODE_ACTIVEBACKUP) ?
@@ -1889,8 +1891,8 @@ static int bond_miimon_inspect(struct bonding *bond)
                                 * recovered before downdelay expired
                                 */
                                slave->link = BOND_LINK_UP;
-                               slave->jiffies = jiffies;
-                               pr_info("%s: link status up again after %d ms for interface %s.\n",
+                               slave->last_link_up = jiffies;
+                               pr_info("%s: link status up again after %d ms for interface %s\n",
                                        bond->dev->name,
                                        (bond->params.downdelay - slave->delay) *
                                        bond->params.miimon,
@@ -1915,7 +1917,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                        slave->delay = bond->params.updelay;
 
                        if (slave->delay) {
-                               pr_info("%s: link status up for interface %s, enabling it in %d ms.\n",
+                               pr_info("%s: link status up for interface %s, enabling it in %d ms\n",
                                        bond->dev->name, slave->dev->name,
                                        ignore_updelay ? 0 :
                                        bond->params.updelay *
@@ -1925,7 +1927,7 @@ static int bond_miimon_inspect(struct bonding *bond)
                case BOND_LINK_BACK:
                        if (!link_state) {
                                slave->link = BOND_LINK_DOWN;
-                               pr_info("%s: link status down again after %d ms for interface %s.\n",
+                               pr_info("%s: link status down again after %d ms for interface %s\n",
                                        bond->dev->name,
                                        (bond->params.updelay - slave->delay) *
                                        bond->params.miimon,
@@ -1964,7 +1966,7 @@ static void bond_miimon_commit(struct bonding *bond)
 
                case BOND_LINK_UP:
                        slave->link = BOND_LINK_UP;
-                       slave->jiffies = jiffies;
+                       slave->last_link_up = jiffies;
 
                        if (bond->params.mode == BOND_MODE_8023AD) {
                                /* prevent it from being the active one */
@@ -1977,7 +1979,7 @@ static void bond_miimon_commit(struct bonding *bond)
                                bond_set_backup_slave(slave);
                        }
 
-                       pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n",
+                       pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex\n",
                                bond->dev->name, slave->dev->name,
                                slave->speed == SPEED_UNKNOWN ? 0 : slave->speed,
                                slave->duplex ? "full" : "half");
@@ -2004,7 +2006,8 @@ static void bond_miimon_commit(struct bonding *bond)
 
                        if (bond->params.mode == BOND_MODE_ACTIVEBACKUP ||
                            bond->params.mode == BOND_MODE_8023AD)
-                               bond_set_slave_inactive_flags(slave);
+                               bond_set_slave_inactive_flags(slave,
+                                                             BOND_SLAVE_NOTIFY_NOW);
 
                        pr_info("%s: link status definitely down for interface %s, disabling it\n",
                                bond->dev->name, slave->dev->name);
@@ -2121,24 +2124,40 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
  * switches in VLAN mode (especially if ports are configured as
  * "native" to a VLAN) might not pass non-tagged frames.
  */
-static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id)
+static void bond_arp_send(struct net_device *slave_dev, int arp_op,
+                         __be32 dest_ip, __be32 src_ip,
+                         struct bond_vlan_tag *inner,
+                         struct bond_vlan_tag *outer)
 {
        struct sk_buff *skb;
 
-       pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", arp_op,
-                slave_dev->name, &dest_ip, &src_ip, vlan_id);
+       pr_debug("arp %d on slave %s: dst %pI4 src %pI4\n",
+                arp_op, slave_dev->name, &dest_ip, &src_ip);
 
        skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
                         NULL, slave_dev->dev_addr, NULL);
 
        if (!skb) {
-               pr_err("ARP packet allocation failed\n");
+               net_err_ratelimited("ARP packet allocation failed\n");
                return;
        }
-       if (vlan_id) {
-               skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
+       if (outer->vlan_id) {
+               if (inner->vlan_id) {
+                       pr_debug("inner tag: proto %X vid %X\n",
+                                ntohs(inner->vlan_proto), inner->vlan_id);
+                       skb = __vlan_put_tag(skb, inner->vlan_proto,
+                                            inner->vlan_id);
+                       if (!skb) {
+                               net_err_ratelimited("failed to insert inner VLAN tag\n");
+                               return;
+                       }
+               }
+
+               pr_debug("outer reg: proto %X vid %X\n",
+                        ntohs(outer->vlan_proto), outer->vlan_id);
+               skb = vlan_put_tag(skb, outer->vlan_proto, outer->vlan_id);
                if (!skb) {
-                       pr_err("failed to insert VLAN tag\n");
+                       net_err_ratelimited("failed to insert outer VLAN tag\n");
                        return;
                }
        }
@@ -2151,23 +2170,32 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
        struct net_device *upper, *vlan_upper;
        struct list_head *iter, *vlan_iter;
        struct rtable *rt;
+       struct bond_vlan_tag inner, outer;
        __be32 *targets = bond->params.arp_targets, addr;
-       int i, vlan_id;
+       int i;
 
        for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
                pr_debug("basa: target %pI4\n", &targets[i]);
+               inner.vlan_proto = 0;
+               inner.vlan_id = 0;
+               outer.vlan_proto = 0;
+               outer.vlan_id = 0;
 
                /* Find out through which dev should the packet go */
                rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
                                     RTO_ONLINK, 0);
                if (IS_ERR(rt)) {
-                       pr_debug("%s: no route to arp_ip_target %pI4\n",
-                                bond->dev->name, &targets[i]);
+                       /* there's no route to target - try to send arp
+                        * probe to generate any traffic (arp_validate=0)
+                        */
+                       if (bond->params.arp_validate)
+                               net_warn_ratelimited("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
+                                                    bond->dev->name,
+                                                    &targets[i]);
+                       bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, &inner, &outer);
                        continue;
                }
 
-               vlan_id = 0;
-
                /* bond device itself */
                if (rt->dst.dev == bond->dev)
                        goto found;
@@ -2177,17 +2205,30 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                 * found we verify its upper dev list, searching for the
                 * rt->dst.dev. If found we save the tag of the vlan and
                 * proceed to send the packet.
-                *
-                * TODO: QinQ?
                 */
                netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper,
                                                  vlan_iter) {
                        if (!is_vlan_dev(vlan_upper))
                                continue;
+
+                       if (vlan_upper == rt->dst.dev) {
+                               outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
+                               outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
+                               rcu_read_unlock();
+                               goto found;
+                       }
                        netdev_for_each_all_upper_dev_rcu(vlan_upper, upper,
                                                          iter) {
                                if (upper == rt->dst.dev) {
-                                       vlan_id = vlan_dev_vlan_id(vlan_upper);
+                                       /* If the upper dev is a vlan dev too,
+                                        *  set the vlan tag to inner tag.
+                                        */
+                                       if (is_vlan_dev(upper)) {
+                                               inner.vlan_proto = vlan_dev_vlan_proto(upper);
+                                               inner.vlan_id = vlan_dev_vlan_id(upper);
+                                       }
+                                       outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
+                                       outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
                                        rcu_read_unlock();
                                        goto found;
                                }
@@ -2200,10 +2241,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
                 */
                netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
                        if (upper == rt->dst.dev) {
-                               /* if it's a vlan - get its VID */
-                               if (is_vlan_dev(upper))
-                                       vlan_id = vlan_dev_vlan_id(upper);
-
                                rcu_read_unlock();
                                goto found;
                        }
@@ -2222,7 +2259,7 @@ found:
                addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
                ip_rt_put(rt);
                bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
-                             addr, vlan_id);
+                             addr, &inner, &outer);
        }
 }
 
@@ -2240,7 +2277,7 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
                pr_debug("bva: sip %pI4 not found in targets\n", &sip);
                return;
        }
-       slave->last_arp_rx = jiffies;
+       slave->last_rx = jiffies;
        slave->target_last_arp_rx[i] = jiffies;
 }
 
@@ -2248,17 +2285,19 @@ 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;
        unsigned char *arp_ptr;
        __be32 sip, tip;
-       int alen;
+       int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP);
 
-       if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
+       if (!slave_do_arp_validate(bond, slave)) {
+               if ((slave_do_arp_validate_only(bond, slave) && is_arp) ||
+                   !slave_do_arp_validate_only(bond, slave))
+                       slave->last_rx = jiffies;
                return RX_HANDLER_ANOTHER;
-
-       read_lock(&bond->lock);
-
-       if (!slave_do_arp_validate(bond, slave))
-               goto out_unlock;
+       } else if (!is_arp) {
+               return RX_HANDLER_ANOTHER;
+       }
 
        alen = arp_hdr_len(bond->dev);
 
@@ -2292,6 +2331,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
                 bond->params.arp_validate, slave_do_arp_validate(bond, slave),
                 &sip, &tip);
 
+       curr_active_slave = rcu_dereference(bond->curr_active_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
@@ -2305,15 +2346,15 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
         * 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 (bond->curr_active_slave &&
-                time_after(slave_last_rx(bond, bond->curr_active_slave),
-                           bond->curr_active_slave->jiffies))
+       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);
 
 out_unlock:
-       read_unlock(&bond->lock);
        if (arp != (struct arphdr *)skb->data)
                kfree(arp);
        return RX_HANDLER_ANOTHER;
@@ -2356,9 +2397,9 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
        oldcurrent = ACCESS_ONCE(bond->curr_active_slave);
        /* see if any of the previous devices are up now (i.e. they have
         * xmt and rcv traffic). the curr_active_slave does not come into
-        * the picture unless it is null. also, slave->jiffies is not needed
-        * here because we send an arp on each slave and give a slave as
-        * long as it needs to get the tx/rx within the delta.
+        * the picture unless it is null. also, slave->last_link_up is not
+        * needed here because we send an arp on each slave and give a slave
+        * as long as it needs to get the tx/rx within the delta.
         * TODO: what about up/down delay in arp mode? it wasn't here before
         *       so it can wait
         */
@@ -2367,7 +2408,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
 
                if (slave->link != BOND_LINK_UP) {
                        if (bond_time_in_interval(bond, trans_start, 1) &&
-                           bond_time_in_interval(bond, slave->dev->last_rx, 1)) {
+                           bond_time_in_interval(bond, slave->last_rx, 1)) {
 
                                slave->link  = BOND_LINK_UP;
                                slave_state_changed = 1;
@@ -2378,7 +2419,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                                 * is closed.
                                 */
                                if (!oldcurrent) {
-                                       pr_info("%s: link status definitely up for interface %s",
+                                       pr_info("%s: link status definitely up for interface %s\n",
                                                bond->dev->name,
                                                slave->dev->name);
                                        do_failover = 1;
@@ -2396,7 +2437,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                         * if we don't know our ip yet
                         */
                        if (!bond_time_in_interval(bond, trans_start, 2) ||
-                           !bond_time_in_interval(bond, slave->dev->last_rx, 2)) {
+                           !bond_time_in_interval(bond, slave->last_rx, 2)) {
 
                                slave->link  = BOND_LINK_DOWN;
                                slave_state_changed = 1;
@@ -2404,9 +2445,8 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                                if (slave->link_failure_count < UINT_MAX)
                                        slave->link_failure_count++;
 
-                               pr_info("%s: interface %s is now down.\n",
-                                       bond->dev->name,
-                                       slave->dev->name);
+                               pr_info("%s: interface %s is now down\n",
+                                       bond->dev->name, slave->dev->name);
 
                                if (slave == oldcurrent)
                                        do_failover = 1;
@@ -2485,7 +2525,7 @@ static int bond_ab_arp_inspect(struct bonding *bond)
                 * active.  This avoids bouncing, as the last receive
                 * times need a full ARP monitor cycle to be updated.
                 */
-               if (bond_time_in_interval(bond, slave->jiffies, 2))
+               if (bond_time_in_interval(bond, slave->last_link_up, 2))
                        continue;
 
                /*
@@ -2551,11 +2591,12 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                slave->link = BOND_LINK_UP;
                                if (bond->current_arp_slave) {
                                        bond_set_slave_inactive_flags(
-                                               bond->current_arp_slave);
+                                               bond->current_arp_slave,
+                                               BOND_SLAVE_NOTIFY_NOW);
                                        bond->current_arp_slave = NULL;
                                }
 
-                               pr_info("%s: link status definitely up for interface %s.\n",
+                               pr_info("%s: link status definitely up for interface %s\n",
                                        bond->dev->name, slave->dev->name);
 
                                if (!bond->curr_active_slave ||
@@ -2571,7 +2612,8 @@ static void bond_ab_arp_commit(struct bonding *bond)
                                slave->link_failure_count++;
 
                        slave->link = BOND_LINK_DOWN;
-                       bond_set_slave_inactive_flags(slave);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_NOW);
 
                        pr_info("%s: link status definitely down for interface %s, disabling it\n",
                                bond->dev->name, slave->dev->name);
@@ -2604,17 +2646,17 @@ do_failover:
 
 /*
  * Send ARP probes for active-backup mode ARP monitor.
+ *
+ * Called with rcu_read_lock hold.
  */
 static bool bond_ab_arp_probe(struct bonding *bond)
 {
        struct slave *slave, *before = NULL, *new_slave = NULL,
-                    *curr_arp_slave, *curr_active_slave;
+                    *curr_arp_slave = rcu_dereference(bond->current_arp_slave),
+                    *curr_active_slave = rcu_dereference(bond->curr_active_slave);
        struct list_head *iter;
        bool found = false;
-
-       rcu_read_lock();
-       curr_arp_slave = rcu_dereference(bond->current_arp_slave);
-       curr_active_slave = rcu_dereference(bond->curr_active_slave);
+       bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
 
        if (curr_arp_slave && curr_active_slave)
                pr_info("PROBE: c_arp %s && cas %s BAD\n",
@@ -2623,32 +2665,23 @@ static bool bond_ab_arp_probe(struct bonding *bond)
 
        if (curr_active_slave) {
                bond_arp_send_all(bond, curr_active_slave);
-               rcu_read_unlock();
-               return true;
+               return should_notify_rtnl;
        }
-       rcu_read_unlock();
 
        /* if we don't have a curr_active_slave, search for the next available
         * backup slave from the current_arp_slave and make it the candidate
         * for becoming the curr_active_slave
         */
 
-       if (!rtnl_trylock())
-               return false;
-       /* curr_arp_slave might have gone away */
-       curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave);
-
        if (!curr_arp_slave) {
-               curr_arp_slave = bond_first_slave(bond);
-               if (!curr_arp_slave) {
-                       rtnl_unlock();
-                       return true;
-               }
+               curr_arp_slave = bond_first_slave_rcu(bond);
+               if (!curr_arp_slave)
+                       return should_notify_rtnl;
        }
 
-       bond_set_slave_inactive_flags(curr_arp_slave);
+       bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER);
 
-       bond_for_each_slave(bond, slave, iter) {
+       bond_for_each_slave_rcu(bond, slave, iter) {
                if (!found && !before && IS_UP(slave->dev))
                        before = slave;
 
@@ -2666,9 +2699,10 @@ static bool bond_ab_arp_probe(struct bonding *bond)
                        if (slave->link_failure_count < UINT_MAX)
                                slave->link_failure_count++;
 
-                       bond_set_slave_inactive_flags(slave);
+                       bond_set_slave_inactive_flags(slave,
+                                                     BOND_SLAVE_NOTIFY_LATER);
 
-                       pr_info("%s: backup interface %s is now down.\n",
+                       pr_info("%s: backup interface %s is now down\n",
                                bond->dev->name, slave->dev->name);
                }
                if (slave == curr_arp_slave)
@@ -2678,26 +2712,31 @@ static bool bond_ab_arp_probe(struct bonding *bond)
        if (!new_slave && before)
                new_slave = before;
 
-       if (!new_slave) {
-               rtnl_unlock();
-               return true;
-       }
+       if (!new_slave)
+               goto check_state;
 
        new_slave->link = BOND_LINK_BACK;
-       bond_set_slave_active_flags(new_slave);
+       bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
        bond_arp_send_all(bond, new_slave);
-       new_slave->jiffies = jiffies;
+       new_slave->last_link_up = jiffies;
        rcu_assign_pointer(bond->current_arp_slave, new_slave);
-       rtnl_unlock();
 
-       return true;
+check_state:
+       bond_for_each_slave_rcu(bond, slave, iter) {
+               if (slave->should_notify) {
+                       should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW;
+                       break;
+               }
+       }
+       return should_notify_rtnl;
 }
 
 static void bond_activebackup_arp_mon(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            arp_work.work);
-       bool should_notify_peers = false, should_commit = false;
+       bool should_notify_peers = false;
+       bool should_notify_rtnl = false;
        int delta_in_ticks;
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2706,11 +2745,12 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                goto re_arm;
 
        rcu_read_lock();
+
        should_notify_peers = bond_should_notify_peers(bond);
-       should_commit = bond_ab_arp_inspect(bond);
-       rcu_read_unlock();
 
-       if (should_commit) {
+       if (bond_ab_arp_inspect(bond)) {
+               rcu_read_unlock();
+
                /* Race avoidance with bond_close flush of workqueue */
                if (!rtnl_trylock()) {
                        delta_in_ticks = 1;
@@ -2719,23 +2759,28 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                }
 
                bond_ab_arp_commit(bond);
+
                rtnl_unlock();
+               rcu_read_lock();
        }
 
-       if (!bond_ab_arp_probe(bond)) {
-               /* rtnl locking failed, re-arm */
-               delta_in_ticks = 1;
-               should_notify_peers = false;
-       }
+       should_notify_rtnl = bond_ab_arp_probe(bond);
+       rcu_read_unlock();
 
 re_arm:
        if (bond->params.arp_interval)
                queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 
-       if (should_notify_peers) {
+       if (should_notify_peers || should_notify_rtnl) {
                if (!rtnl_trylock())
                        return;
-               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
+
+               if (should_notify_peers)
+                       call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
+                                                bond->dev);
+               if (should_notify_rtnl)
+                       bond_slave_state_notify(bond);
+
                rtnl_unlock();
        }
 }
@@ -2854,12 +2899,15 @@ static int bond_slave_netdev_event(unsigned long event,
                        break;
                }
 
-               pr_info("%s: Primary slave changed to %s, reselecting active slave.\n",
-                       bond->dev->name, bond->primary_slave ? slave_dev->name :
-                                                              "none");
+               pr_info("%s: Primary slave changed to %s, reselecting active slave\n",
+                       bond->dev->name,
+                       bond->primary_slave ? slave_dev->name : "none");
+
+               block_netpoll_tx();
                write_lock_bh(&bond->curr_slave_lock);
                bond_select_active_slave(bond);
                write_unlock_bh(&bond->curr_slave_lock);
+               unblock_netpoll_tx();
                break;
        case NETDEV_FEAT_CHANGE:
                bond_compute_features(bond);
@@ -2889,8 +2937,7 @@ static int bond_netdev_event(struct notifier_block *this,
        struct net_device *event_dev = netdev_notifier_info_to_dev(ptr);
 
        pr_debug("event_dev: %s, event: %lx\n",
-                event_dev ? event_dev->name : "None",
-                event);
+                event_dev ? event_dev->name : "None", event);
 
        if (!(event_dev->priv_flags & IFF_BONDING))
                return NOTIFY_DONE;
@@ -2939,7 +2986,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
        fk->ports = 0;
        noff = skb_network_offset(skb);
        if (skb->protocol == htons(ETH_P_IP)) {
-               if (!pskb_may_pull(skb, noff + sizeof(*iph)))
+               if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
                        return false;
                iph = ip_hdr(skb);
                fk->src = iph->saddr;
@@ -2948,7 +2995,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
                if (!ip_is_fragment(iph))
                        proto = iph->protocol;
        } else if (skb->protocol == htons(ETH_P_IPV6)) {
-               if (!pskb_may_pull(skb, noff + sizeof(*iph6)))
+               if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph6))))
                        return false;
                iph6 = ipv6_hdr(skb);
                fk->src = (__force __be32)ipv6_addr_hash(&iph6->saddr);
@@ -3032,9 +3079,11 @@ static int bond_open(struct net_device *bond_dev)
                bond_for_each_slave(bond, slave, iter) {
                        if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                && (slave != bond->curr_active_slave)) {
-                               bond_set_slave_inactive_flags(slave);
+                               bond_set_slave_inactive_flags(slave,
+                                                             BOND_SLAVE_NOTIFY_NOW);
                        } else {
-                               bond_set_slave_active_flags(slave);
+                               bond_set_slave_active_flags(slave,
+                                                           BOND_SLAVE_NOTIFY_NOW);
                        }
                }
                read_unlock(&bond->curr_slave_lock);
@@ -3057,8 +3106,7 @@ static int bond_open(struct net_device *bond_dev)
 
        if (bond->params.arp_interval) {  /* arp interval, in milliseconds. */
                queue_delayed_work(bond->wq, &bond->arp_work, 0);
-               if (bond->params.arp_validate)
-                       bond->recv_probe = bond_arp_rcv;
+               bond->recv_probe = bond_arp_rcv;
        }
 
        if (bond->params.mode == BOND_MODE_8023AD) {
@@ -3345,8 +3393,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
        struct list_head *iter;
        int res = 0;
 
-       pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond,
-                (bond_dev ? bond_dev->name : "None"), new_mtu);
+       pr_debug("bond=%p, name=%s, new_mtu=%d\n",
+                bond, bond_dev ? bond_dev->name : "None", new_mtu);
 
        /* Can't hold bond->lock with bh disabled here since
         * some base drivers panic. On the other hand we can't
@@ -3365,8 +3413,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu)
 
        bond_for_each_slave(bond, slave, iter) {
                pr_debug("s %p c_m %p\n",
-                        slave,
-                        slave->dev->netdev_ops->ndo_change_mtu);
+                        slave, slave->dev->netdev_ops->ndo_change_mtu);
 
                res = dev_set_mtu(slave->dev, new_mtu);
 
@@ -3431,7 +3478,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
        /* If fail_over_mac is enabled, do nothing and return success.
         * Returning an error causes ifenslave to fail.
         */
-       if (bond->params.fail_over_mac)
+       if (bond->params.fail_over_mac &&
+           bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                return 0;
 
        if (!is_valid_ether_addr(sa->sa_data))
@@ -3453,15 +3501,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr)
         */
 
        bond_for_each_slave(bond, slave, iter) {
-               const struct net_device_ops *slave_ops = slave->dev->netdev_ops;
                pr_debug("slave %p %s\n", slave, slave->dev->name);
-
-               if (slave_ops->ndo_set_mac_address == NULL) {
-                       res = -EOPNOTSUPP;
-                       pr_debug("EOPNOTSUPP %s\n", slave->dev->name);
-                       goto unwind;
-               }
-
                res = dev_set_mac_address(slave->dev, addr);
                if (res) {
                        /* TODO: consider downing the slave
@@ -3537,7 +3577,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl
                }
        }
        /* no slave that can tx has been found */
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 }
 
 /**
@@ -3613,7 +3653,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
        if (slave)
                bond_dev_queue_xmit(bond, skb, slave->dev);
        else
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -3645,8 +3685,8 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
                        struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 
                        if (!skb2) {
-                               pr_err("%s: Error: bond_xmit_broadcast(): skb_clone() failed\n",
-                                      bond_dev->name);
+                               net_err_ratelimited("%s: Error: %s: skb_clone() failed\n",
+                                                   bond_dev->name, __func__);
                                continue;
                        }
                        /* bond_dev_queue_xmit always returns 0 */
@@ -3656,7 +3696,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
        if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP)
                bond_dev_queue_xmit(bond, skb, slave->dev);
        else
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -3692,7 +3732,7 @@ static inline int bond_slave_override(struct bonding *bond,
 
 
 static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb,
-                            void *accel_priv)
+                            void *accel_priv, select_queue_fallback_t fallback)
 {
        /*
         * This helper function exists to help dev_pick_tx get the correct
@@ -3743,7 +3783,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
                pr_err("%s: Error: Unknown bonding mode %d\n",
                       dev->name, bond->params.mode);
                WARN_ON_ONCE(1);
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 }
@@ -3757,14 +3797,14 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
         * If we risk deadlock from transmitting this in the
         * netpoll path, tell netpoll to queue the frame for later tx
         */
-       if (is_netpoll_tx_blocked(dev))
+       if (unlikely(is_netpoll_tx_blocked(dev)))
                return NETDEV_TX_BUSY;
 
        rcu_read_lock();
        if (bond_has_slaves(bond))
                ret = __bond_start_xmit(skb, dev);
        else
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        rcu_read_unlock();
 
        return ret;
@@ -3927,7 +3967,7 @@ static void bond_uninit(struct net_device *bond_dev)
        /* Release the bonded slaves */
        bond_for_each_slave(bond, slave, iter)
                __bond_release_one(bond_dev, slave->dev, true);
-       pr_info("%s: released all slaves\n", bond_dev->name);
+       pr_info("%s: Released all slaves\n", bond_dev->name);
 
        list_del(&bond->bond_list);
 
@@ -3936,56 +3976,11 @@ static void bond_uninit(struct net_device *bond_dev)
 
 /*------------------------- Module initialization ---------------------------*/
 
-int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl)
-{
-       int i;
-
-       for (i = 0; tbl[i].modename; i++)
-               if (mode == tbl[i].mode)
-                       return tbl[i].mode;
-
-       return -1;
-}
-
-static int bond_parm_tbl_lookup_name(const char *modename,
-                                    const struct bond_parm_tbl *tbl)
-{
-       int i;
-
-       for (i = 0; tbl[i].modename; i++)
-               if (strcmp(modename, tbl[i].modename) == 0)
-                       return tbl[i].mode;
-
-       return -1;
-}
-
-/*
- * Convert string input module parms.  Accept either the
- * number of the mode or its string name.  A bit complicated because
- * some mode names are substrings of other names, and calls from sysfs
- * may have whitespace in the name (trailing newlines, for example).
- */
-int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl)
-{
-       int modeint;
-       char *p, modestr[BOND_MAX_MODENAME_LEN + 1];
-
-       for (p = (char *)buf; *p; p++)
-               if (!(isdigit(*p) || isspace(*p)))
-                       break;
-
-       if (*p && sscanf(buf, "%20s", modestr) != 0)
-               return bond_parm_tbl_lookup_name(modestr, tbl);
-       else if (sscanf(buf, "%d", &modeint) != 0)
-               return bond_parm_tbl_lookup(modeint, tbl);
-
-       return -1;
-}
-
 static int bond_check_params(struct bond_params *params)
 {
        int arp_validate_value, fail_over_mac_value, primary_reselect_value, i;
-       struct bond_opt_value newval, *valptr;
+       struct bond_opt_value newval;
+       const struct bond_opt_value *valptr;
        int arp_all_targets_value;
 
        /*
@@ -4005,7 +4000,7 @@ static int bond_check_params(struct bond_params *params)
                if ((bond_mode != BOND_MODE_XOR) &&
                    (bond_mode != BOND_MODE_8023AD)) {
                        pr_info("xmit_hash_policy param is irrelevant in mode %s\n",
-                              bond_mode_name(bond_mode));
+                               bond_mode_name(bond_mode));
                } else {
                        bond_opt_initstr(&newval, xmit_hash_policy);
                        valptr = bond_opt_parse(bond_opt_get(BOND_OPT_XMIT_HASH),
@@ -4046,74 +4041,71 @@ static int bond_check_params(struct bond_params *params)
                }
                params->ad_select = valptr->value;
                if (bond_mode != BOND_MODE_8023AD)
-                       pr_warning("ad_select param only affects 802.3ad mode\n");
+                       pr_warn("ad_select param only affects 802.3ad mode\n");
        } else {
                params->ad_select = BOND_AD_STABLE;
        }
 
        if (max_bonds < 0) {
-               pr_warning("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
-                          max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS);
+               pr_warn("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n",
+                       max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS);
                max_bonds = BOND_DEFAULT_MAX_BONDS;
        }
 
        if (miimon < 0) {
-               pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n",
-                          miimon, INT_MAX);
+               pr_warn("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+                       miimon, INT_MAX);
                miimon = 0;
        }
 
        if (updelay < 0) {
-               pr_warning("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
-                          updelay, INT_MAX);
+               pr_warn("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+                       updelay, INT_MAX);
                updelay = 0;
        }
 
        if (downdelay < 0) {
-               pr_warning("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
-                          downdelay, INT_MAX);
+               pr_warn("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+                       downdelay, INT_MAX);
                downdelay = 0;
        }
 
        if ((use_carrier != 0) && (use_carrier != 1)) {
-               pr_warning("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n",
-                          use_carrier);
+               pr_warn("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n",
+                       use_carrier);
                use_carrier = 1;
        }
 
        if (num_peer_notif < 0 || num_peer_notif > 255) {
-               pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
-                          num_peer_notif);
+               pr_warn("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
+                       num_peer_notif);
                num_peer_notif = 1;
        }
 
        /* reset values for 802.3ad/TLB/ALB */
        if (BOND_NO_USES_ARP(bond_mode)) {
                if (!miimon) {
-                       pr_warning("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n");
-                       pr_warning("Forcing miimon to 100msec\n");
+                       pr_warn("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n");
+                       pr_warn("Forcing miimon to 100msec\n");
                        miimon = BOND_DEFAULT_MIIMON;
                }
        }
 
        if (tx_queues < 1 || tx_queues > 255) {
-               pr_warning("Warning: tx_queues (%d) should be between "
-                          "1 and 255, resetting to %d\n",
-                          tx_queues, BOND_DEFAULT_TX_QUEUES);
+               pr_warn("Warning: tx_queues (%d) should be between 1 and 255, resetting to %d\n",
+                       tx_queues, BOND_DEFAULT_TX_QUEUES);
                tx_queues = BOND_DEFAULT_TX_QUEUES;
        }
 
        if ((all_slaves_active != 0) && (all_slaves_active != 1)) {
-               pr_warning("Warning: all_slaves_active module parameter (%d), "
-                          "not of valid value (0/1), so it was set to "
-                          "0\n", all_slaves_active);
+               pr_warn("Warning: all_slaves_active module parameter (%d), not of valid value (0/1), so it was set to 0\n",
+                       all_slaves_active);
                all_slaves_active = 0;
        }
 
        if (resend_igmp < 0 || resend_igmp > 255) {
-               pr_warning("Warning: resend_igmp (%d) should be between "
-                          "0 and 255, resetting to %d\n",
-                          resend_igmp, BOND_DEFAULT_RESEND_IGMP);
+               pr_warn("Warning: resend_igmp (%d) should be between 0 and 255, resetting to %d\n",
+                       resend_igmp, BOND_DEFAULT_RESEND_IGMP);
                resend_igmp = BOND_DEFAULT_RESEND_IGMP;
        }
 
@@ -4134,37 +4126,36 @@ static int bond_check_params(struct bond_params *params)
                        /* just warn the user the up/down delay will have
                         * no effect since miimon is zero...
                         */
-                       pr_warning("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n",
-                                  updelay, downdelay);
+                       pr_warn("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n",
+                               updelay, downdelay);
                }
        } else {
                /* don't allow arp monitoring */
                if (arp_interval) {
-                       pr_warning("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n",
-                                  miimon, arp_interval);
+                       pr_warn("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n",
+                               miimon, arp_interval);
                        arp_interval = 0;
                }
 
                if ((updelay % miimon) != 0) {
-                       pr_warning("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
-                                  updelay, miimon,
-                                  (updelay / miimon) * miimon);
+                       pr_warn("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n",
+                               updelay, miimon, (updelay / miimon) * miimon);
                }
 
                updelay /= miimon;
 
                if ((downdelay % miimon) != 0) {
-                       pr_warning("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n",
-                                  downdelay, miimon,
-                                  (downdelay / miimon) * miimon);
+                       pr_warn("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n",
+                               downdelay, miimon,
+                               (downdelay / miimon) * miimon);
                }
 
                downdelay /= miimon;
        }
 
        if (arp_interval < 0) {
-               pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to 0\n",
-                          arp_interval, INT_MAX);
+               pr_warn("Warning: arp_interval module parameter (%d), not in range 0-%d, so it was reset to 0\n",
+                       arp_interval, INT_MAX);
                arp_interval = 0;
        }
 
@@ -4175,30 +4166,26 @@ static int bond_check_params(struct bond_params *params)
                __be32 ip;
                if (!in4_pton(arp_ip_target[i], -1, (u8 *)&ip, -1, NULL) ||
                    IS_IP_TARGET_UNUSABLE_ADDRESS(ip)) {
-                       pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
-                                  arp_ip_target[i]);
+                       pr_warn("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
+                               arp_ip_target[i]);
                        arp_interval = 0;
                } else {
                        if (bond_get_targets_ip(arp_target, ip) == -1)
                                arp_target[arp_ip_count++] = ip;
                        else
-                               pr_warning("Warning: duplicate address %pI4 in arp_ip_target, skipping\n",
-                                          &ip);
+                               pr_warn("Warning: duplicate address %pI4 in arp_ip_target, skipping\n",
+                                       &ip);
                }
        }
 
        if (arp_interval && !arp_ip_count) {
                /* don't allow arping if no arp_ip_target given... */
-               pr_warning("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n",
-                          arp_interval);
+               pr_warn("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n",
+                       arp_interval);
                arp_interval = 0;
        }
 
        if (arp_validate) {
-               if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
-                       pr_err("arp_validate only supported in active-backup mode\n");
-                       return -EINVAL;
-               }
                if (!arp_interval) {
                        pr_err("arp_validate requires arp_interval\n");
                        return -EINVAL;
@@ -4240,23 +4227,23 @@ static int bond_check_params(struct bond_params *params)
                        arp_interval, valptr->string, arp_ip_count);
 
                for (i = 0; i < arp_ip_count; i++)
-                       pr_info(" %s", arp_ip_target[i]);
+                       pr_cont(" %s", arp_ip_target[i]);
 
-               pr_info("\n");
+               pr_cont("\n");
 
        } else if (max_bonds) {
                /* miimon and arp_interval not set, we need one so things
                 * work as expected, see bonding.txt for details
                 */
-               pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details.\n");
+               pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details\n");
        }
 
        if (primary && !USES_PRIMARY(bond_mode)) {
                /* currently, using a primary only makes sense
                 * in active backup, TLB or ALB modes
                 */
-               pr_warning("Warning: %s primary device specified but has no effect in %s mode\n",
-                          primary, bond_mode_name(bond_mode));
+               pr_warn("Warning: %s primary device specified but has no effect in %s mode\n",
+                       primary, bond_mode_name(bond_mode));
                primary = NULL;
        }
 
@@ -4285,14 +4272,14 @@ static int bond_check_params(struct bond_params *params)
                }
                fail_over_mac_value = valptr->value;
                if (bond_mode != BOND_MODE_ACTIVEBACKUP)
-                       pr_warning("Warning: fail_over_mac only affects active-backup mode.\n");
+                       pr_warn("Warning: fail_over_mac only affects active-backup mode\n");
        } else {
                fail_over_mac_value = BOND_FOM_NONE;
        }
 
        if (lp_interval == 0) {
-               pr_warning("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
-                          INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
+               pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n",
+                       INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL);
                lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL;
        }
 
index 70651f8e8e3b9791c5feb285483e983fd52ffd75..f847e165d252fb2a4528fe396b2c4f0553e81ac3 100644 (file)
@@ -181,7 +181,7 @@ static int bond_changelink(struct net_device *bond_dev,
                int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]);
 
                if (arp_interval && miimon) {
-                       pr_err("%s: ARP monitoring cannot be used with MII monitoring.\n",
+                       pr_err("%s: ARP monitoring cannot be used with MII monitoring\n",
                               bond->dev->name);
                        return -EINVAL;
                }
@@ -199,7 +199,7 @@ static int bond_changelink(struct net_device *bond_dev,
                nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
                        __be32 target = nla_get_be32(attr);
 
-                       bond_opt_initval(&newval, target);
+                       bond_opt_initval(&newval, (__force u64)target);
                        err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS,
                                             &newval);
                        if (err)
@@ -207,7 +207,7 @@ static int bond_changelink(struct net_device *bond_dev,
                        i++;
                }
                if (i == 0 && bond->params.arp_interval)
-                       pr_warn("%s: removing last arp target with arp_interval on\n",
+                       pr_warn("%s: Removing last arp target with arp_interval on\n",
                                bond->dev->name);
                if (err)
                        return err;
@@ -216,7 +216,7 @@ static int bond_changelink(struct net_device *bond_dev,
                int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]);
 
                if (arp_validate && miimon) {
-                       pr_err("%s: ARP validating cannot be used with MII monitoring.\n",
+                       pr_err("%s: ARP validating cannot be used with MII monitoring\n",
                               bond->dev->name);
                        return -EINVAL;
                }
index 11cb943222d5c839ed363715db445351e6b3da56..724e30fa20b9fa70166b5d9b25ed9029fab6db73 100644 (file)
 #include <linux/errno.h>
 #include <linux/if.h>
 #include <linux/netdevice.h>
-#include <linux/rwlock.h>
+#include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 #include <linux/ctype.h>
 #include <linux/inet.h>
 #include "bonding.h"
 
-static struct bond_opt_value bond_mode_tbl[] = {
+static int bond_option_active_slave_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval);
+static int bond_option_miimon_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval);
+static int bond_option_updelay_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval);
+static int bond_option_downdelay_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_use_carrier_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
+static int bond_option_arp_interval_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval);
+static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
+static int bond_option_arp_ip_targets_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval);
+static int bond_option_arp_validate_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval);
+static int bond_option_arp_all_targets_set(struct bonding *bond,
+                                          const struct bond_opt_value *newval);
+static int bond_option_primary_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval);
+static int bond_option_primary_reselect_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval);
+static int bond_option_fail_over_mac_set(struct bonding *bond,
+                                        const struct bond_opt_value *newval);
+static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval);
+static int bond_option_resend_igmp_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
+static int bond_option_num_peer_notif_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval);
+static int bond_option_all_slaves_active_set(struct bonding *bond,
+                                            const struct bond_opt_value *newval);
+static int bond_option_min_links_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_lp_interval_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval);
+static int bond_option_pps_set(struct bonding *bond,
+                              const struct bond_opt_value *newval);
+static int bond_option_lacp_rate_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_ad_select_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval);
+static int bond_option_queue_id_set(struct bonding *bond,
+                                   const struct bond_opt_value *newval);
+static int bond_option_mode_set(struct bonding *bond,
+                               const struct bond_opt_value *newval);
+static int bond_option_slaves_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval);
+
+
+static const struct bond_opt_value bond_mode_tbl[] = {
        { "balance-rr",    BOND_MODE_ROUNDROBIN,   BOND_VALFLAG_DEFAULT},
        { "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
        { "balance-xor",   BOND_MODE_XOR,          0},
@@ -31,13 +83,13 @@ static struct bond_opt_value bond_mode_tbl[] = {
        { NULL,            -1,                     0},
 };
 
-static struct bond_opt_value bond_pps_tbl[] = {
+static const struct bond_opt_value bond_pps_tbl[] = {
        { "default", 1,         BOND_VALFLAG_DEFAULT},
        { "maxval",  USHRT_MAX, BOND_VALFLAG_MAX},
        { NULL,      -1,        0},
 };
 
-static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
+static const struct bond_opt_value bond_xmit_hashtype_tbl[] = {
        { "layer2",   BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT},
        { "layer3+4", BOND_XMIT_POLICY_LAYER34, 0},
        { "layer2+3", BOND_XMIT_POLICY_LAYER23, 0},
@@ -46,84 +98,88 @@ static struct bond_opt_value bond_xmit_hashtype_tbl[] = {
        { NULL,       -1,                       0},
 };
 
-static struct bond_opt_value bond_arp_validate_tbl[] = {
-       { "none",   BOND_ARP_VALIDATE_NONE,   BOND_VALFLAG_DEFAULT},
-       { "active", BOND_ARP_VALIDATE_ACTIVE, 0},
-       { "backup", BOND_ARP_VALIDATE_BACKUP, 0},
-       { "all",    BOND_ARP_VALIDATE_ALL,    0},
-       { NULL,     -1,                       0},
+static const struct bond_opt_value bond_arp_validate_tbl[] = {
+       { "none",               BOND_ARP_VALIDATE_NONE,         BOND_VALFLAG_DEFAULT},
+       { "active",             BOND_ARP_VALIDATE_ACTIVE,       0},
+       { "backup",             BOND_ARP_VALIDATE_BACKUP,       0},
+       { "all",                BOND_ARP_VALIDATE_ALL,          0},
+       { "filter",             BOND_ARP_FILTER,                0},
+       { "filter_active",      BOND_ARP_FILTER_ACTIVE,         0},
+       { "filter_backup",      BOND_ARP_FILTER_BACKUP,         0},
+       { NULL,                 -1,                             0},
 };
 
-static struct bond_opt_value bond_arp_all_targets_tbl[] = {
+static const struct bond_opt_value bond_arp_all_targets_tbl[] = {
        { "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
        { "all", BOND_ARP_TARGETS_ALL, 0},
        { NULL,  -1,                   0},
 };
 
-static struct bond_opt_value bond_fail_over_mac_tbl[] = {
+static const struct bond_opt_value bond_fail_over_mac_tbl[] = {
        { "none",   BOND_FOM_NONE,   BOND_VALFLAG_DEFAULT},
        { "active", BOND_FOM_ACTIVE, 0},
        { "follow", BOND_FOM_FOLLOW, 0},
        { NULL,     -1,              0},
 };
 
-static struct bond_opt_value bond_intmax_tbl[] = {
+static const struct bond_opt_value bond_intmax_tbl[] = {
        { "off",     0,       BOND_VALFLAG_DEFAULT},
        { "maxval",  INT_MAX, BOND_VALFLAG_MAX},
 };
 
-static struct bond_opt_value bond_lacp_rate_tbl[] = {
+static const struct bond_opt_value bond_lacp_rate_tbl[] = {
        { "slow", AD_LACP_SLOW, 0},
        { "fast", AD_LACP_FAST, 0},
        { NULL,   -1,           0},
 };
 
-static struct bond_opt_value bond_ad_select_tbl[] = {
+static const struct bond_opt_value bond_ad_select_tbl[] = {
        { "stable",    BOND_AD_STABLE,    BOND_VALFLAG_DEFAULT},
        { "bandwidth", BOND_AD_BANDWIDTH, 0},
        { "count",     BOND_AD_COUNT,     0},
        { NULL,        -1,                0},
 };
 
-static struct bond_opt_value bond_num_peer_notif_tbl[] = {
+static const struct bond_opt_value bond_num_peer_notif_tbl[] = {
        { "off",     0,   0},
        { "maxval",  255, BOND_VALFLAG_MAX},
        { "default", 1,   BOND_VALFLAG_DEFAULT},
        { NULL,      -1,  0}
 };
 
-static struct bond_opt_value bond_primary_reselect_tbl[] = {
+static const struct bond_opt_value bond_primary_reselect_tbl[] = {
        { "always",  BOND_PRI_RESELECT_ALWAYS,  BOND_VALFLAG_DEFAULT},
        { "better",  BOND_PRI_RESELECT_BETTER,  0},
        { "failure", BOND_PRI_RESELECT_FAILURE, 0},
        { NULL,      -1},
 };
 
-static struct bond_opt_value bond_use_carrier_tbl[] = {
+static const struct bond_opt_value bond_use_carrier_tbl[] = {
        { "off", 0,  0},
        { "on",  1,  BOND_VALFLAG_DEFAULT},
        { NULL,  -1, 0}
 };
 
-static struct bond_opt_value bond_all_slaves_active_tbl[] = {
+static const struct bond_opt_value bond_all_slaves_active_tbl[] = {
        { "off", 0,  BOND_VALFLAG_DEFAULT},
        { "on",  1,  0},
        { NULL,  -1, 0}
 };
 
-static struct bond_opt_value bond_resend_igmp_tbl[] = {
+static const struct bond_opt_value bond_resend_igmp_tbl[] = {
        { "off",     0,   0},
        { "maxval",  255, BOND_VALFLAG_MAX},
        { "default", 1,   BOND_VALFLAG_DEFAULT},
        { NULL,      -1,  0}
 };
 
-static struct bond_opt_value bond_lp_interval_tbl[] = {
+static const struct bond_opt_value bond_lp_interval_tbl[] = {
        { "minval",  1,       BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
        { "maxval",  INT_MAX, BOND_VALFLAG_MAX},
+       { NULL,      -1,      0},
 };
 
-static struct bond_option bond_opts[] = {
+static const struct bond_option bond_opts[] = {
        [BOND_OPT_MODE] = {
                .id = BOND_OPT_MODE,
                .name = "mode",
@@ -151,7 +207,8 @@ static struct bond_option bond_opts[] = {
                .id = BOND_OPT_ARP_VALIDATE,
                .name = "arp_validate",
                .desc = "validate src/dst of ARP probes",
-               .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP)),
+               .unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
+                              BIT(BOND_MODE_ALB),
                .values = bond_arp_validate_tbl,
                .set = bond_option_arp_validate_set
        },
@@ -311,9 +368,9 @@ static struct bond_option bond_opts[] = {
 };
 
 /* Searches for a value in opt's values[] table */
-struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
 {
-       struct bond_option *opt;
+       const struct bond_option *opt;
        int i;
 
        opt = bond_opt_get(option);
@@ -327,7 +384,7 @@ struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
 }
 
 /* Searches for a value in opt's values[] table which matches the flagmask */
-static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
+static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
                                                 u32 flagmask)
 {
        int i;
@@ -344,7 +401,7 @@ static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
  */
 static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
 {
-       struct bond_opt_value *minval, *maxval;
+       const struct bond_opt_value *minval, *maxval;
 
        minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
        maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
@@ -364,11 +421,12 @@ static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
  * or the struct_opt_value that matched. It also strips the new line from
  * @val->string if it's present.
  */
-struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
-                                     struct bond_opt_value *val)
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+                                           struct bond_opt_value *val)
 {
        char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
-       struct bond_opt_value *tbl, *ret = NULL;
+       const struct bond_opt_value *tbl;
+       const struct bond_opt_value *ret = NULL;
        bool checkval;
        int i, rv;
 
@@ -447,7 +505,7 @@ static int bond_opt_check_deps(struct bonding *bond,
 static void bond_opt_dep_print(struct bonding *bond,
                               const struct bond_option *opt)
 {
-       struct bond_opt_value *modeval;
+       const struct bond_opt_value *modeval;
        struct bond_params *params;
 
        params = &bond->params;
@@ -460,9 +518,9 @@ static void bond_opt_dep_print(struct bonding *bond,
 
 static void bond_opt_error_interpret(struct bonding *bond,
                                     const struct bond_option *opt,
-                                    int error, struct bond_opt_value *val)
+                                    int error, const struct bond_opt_value *val)
 {
-       struct bond_opt_value *minval, *maxval;
+       const struct bond_opt_value *minval, *maxval;
        char *p;
 
        switch (error) {
@@ -473,10 +531,10 @@ static void bond_opt_error_interpret(struct bonding *bond,
                                p = strchr(val->string, '\n');
                                if (p)
                                        *p = '\0';
-                               pr_err("%s: option %s: invalid value (%s).\n",
+                               pr_err("%s: option %s: invalid value (%s)\n",
                                       bond->dev->name, opt->name, val->string);
                        } else {
-                               pr_err("%s: option %s: invalid value (%llu).\n",
+                               pr_err("%s: option %s: invalid value (%llu)\n",
                                       bond->dev->name, opt->name, val->value);
                        }
                }
@@ -484,7 +542,7 @@ static void bond_opt_error_interpret(struct bonding *bond,
                maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
                if (!maxval)
                        break;
-               pr_err("%s: option %s: allowed values %llu - %llu.\n",
+               pr_err("%s: option %s: allowed values %llu - %llu\n",
                       bond->dev->name, opt->name, minval ? minval->value : 0,
                       maxval->value);
                break;
@@ -492,11 +550,11 @@ static void bond_opt_error_interpret(struct bonding *bond,
                bond_opt_dep_print(bond, opt);
                break;
        case -ENOTEMPTY:
-               pr_err("%s: option %s: unable to set because the bond device has slaves.\n",
+               pr_err("%s: option %s: unable to set because the bond device has slaves\n",
                       bond->dev->name, opt->name);
                break;
        case -EBUSY:
-               pr_err("%s: option %s: unable to set because the bond device is up.\n",
+               pr_err("%s: option %s: unable to set because the bond device is up\n",
                       bond->dev->name, opt->name);
                break;
        default:
@@ -517,7 +575,7 @@ static void bond_opt_error_interpret(struct bonding *bond,
 int __bond_opt_set(struct bonding *bond,
                   unsigned int option, struct bond_opt_value *val)
 {
-       struct bond_opt_value *retval = NULL;
+       const struct bond_opt_value *retval = NULL;
        const struct bond_option *opt;
        int ret = -ENOENT;
 
@@ -572,7 +630,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
  * This function checks if option is valid and if so returns a pointer
  * to its entry in the bond_opts[] option array.
  */
-struct bond_option *bond_opt_get(unsigned int option)
+const struct bond_option *bond_opt_get(unsigned int option)
 {
        if (!BOND_OPT_VALID(option))
                return NULL;
@@ -580,7 +638,7 @@ struct bond_option *bond_opt_get(unsigned int option)
        return &bond_opts[option];
 }
 
-int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval)
+int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval)
 {
        if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) {
                pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n",
@@ -589,7 +647,7 @@ int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval)
                bond->params.arp_interval = 0;
                /* set miimon to default value */
                bond->params.miimon = BOND_DEFAULT_MIIMON;
-               pr_info("%s: Setting MII monitoring interval to %d.\n",
+               pr_info("%s: Setting MII monitoring interval to %d\n",
                        bond->dev->name, bond->params.miimon);
        }
 
@@ -618,8 +676,8 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond)
        return __bond_option_active_slave_get(bond, bond->curr_active_slave);
 }
 
-int bond_option_active_slave_set(struct bonding *bond,
-                                struct bond_opt_value *newval)
+static int bond_option_active_slave_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval)
 {
        char ifname[IFNAMSIZ] = { 0, };
        struct net_device *slave_dev;
@@ -636,13 +694,13 @@ int bond_option_active_slave_set(struct bonding *bond,
 
        if (slave_dev) {
                if (!netif_is_bond_slave(slave_dev)) {
-                       pr_err("Device %s is not bonding slave.\n",
+                       pr_err("Device %s is not bonding slave\n",
                               slave_dev->name);
                        return -EINVAL;
                }
 
                if (bond->dev != netdev_master_upper_dev_get(slave_dev)) {
-                       pr_err("%s: Device %s is not our slave.\n",
+                       pr_err("%s: Device %s is not our slave\n",
                               bond->dev->name, slave_dev->name);
                        return -EINVAL;
                }
@@ -653,9 +711,8 @@ int bond_option_active_slave_set(struct bonding *bond,
 
        /* check to see if we are clearing active */
        if (!slave_dev) {
-               pr_info("%s: Clearing current active slave.\n",
-               bond->dev->name);
-               rcu_assign_pointer(bond->curr_active_slave, NULL);
+               pr_info("%s: Clearing current active slave\n", bond->dev->name);
+               RCU_INIT_POINTER(bond->curr_active_slave, NULL);
                bond_select_active_slave(bond);
        } else {
                struct slave *old_active = bond->curr_active_slave;
@@ -665,16 +722,16 @@ int bond_option_active_slave_set(struct bonding *bond,
 
                if (new_active == old_active) {
                        /* do nothing */
-                       pr_info("%s: %s is already the current active slave.\n",
+                       pr_info("%s: %s is already the current active slave\n",
                                bond->dev->name, new_active->dev->name);
                } else {
                        if (old_active && (new_active->link == BOND_LINK_UP) &&
                            IS_UP(new_active->dev)) {
-                               pr_info("%s: Setting %s as active slave.\n",
+                               pr_info("%s: Setting %s as active slave\n",
                                        bond->dev->name, new_active->dev->name);
                                bond_change_active_slave(bond, new_active);
                        } else {
-                               pr_err("%s: Could not set %s as active slave; either %s is down or the link is down.\n",
+                               pr_err("%s: Could not set %s as active slave; either %s is down or the link is down\n",
                                       bond->dev->name, new_active->dev->name,
                                       new_active->dev->name);
                                ret = -EINVAL;
@@ -688,21 +745,22 @@ int bond_option_active_slave_set(struct bonding *bond,
        return ret;
 }
 
-int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_miimon_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting MII monitoring interval to %llu.\n",
+       pr_info("%s: Setting MII monitoring interval to %llu\n",
                bond->dev->name, newval->value);
        bond->params.miimon = newval->value;
        if (bond->params.updelay)
-               pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
+               pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
                        bond->dev->name,
                        bond->params.updelay * bond->params.miimon);
        if (bond->params.downdelay)
-               pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
+               pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
                        bond->dev->name,
                        bond->params.downdelay * bond->params.miimon);
        if (newval->value && bond->params.arp_interval) {
-               pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
+               pr_info("%s: MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n",
                        bond->dev->name);
                bond->params.arp_interval = 0;
                if (bond->params.arp_validate)
@@ -725,7 +783,8 @@ int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval)
        return 0;
 }
 
-int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_updelay_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval)
 {
        int value = newval->value;
 
@@ -742,15 +801,14 @@ int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval)
                        bond->params.miimon);
        }
        bond->params.updelay = value / bond->params.miimon;
-       pr_info("%s: Setting up delay to %d.\n",
-               bond->dev->name,
-               bond->params.updelay * bond->params.miimon);
+       pr_info("%s: Setting up delay to %d\n",
+               bond->dev->name, bond->params.updelay * bond->params.miimon);
 
        return 0;
 }
 
-int bond_option_downdelay_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_downdelay_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
        int value = newval->value;
 
@@ -767,37 +825,36 @@ int bond_option_downdelay_set(struct bonding *bond,
                        bond->params.miimon);
        }
        bond->params.downdelay = value / bond->params.miimon;
-       pr_info("%s: Setting down delay to %d.\n",
-               bond->dev->name,
-               bond->params.downdelay * bond->params.miimon);
+       pr_info("%s: Setting down delay to %d\n",
+               bond->dev->name, bond->params.downdelay * bond->params.miimon);
 
        return 0;
 }
 
-int bond_option_use_carrier_set(struct bonding *bond,
-                               struct bond_opt_value *newval)
+static int bond_option_use_carrier_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting use_carrier to %llu.\n",
+       pr_info("%s: Setting use_carrier to %llu\n",
                bond->dev->name, newval->value);
        bond->params.use_carrier = newval->value;
 
        return 0;
 }
 
-int bond_option_arp_interval_set(struct bonding *bond,
-                                struct bond_opt_value *newval)
+static int bond_option_arp_interval_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting ARP monitoring interval to %llu.\n",
+       pr_info("%s: Setting ARP monitoring interval to %llu\n",
                bond->dev->name, newval->value);
        bond->params.arp_interval = newval->value;
        if (newval->value) {
                if (bond->params.miimon) {
-                       pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
+                       pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring\n",
                                bond->dev->name, bond->dev->name);
                        bond->params.miimon = 0;
                }
                if (!bond->params.arp_targets[0])
-                       pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
+                       pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified\n",
                                bond->dev->name);
        }
        if (bond->dev->flags & IFF_UP) {
@@ -812,8 +869,7 @@ int bond_option_arp_interval_set(struct bonding *bond,
                        cancel_delayed_work_sync(&bond->arp_work);
                } else {
                        /* arp_validate can be set only in active-backup mode */
-                       if (bond->params.arp_validate)
-                               bond->recv_probe = bond_arp_rcv;
+                       bond->recv_probe = bond_arp_rcv;
                        cancel_delayed_work_sync(&bond->mii_work);
                        queue_delayed_work(bond->wq, &bond->arp_work, 0);
                }
@@ -856,19 +912,18 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
 
        ind = bond_get_targets_ip(targets, 0); /* first free slot */
        if (ind == -1) {
-               pr_err("%s: ARP target table is full!\n",
-                      bond->dev->name);
+               pr_err("%s: ARP target table is full!\n", bond->dev->name);
                return -EINVAL;
        }
 
-       pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, &target);
+       pr_info("%s: Adding ARP target %pI4\n", bond->dev->name, &target);
 
        _bond_options_arp_ip_target_set(bond, ind, target, jiffies);
 
        return 0;
 }
 
-int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
 {
        int ret;
 
@@ -880,7 +935,7 @@ int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
        return ret;
 }
 
-int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
+static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
 {
        __be32 *targets = bond->params.arp_targets;
        struct list_head *iter;
@@ -896,17 +951,16 @@ int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
 
        ind = bond_get_targets_ip(targets, target);
        if (ind == -1) {
-               pr_err("%s: unable to remove nonexistent ARP target %pI4.\n",
+               pr_err("%s: unable to remove nonexistent ARP target %pI4\n",
                       bond->dev->name, &target);
                return -EINVAL;
        }
 
        if (ind == 0 && !targets[1] && bond->params.arp_interval)
-               pr_warn("%s: removing last arp target with arp_interval on\n",
+               pr_warn("%s: Removing last arp target with arp_interval on\n",
                        bond->dev->name);
 
-       pr_info("%s: removing ARP target %pI4.\n", bond->dev->name,
-               &target);
+       pr_info("%s: Removing ARP target %pI4\n", bond->dev->name, &target);
 
        /* not to race with bond_arp_rcv */
        write_lock_bh(&bond->lock);
@@ -937,8 +991,8 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond)
        write_unlock_bh(&bond->lock);
 }
 
-int bond_option_arp_ip_targets_set(struct bonding *bond,
-                                  struct bond_opt_value *newval)
+static int bond_option_arp_ip_targets_set(struct bonding *bond,
+                                         const struct bond_opt_value *newval)
 {
        int ret = -EPERM;
        __be32 target;
@@ -954,7 +1008,7 @@ int bond_option_arp_ip_targets_set(struct bonding *bond,
                else if (newval->string[0] == '-')
                        ret = bond_option_arp_ip_target_rem(bond, target);
                else
-                       pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n",
+                       pr_err("no command found in arp_ip_targets file for bond %s - use +<addr> or -<addr>\n",
                               bond->dev->name);
        } else {
                target = newval->value;
@@ -964,10 +1018,10 @@ int bond_option_arp_ip_targets_set(struct bonding *bond,
        return ret;
 }
 
-int bond_option_arp_validate_set(struct bonding *bond,
-                                struct bond_opt_value *newval)
+static int bond_option_arp_validate_set(struct bonding *bond,
+                                       const struct bond_opt_value *newval)
 {
-       pr_info("%s: setting arp_validate to %s (%llu).\n",
+       pr_info("%s: Setting arp_validate to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
 
        if (bond->dev->flags & IFF_UP) {
@@ -981,17 +1035,18 @@ int bond_option_arp_validate_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_arp_all_targets_set(struct bonding *bond,
-                                   struct bond_opt_value *newval)
+static int bond_option_arp_all_targets_set(struct bonding *bond,
+                                          const struct bond_opt_value *newval)
 {
-       pr_info("%s: setting arp_all_targets to %s (%llu).\n",
+       pr_info("%s: Setting arp_all_targets to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
        bond->params.arp_all_targets = newval->value;
 
        return 0;
 }
 
-int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_primary_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval)
 {
        char *p, *primary = newval->string;
        struct list_head *iter;
@@ -1006,8 +1061,7 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
                *p = '\0';
        /* check to see if we are clearing primary */
        if (!strlen(primary)) {
-               pr_info("%s: Setting primary slave to None.\n",
-                       bond->dev->name);
+               pr_info("%s: Setting primary slave to None\n", bond->dev->name);
                bond->primary_slave = NULL;
                memset(bond->params.primary, 0, sizeof(bond->params.primary));
                bond_select_active_slave(bond);
@@ -1016,7 +1070,7 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
 
        bond_for_each_slave(bond, slave, iter) {
                if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
-                       pr_info("%s: Setting %s as primary slave.\n",
+                       pr_info("%s: Setting %s as primary slave\n",
                                bond->dev->name, slave->dev->name);
                        bond->primary_slave = slave;
                        strcpy(bond->params.primary, slave->dev->name);
@@ -1026,15 +1080,14 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval)
        }
 
        if (bond->primary_slave) {
-               pr_info("%s: Setting primary slave to None.\n",
-                       bond->dev->name);
+               pr_info("%s: Setting primary slave to None\n", bond->dev->name);
                bond->primary_slave = NULL;
                bond_select_active_slave(bond);
        }
        strncpy(bond->params.primary, primary, IFNAMSIZ);
        bond->params.primary[IFNAMSIZ - 1] = 0;
 
-       pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet.\n",
+       pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet\n",
                bond->dev->name, primary, bond->dev->name);
 
 out:
@@ -1045,10 +1098,10 @@ out:
        return 0;
 }
 
-int bond_option_primary_reselect_set(struct bonding *bond,
-                                    struct bond_opt_value *newval)
+static int bond_option_primary_reselect_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval)
 {
-       pr_info("%s: setting primary_reselect to %s (%llu).\n",
+       pr_info("%s: Setting primary_reselect to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
        bond->params.primary_reselect = newval->value;
 
@@ -1061,46 +1114,46 @@ int bond_option_primary_reselect_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_fail_over_mac_set(struct bonding *bond,
-                                 struct bond_opt_value *newval)
+static int bond_option_fail_over_mac_set(struct bonding *bond,
+                                        const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting fail_over_mac to %s (%llu).\n",
+       pr_info("%s: Setting fail_over_mac to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
        bond->params.fail_over_mac = newval->value;
 
        return 0;
 }
 
-int bond_option_xmit_hash_policy_set(struct bonding *bond,
-                                    struct bond_opt_value *newval)
+static int bond_option_xmit_hash_policy_set(struct bonding *bond,
+                                           const struct bond_opt_value *newval)
 {
-       pr_info("%s: setting xmit hash policy to %s (%llu).\n",
+       pr_info("%s: Setting xmit hash policy to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
        bond->params.xmit_policy = newval->value;
 
        return 0;
 }
 
-int bond_option_resend_igmp_set(struct bonding *bond,
-                               struct bond_opt_value *newval)
+static int bond_option_resend_igmp_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting resend_igmp to %llu.\n",
+       pr_info("%s: Setting resend_igmp to %llu\n",
                bond->dev->name, newval->value);
        bond->params.resend_igmp = newval->value;
 
        return 0;
 }
 
-int bond_option_num_peer_notif_set(struct bonding *bond,
-                                  struct bond_opt_value *newval)
+static int bond_option_num_peer_notif_set(struct bonding *bond,
+                                  const struct bond_opt_value *newval)
 {
        bond->params.num_peer_notif = newval->value;
 
        return 0;
 }
 
-int bond_option_all_slaves_active_set(struct bonding *bond,
-                                     struct bond_opt_value *newval)
+static int bond_option_all_slaves_active_set(struct bonding *bond,
+                                            const struct bond_opt_value *newval)
 {
        struct list_head *iter;
        struct slave *slave;
@@ -1120,8 +1173,8 @@ int bond_option_all_slaves_active_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_min_links_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_min_links_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
        pr_info("%s: Setting min links value to %llu\n",
                bond->dev->name, newval->value);
@@ -1130,15 +1183,16 @@ int bond_option_min_links_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_lp_interval_set(struct bonding *bond,
-                               struct bond_opt_value *newval)
+static int bond_option_lp_interval_set(struct bonding *bond,
+                                      const struct bond_opt_value *newval)
 {
        bond->params.lp_interval = newval->value;
 
        return 0;
 }
 
-int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_pps_set(struct bonding *bond,
+                              const struct bond_opt_value *newval)
 {
        bond->params.packets_per_slave = newval->value;
        if (newval->value > 0) {
@@ -1155,10 +1209,10 @@ int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval)
        return 0;
 }
 
-int bond_option_lacp_rate_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_lacp_rate_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting LACP rate to %s (%llu).\n",
+       pr_info("%s: Setting LACP rate to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
        bond->params.lacp_fast = newval->value;
        bond_3ad_update_lacp_rate(bond);
@@ -1166,18 +1220,18 @@ int bond_option_lacp_rate_set(struct bonding *bond,
        return 0;
 }
 
-int bond_option_ad_select_set(struct bonding *bond,
-                             struct bond_opt_value *newval)
+static int bond_option_ad_select_set(struct bonding *bond,
+                                    const struct bond_opt_value *newval)
 {
-       pr_info("%s: Setting ad_select to %s (%llu).\n",
+       pr_info("%s: Setting ad_select to %s (%llu)\n",
                bond->dev->name, newval->string, newval->value);
        bond->params.ad_select = newval->value;
 
        return 0;
 }
 
-int bond_option_queue_id_set(struct bonding *bond,
-                            struct bond_opt_value *newval)
+static int bond_option_queue_id_set(struct bonding *bond,
+                                   const struct bond_opt_value *newval)
 {
        struct slave *slave, *update_slave;
        struct net_device *sdev;
@@ -1199,8 +1253,7 @@ int bond_option_queue_id_set(struct bonding *bond,
                goto err_no_cmd;
 
        /* Check buffer length, valid ifname and queue id */
-       if (strlen(newval->string) > IFNAMSIZ ||
-           !dev_valid_name(newval->string) ||
+       if (!dev_valid_name(newval->string) ||
            qid > bond->dev->real_num_tx_queues)
                goto err_no_cmd;
 
@@ -1232,14 +1285,14 @@ out:
        return ret;
 
 err_no_cmd:
-       pr_info("invalid input for queue_id set for %s.\n",
-               bond->dev->name);
+       pr_info("invalid input for queue_id set for %s\n", bond->dev->name);
        ret = -EPERM;
        goto out;
 
 }
 
-int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
+static int bond_option_slaves_set(struct bonding *bond,
+                                 const struct bond_opt_value *newval)
 {
        char command[IFNAMSIZ + 1] = { 0, };
        struct net_device *dev;
@@ -1254,7 +1307,7 @@ int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
 
        dev = __dev_get_by_name(dev_net(bond->dev), ifname);
        if (!dev) {
-               pr_info("%s: Interface %s does not exist!\n",
+               pr_info("%s: interface %s does not exist!\n",
                        bond->dev->name, ifname);
                ret = -ENODEV;
                goto out;
@@ -1262,12 +1315,12 @@ int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval)
 
        switch (command[0]) {
        case '+':
-               pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
+               pr_info("%s: Adding slave %s\n", bond->dev->name, dev->name);
                ret = bond_enslave(bond->dev, dev);
                break;
 
        case '-':
-               pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
+               pr_info("%s: Removing slave %s\n", bond->dev->name, dev->name);
                ret = bond_release(bond->dev, dev);
                break;
 
@@ -1279,7 +1332,7 @@ out:
        return ret;
 
 err_no_cmd:
-       pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
+       pr_err("no command found in slaves file for bond %s - use +ifname or -ifname\n",
               bond->dev->name);
        ret = -EPERM;
        goto out;
index 433d37f6940b997649147ba4d8c0f415bdba47c9..12be9e1bfb0c0d048229a1698c2b384847fbd794 100644 (file)
@@ -81,8 +81,8 @@ struct bonding;
 
 struct bond_option {
        int id;
-       char *name;
-       char *desc;
+       const char *name;
+       const char *desc;
        u32 flags;
 
        /* unsuppmodes is used to denote modes in which the option isn't
@@ -92,18 +92,19 @@ struct bond_option {
        /* supported values which this option can have, can be a subset of
         * BOND_OPTVAL_RANGE's value range
         */
-       struct bond_opt_value *values;
+       const struct bond_opt_value *values;
 
-       int (*set)(struct bonding *bond, struct bond_opt_value *val);
+       int (*set)(struct bonding *bond, const struct bond_opt_value *val);
 };
 
 int __bond_opt_set(struct bonding *bond, unsigned int option,
                   struct bond_opt_value *val);
 int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf);
-struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
-                                     struct bond_opt_value *val);
-struct bond_option *bond_opt_get(unsigned int option);
-struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
+
+const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
+                                           struct bond_opt_value *val);
+const struct bond_option *bond_opt_get(unsigned int option);
+const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val);
 
 /* This helper is used to initialize a bond_opt_value structure for parameter
  * passing. There should be either a valid string or value, but not both.
@@ -122,49 +123,6 @@ static inline void __bond_opt_init(struct bond_opt_value *optval,
 #define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value)
 #define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX)
 
-int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_xmit_hash_policy_set(struct bonding *bond,
-                                    struct bond_opt_value *newval);
-int bond_option_arp_validate_set(struct bonding *bond,
-                                struct bond_opt_value *newval);
-int bond_option_arp_all_targets_set(struct bonding *bond,
-                                   struct bond_opt_value *newval);
-int bond_option_fail_over_mac_set(struct bonding *bond,
-                                 struct bond_opt_value *newval);
-int bond_option_arp_interval_set(struct bonding *bond,
-                                struct bond_opt_value *newval);
-int bond_option_arp_ip_targets_set(struct bonding *bond,
-                                  struct bond_opt_value *newval);
 void bond_option_arp_ip_targets_clear(struct bonding *bond);
-int bond_option_downdelay_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_updelay_set(struct bonding *bond,
-                           struct bond_opt_value *newval);
-int bond_option_lacp_rate_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_min_links_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_ad_select_set(struct bonding *bond,
-                             struct bond_opt_value *newval);
-int bond_option_num_peer_notif_set(struct bonding *bond,
-                                  struct bond_opt_value *newval);
-int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval);
-int bond_option_primary_set(struct bonding *bond,
-                           struct bond_opt_value *newval);
-int bond_option_primary_reselect_set(struct bonding *bond,
-                                    struct bond_opt_value *newval);
-int bond_option_use_carrier_set(struct bonding *bond,
-                               struct bond_opt_value *newval);
-int bond_option_active_slave_set(struct bonding *bond,
-                                struct bond_opt_value *newval);
-int bond_option_queue_id_set(struct bonding *bond,
-                            struct bond_opt_value *newval);
-int bond_option_all_slaves_active_set(struct bonding *bond,
-                                     struct bond_opt_value *newval);
-int bond_option_resend_igmp_set(struct bonding *bond,
-                               struct bond_opt_value *newval);
-int bond_option_lp_interval_set(struct bonding *bond,
-                               struct bond_opt_value *newval);
-int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval);
+
 #endif /* _BOND_OPTIONS_H */
index 3ac20e78eafc628bf87c852b9e2fd9c2b20bf992..013fdd0f45e94340917ee2aeecc8529d386862e2 100644 (file)
@@ -65,13 +65,11 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v)
 static void bond_info_show_master(struct seq_file *seq)
 {
        struct bonding *bond = seq->private;
-       struct bond_opt_value *optval;
+       const struct bond_opt_value *optval;
        struct slave *curr;
        int i;
 
-       read_lock(&bond->curr_slave_lock);
-       curr = bond->curr_active_slave;
-       read_unlock(&bond->curr_slave_lock);
+       curr = rcu_dereference(bond->curr_active_slave);
 
        seq_printf(seq, "Bonding Mode: %s",
                   bond_mode_name(bond->params.mode));
@@ -254,8 +252,8 @@ void bond_create_proc_entry(struct bonding *bond)
                                                    S_IRUGO, bn->proc_dir,
                                                    &bond_info_fops, bond);
                if (bond->proc_entry == NULL)
-                       pr_warning("Warning: Cannot create /proc/net/%s/%s\n",
-                                  DRV_NAME, bond_dev->name);
+                       pr_warn("Warning: Cannot create /proc/net/%s/%s\n",
+                               DRV_NAME, bond_dev->name);
                else
                        memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ);
        }
@@ -281,8 +279,8 @@ void __net_init bond_create_proc_dir(struct bond_net *bn)
        if (!bn->proc_dir) {
                bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net);
                if (!bn->proc_dir)
-                       pr_warning("Warning: cannot create /proc/net/%s\n",
-                                  DRV_NAME);
+                       pr_warn("Warning: Cannot create /proc/net/%s\n",
+                               DRV_NAME);
        }
 }
 
index 643fcc110299b7b5c9f728703a849d8fd13d5ce8..0e8b268da0a08f58c4443c6c36aa62bb9ef0f071 100644 (file)
@@ -117,9 +117,9 @@ static ssize_t bonding_store_bonds(struct class *cls,
                rv = bond_create(bn->net, ifname);
                if (rv) {
                        if (rv == -EEXIST)
-                               pr_info("%s already exists.\n", ifname);
+                               pr_info("%s already exists\n", ifname);
                        else
-                               pr_info("%s creation failed.\n", ifname);
+                               pr_info("%s creation failed\n", ifname);
                        res = rv;
                }
        } else if (command[0] == '-') {
@@ -144,7 +144,7 @@ static ssize_t bonding_store_bonds(struct class *cls,
        return res;
 
 err_no_cmd:
-       pr_err("no command found in bonding_masters. Use +ifname or -ifname.\n");
+       pr_err("no command found in bonding_masters - use +ifname or -ifname\n");
        return -EPERM;
 }
 
@@ -220,7 +220,7 @@ static ssize_t bonding_show_mode(struct device *d,
                                 struct device_attribute *attr, char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode);
 
@@ -251,7 +251,7 @@ static ssize_t bonding_show_xmit_hash(struct device *d,
                                      char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy);
 
@@ -282,7 +282,7 @@ static ssize_t bonding_show_arp_validate(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE,
                               bond->params.arp_validate);
@@ -314,7 +314,7 @@ static ssize_t bonding_show_arp_all_targets(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS,
                               bond->params.arp_all_targets);
@@ -348,7 +348,7 @@ static ssize_t bonding_show_fail_over_mac(struct device *d,
                                          char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC,
                               bond->params.fail_over_mac);
@@ -505,7 +505,7 @@ static ssize_t bonding_show_lacp(struct device *d,
                                 char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast);
 
@@ -558,7 +558,7 @@ static ssize_t bonding_show_ad_select(struct device *d,
                                      char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select);
 
@@ -686,7 +686,7 @@ static ssize_t bonding_show_primary_reselect(struct device *d,
                                             char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct bond_opt_value *val;
+       const struct bond_opt_value *val;
 
        val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT,
                               bond->params.primary_reselect);
@@ -1135,7 +1135,7 @@ int bond_create_sysfs(struct bond_net *bn)
                /* Is someone being kinky and naming a device bonding_master? */
                if (__dev_get_by_name(bn->net,
                                      class_attr_bonding_masters.attr.name))
-                       pr_err("network device named %s already exists in sysfs",
+                       pr_err("network device named %s already exists in sysfs\n",
                               class_attr_bonding_masters.attr.name);
                ret = 0;
        }
index 86ccfb9f71cc4dd8c843f40f5eee38b7c0c033ab..b8bdd0acc8f334ac97bca2ddfea602f473c3272f 100644 (file)
@@ -188,14 +188,16 @@ struct slave {
        struct net_device *dev; /* first - useful for panic debug */
        struct bonding *bond; /* our master */
        int    delay;
-       unsigned long jiffies;
-       unsigned long last_arp_rx;
+       /* all three in jiffies */
+       unsigned long last_link_up;
+       unsigned long last_rx;
        unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS];
        s8     link;    /* one of BOND_LINK_XXXX */
        s8     new_link;
        u8     backup:1,   /* indicates backup slave. Value corresponds with
                              BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
-              inactive:1; /* indicates inactive slave */
+              inactive:1, /* indicates inactive slave */
+              should_notify:1; /* indicateds whether the state changed */
        u8     duplex;
        u32    original_mtu;
        u32    link_failure_count;
@@ -264,6 +266,11 @@ struct bonding {
 #define bond_slave_get_rtnl(dev) \
        ((struct slave *) rtnl_dereference(dev->rx_handler_data))
 
+struct bond_vlan_tag {
+       __be16          vlan_proto;
+       unsigned short  vlan_id;
+};
+
 /**
  * Returns NULL if the net_device does not belong to any of the bond's slaves
  *
@@ -291,7 +298,7 @@ static inline void bond_set_active_slave(struct slave *slave)
 {
        if (slave->backup) {
                slave->backup = 0;
-               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
        }
 }
 
@@ -299,7 +306,25 @@ static inline void bond_set_backup_slave(struct slave *slave)
 {
        if (!slave->backup) {
                slave->backup = 1;
-               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL);
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+       }
+}
+
+static inline void bond_set_slave_state(struct slave *slave,
+                                       int slave_state, bool notify)
+{
+       if (slave->backup == slave_state)
+               return;
+
+       slave->backup = slave_state;
+       if (notify) {
+               rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC);
+               slave->should_notify = 0;
+       } else {
+               if (slave->should_notify)
+                       slave->should_notify = 0;
+               else
+                       slave->should_notify = 1;
        }
 }
 
@@ -316,6 +341,19 @@ static inline void bond_slave_state_change(struct bonding *bond)
        }
 }
 
+static inline void bond_slave_state_notify(struct bonding *bond)
+{
+       struct list_head *iter;
+       struct slave *tmp;
+
+       bond_for_each_slave(bond, tmp, iter) {
+               if (tmp->should_notify) {
+                       rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC);
+                       tmp->should_notify = 0;
+               }
+       }
+}
+
 static inline int bond_slave_state(struct slave *slave)
 {
        return slave->backup;
@@ -342,6 +380,14 @@ static inline bool bond_is_active_slave(struct slave *slave)
 #define BOND_ARP_VALIDATE_BACKUP       (1 << BOND_STATE_BACKUP)
 #define BOND_ARP_VALIDATE_ALL          (BOND_ARP_VALIDATE_ACTIVE | \
                                         BOND_ARP_VALIDATE_BACKUP)
+#define BOND_ARP_FILTER                        (BOND_ARP_VALIDATE_ALL + 1)
+#define BOND_ARP_FILTER_ACTIVE         (BOND_ARP_VALIDATE_ACTIVE | \
+                                        BOND_ARP_FILTER)
+#define BOND_ARP_FILTER_BACKUP         (BOND_ARP_VALIDATE_BACKUP | \
+                                        BOND_ARP_FILTER)
+
+#define BOND_SLAVE_NOTIFY_NOW          true
+#define BOND_SLAVE_NOTIFY_LATER                false
 
 static inline int slave_do_arp_validate(struct bonding *bond,
                                        struct slave *slave)
@@ -349,6 +395,12 @@ static inline int slave_do_arp_validate(struct bonding *bond,
        return bond->params.arp_validate & (1 << bond_slave_state(slave));
 }
 
+static inline int slave_do_arp_validate_only(struct bonding *bond,
+                                            struct slave *slave)
+{
+       return bond->params.arp_validate & BOND_ARP_FILTER;
+}
+
 /* Get the oldest arp which we've received on this slave for bond's
  * arp_targets.
  */
@@ -368,14 +420,10 @@ static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond,
 static inline unsigned long slave_last_rx(struct bonding *bond,
                                        struct slave *slave)
 {
-       if (slave_do_arp_validate(bond, slave)) {
-               if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL)
-                       return slave_oldest_target_arp_rx(bond, slave);
-               else
-                       return slave->last_arp_rx;
-       }
+       if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL)
+               return slave_oldest_target_arp_rx(bond, slave);
 
-       return slave->dev->last_rx;
+       return slave->last_rx;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -394,17 +442,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave,
 }
 #endif
 
-static inline void bond_set_slave_inactive_flags(struct slave *slave)
+static inline void bond_set_slave_inactive_flags(struct slave *slave,
+                                                bool notify)
 {
        if (!bond_is_lb(slave->bond))
-               bond_set_backup_slave(slave);
+               bond_set_slave_state(slave, BOND_STATE_BACKUP, notify);
        if (!slave->bond->params.all_slaves_active)
                slave->inactive = 1;
 }
 
-static inline void bond_set_slave_active_flags(struct slave *slave)
+static inline void bond_set_slave_active_flags(struct slave *slave,
+                                              bool notify)
 {
-       bond_set_active_slave(slave);
+       bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify);
        slave->inactive = 0;
 }
 
@@ -450,8 +500,6 @@ void bond_sysfs_slave_del(struct slave *slave);
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
 int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count);
-int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
-int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl);
 void bond_select_active_slave(struct bonding *bond);
 void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
 void bond_create_debugfs(void);
@@ -464,8 +512,6 @@ void bond_setup(struct net_device *bond_dev);
 unsigned int bond_get_num_tx_queues(void);
 int bond_netlink_init(void);
 void bond_netlink_fini(void);
-int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
-int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
 struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
 struct net_device *bond_option_active_slave_get(struct bonding *bond);
 const char *bond_slave_link_status(s8 link);
index 88a6a5810ec6820a1e8f2b674021a4a142804885..fc73865bb83a705f9fa1d1f3d70e1c6191952b9b 100644 (file)
@@ -204,7 +204,6 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
 
        skb->protocol = htons(ETH_P_CAIF);
        skb_reset_mac_header(skb);
-       skb->dev = ser->dev;
        debugfs_rx(ser, data, count);
        /* Push received packet up the stack. */
        ret = netif_rx_ni(skb);
index 155db68e13bae83ce006d7835bdbc93d38cdd878..ff54c0eb2052137d8f1561448f3c654f34d354df 100644 (file)
@@ -554,7 +554,6 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
 
                skb->protocol = htons(ETH_P_CAIF);
                skb_reset_mac_header(skb);
-               skb->dev = cfspi->ndev;
 
                /*
                 * Push received packet up the stack.
index d447b881bbde1af6d25f6102b0f3efc639893d70..9e7d95dae2c7038478d6efadddba81e2778f47a9 100644 (file)
@@ -104,7 +104,7 @@ config CAN_JANZ_ICAN3
 
 config CAN_FLEXCAN
        tristate "Support for Freescale FLEXCAN based chips"
-       depends on (ARM && CPU_LITTLE_ENDIAN) || PPC
+       depends on ARM || PPC
        ---help---
          Say Y here if you want to support for Freescale FlexCAN.
 
index 6efe27458116cf7f5af0c48f68f7cc8a68a55cdd..f07fa89b5fd5b294a5a234e949985080a0617a1d 100644 (file)
@@ -420,7 +420,11 @@ static void at91_chip_start(struct net_device *dev)
        at91_transceiver_switch(priv, 1);
 
        /* enable chip */
-       at91_write(priv, AT91_MR, AT91_MR_CANEN);
+       if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
+               reg_mr = AT91_MR_CANEN | AT91_MR_ABM;
+       else
+               reg_mr = AT91_MR_CANEN;
+       at91_write(priv, AT91_MR, reg_mr);
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
@@ -1190,6 +1194,7 @@ static const struct net_device_ops at91_netdev_ops = {
        .ndo_open       = at91_open,
        .ndo_stop       = at91_close,
        .ndo_start_xmit = at91_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
@@ -1341,7 +1346,8 @@ static int at91_can_probe(struct platform_device *pdev)
        priv->can.bittiming_const = &at91_bittiming_const;
        priv->can.do_set_mode = at91_set_mode;
        priv->can.do_get_berr_counter = at91_get_berr_counter;
-       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+       priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
+               CAN_CTRLMODE_LISTENONLY;
        priv->dev = dev;
        priv->reg_base = addr;
        priv->devtype_data = *devtype_data;
index 8d2b89a12e09b5f19c35757fc7fddb75689395e5..543ecceb33e91341ca0a6651e92d3dcbce1d0978 100644 (file)
@@ -528,6 +528,7 @@ static const struct net_device_ops bfin_can_netdev_ops = {
        .ndo_open               = bfin_can_open,
        .ndo_stop               = bfin_can_close,
        .ndo_start_xmit         = bfin_can_start_xmit,
+       .ndo_change_mtu         = can_change_mtu,
 };
 
 static int bfin_can_probe(struct platform_device *pdev)
index 951bfede8f3d80b7026b2bfba219d5c3e092f210..9c32e9ef76942192fd94fca634a6565468458946 100644 (file)
@@ -1277,6 +1277,7 @@ static const struct net_device_ops c_can_netdev_ops = {
        .ndo_open = c_can_open,
        .ndo_stop = c_can_close,
        .ndo_start_xmit = c_can_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 int register_c_can_dev(struct net_device *dev)
index 0f12abf6591ce79bdc30b1f69844f7d811ac5d1e..d8379278d648a2160f63d386eb5056dc47d70b7a 100644 (file)
@@ -823,6 +823,7 @@ static const struct net_device_ops cc770_netdev_ops = {
        .ndo_open = cc770_open,
        .ndo_stop = cc770_close,
        .ndo_start_xmit = cc770_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 int register_cc770dev(struct net_device *dev)
index 13a909822e25bf54d455c251ab9655f9554f00e9..c7a260478749ad163ec133df88e7a0086b220a73 100644 (file)
@@ -99,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc,
        return 1000 * (tseg + 1 - *tseg2) / (tseg + 1);
 }
 
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                             const struct can_bittiming_const *btc)
 {
        struct can_priv *priv = netdev_priv(dev);
-       const struct can_bittiming_const *btc = priv->bittiming_const;
        long rate, best_rate = 0;
        long best_error = 1000000000, error = 0;
        int best_tseg = 0, best_brp = 0, brp = 0;
@@ -110,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
        int spt_error = 1000, spt = 0, sampl_pt;
        u64 v64;
 
-       if (!priv->bittiming_const)
-               return -ENOTSUPP;
-
        /* Use CIA recommended sample points */
        if (bt->sample_point) {
                sampl_pt = bt->sample_point;
@@ -204,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
        return 0;
 }
 #else /* !CONFIG_CAN_CALC_BITTIMING */
-static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                             const struct can_bittiming_const *btc)
 {
        netdev_err(dev, "bit-timing calculation not available\n");
        return -EINVAL;
@@ -217,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt)
  * prescaler value brp. You can find more information in the header
  * file linux/can/netlink.h.
  */
-static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                              const struct can_bittiming_const *btc)
 {
        struct can_priv *priv = netdev_priv(dev);
-       const struct can_bittiming_const *btc = priv->bittiming_const;
        int tseg1, alltseg;
        u64 brp64;
 
-       if (!priv->bittiming_const)
-               return -ENOTSUPP;
-
        tseg1 = bt->prop_seg + bt->phase_seg1;
        if (!bt->sjw)
                bt->sjw = 1;
@@ -254,26 +249,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt)
        return 0;
 }
 
-static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt)
+static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
+                            const struct can_bittiming_const *btc)
 {
-       struct can_priv *priv = netdev_priv(dev);
        int err;
 
        /* Check if the CAN device has bit-timing parameters */
-       if (priv->bittiming_const) {
+       if (!btc)
+               return -ENOTSUPP;
 
-               /* Non-expert mode? Check if the bitrate has been pre-defined */
-               if (!bt->tq)
-                       /* Determine bit-timing parameters */
-                       err = can_calc_bittiming(dev, bt);
-               else
-                       /* Check bit-timing params and calculate proper brp */
-                       err = can_fixup_bittiming(dev, bt);
-               if (err)
-                       return err;
-       }
+       /*
+        * Depending on the given can_bittiming parameter structure the CAN
+        * timing parameters are calculated based on the provided bitrate OR
+        * alternatively the CAN timing parameters (tq, prop_seg, etc.) are
+        * provided directly which are then checked and fixed up.
+        */
+       if (!bt->tq && bt->bitrate)
+               err = can_calc_bittiming(dev, bt, btc);
+       else if (bt->tq && !bt->bitrate)
+               err = can_fixup_bittiming(dev, bt, btc);
+       else
+               err = -EINVAL;
 
-       return 0;
+       return err;
 }
 
 /*
@@ -317,28 +315,20 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
        BUG_ON(idx >= priv->echo_skb_max);
 
        /* check flag whether this packet has to be looped back */
-       if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) {
+       if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK ||
+           (skb->protocol != htons(ETH_P_CAN) &&
+            skb->protocol != htons(ETH_P_CANFD))) {
                kfree_skb(skb);
                return;
        }
 
        if (!priv->echo_skb[idx]) {
-               struct sock *srcsk = skb->sk;
 
-               if (atomic_read(&skb->users) != 1) {
-                       struct sk_buff *old_skb = skb;
-
-                       skb = skb_clone(old_skb, GFP_ATOMIC);
-                       kfree_skb(old_skb);
-                       if (!skb)
-                               return;
-               } else
-                       skb_orphan(skb);
-
-               skb->sk = srcsk;
+               skb = can_create_echo_skb(skb);
+               if (!skb)
+                       return;
 
                /* make settings for echo to reduce code in irq context */
-               skb->protocol = htons(ETH_P_CAN);
                skb->pkt_type = PACKET_BROADCAST;
                skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb->dev = dev;
@@ -521,6 +511,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf)
 }
 EXPORT_SYMBOL_GPL(alloc_can_skb);
 
+struct sk_buff *alloc_canfd_skb(struct net_device *dev,
+                               struct canfd_frame **cfd)
+{
+       struct sk_buff *skb;
+
+       skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) +
+                              sizeof(struct canfd_frame));
+       if (unlikely(!skb))
+               return NULL;
+
+       skb->protocol = htons(ETH_P_CANFD);
+       skb->pkt_type = PACKET_BROADCAST;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       can_skb_reserve(skb);
+       can_skb_prv(skb)->ifindex = dev->ifindex;
+
+       *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame));
+       memset(*cfd, 0, sizeof(struct canfd_frame));
+
+       return skb;
+}
+EXPORT_SYMBOL_GPL(alloc_canfd_skb);
+
 struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf)
 {
        struct sk_buff *skb;
@@ -580,6 +594,39 @@ void free_candev(struct net_device *dev)
 }
 EXPORT_SYMBOL_GPL(free_candev);
 
+/*
+ * changing MTU and control mode for CAN/CANFD devices
+ */
+int can_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct can_priv *priv = netdev_priv(dev);
+
+       /* Do not allow changing the MTU while running */
+       if (dev->flags & IFF_UP)
+               return -EBUSY;
+
+       /* allow change of MTU according to the CANFD ability of the device */
+       switch (new_mtu) {
+       case CAN_MTU:
+               priv->ctrlmode &= ~CAN_CTRLMODE_FD;
+               break;
+
+       case CANFD_MTU:
+               if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD))
+                       return -EINVAL;
+
+               priv->ctrlmode |= CAN_CTRLMODE_FD;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(can_change_mtu);
+
 /*
  * Common open function when the device gets opened.
  *
@@ -590,11 +637,19 @@ int open_candev(struct net_device *dev)
 {
        struct can_priv *priv = netdev_priv(dev);
 
-       if (!priv->bittiming.tq && !priv->bittiming.bitrate) {
+       if (!priv->bittiming.bitrate) {
                netdev_err(dev, "bit-timing not yet defined\n");
                return -EINVAL;
        }
 
+       /* For CAN FD the data bitrate has to be >= the arbitration bitrate */
+       if ((priv->ctrlmode & CAN_CTRLMODE_FD) &&
+           (!priv->data_bittiming.bitrate ||
+            (priv->data_bittiming.bitrate < priv->bittiming.bitrate))) {
+               netdev_err(dev, "incorrect/missing data bit-timing\n");
+               return -EINVAL;
+       }
+
        /* Switch carrier on if device was stopped while in bus-off state */
        if (!netif_carrier_ok(dev))
                netif_carrier_on(dev);
@@ -633,6 +688,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
                                = { .len = sizeof(struct can_bittiming_const) },
        [IFLA_CAN_CLOCK]        = { .len = sizeof(struct can_clock) },
        [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
+       [IFLA_CAN_DATA_BITTIMING]
+                               = { .len = sizeof(struct can_bittiming) },
+       [IFLA_CAN_DATA_BITTIMING_CONST]
+                               = { .len = sizeof(struct can_bittiming_const) },
 };
 
 static int can_changelink(struct net_device *dev,
@@ -651,9 +710,7 @@ static int can_changelink(struct net_device *dev,
                if (dev->flags & IFF_UP)
                        return -EBUSY;
                memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
-               if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq))
-                       return -EINVAL;
-               err = can_get_bittiming(dev, &bt);
+               err = can_get_bittiming(dev, &bt, priv->bittiming_const);
                if (err)
                        return err;
                memcpy(&priv->bittiming, &bt, sizeof(bt));
@@ -677,6 +734,12 @@ static int can_changelink(struct net_device *dev,
                        return -EOPNOTSUPP;
                priv->ctrlmode &= ~cm->mask;
                priv->ctrlmode |= cm->flags;
+
+               /* CAN_CTRLMODE_FD can only be set when driver supports FD */
+               if (priv->ctrlmode & CAN_CTRLMODE_FD)
+                       dev->mtu = CANFD_MTU;
+               else
+                       dev->mtu = CAN_MTU;
        }
 
        if (data[IFLA_CAN_RESTART_MS]) {
@@ -695,6 +758,27 @@ static int can_changelink(struct net_device *dev,
                        return err;
        }
 
+       if (data[IFLA_CAN_DATA_BITTIMING]) {
+               struct can_bittiming dbt;
+
+               /* Do not allow changing bittiming while running */
+               if (dev->flags & IFF_UP)
+                       return -EBUSY;
+               memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
+                      sizeof(dbt));
+               err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const);
+               if (err)
+                       return err;
+               memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
+
+               if (priv->do_set_data_bittiming) {
+                       /* Finally, set the bit-timing registers */
+                       err = priv->do_set_data_bittiming(dev);
+                       if (err)
+                               return err;
+               }
+       }
+
        return 0;
 }
 
@@ -703,7 +787,8 @@ static size_t can_get_size(const struct net_device *dev)
        struct can_priv *priv = netdev_priv(dev);
        size_t size = 0;
 
-       size += nla_total_size(sizeof(struct can_bittiming));   /* IFLA_CAN_BITTIMING */
+       if (priv->bittiming.bitrate)                            /* IFLA_CAN_BITTIMING */
+               size += nla_total_size(sizeof(struct can_bittiming));
        if (priv->bittiming_const)                              /* IFLA_CAN_BITTIMING_CONST */
                size += nla_total_size(sizeof(struct can_bittiming_const));
        size += nla_total_size(sizeof(struct can_clock));       /* IFLA_CAN_CLOCK */
@@ -712,6 +797,10 @@ static size_t can_get_size(const struct net_device *dev)
        size += nla_total_size(sizeof(u32));                    /* IFLA_CAN_RESTART_MS */
        if (priv->do_get_berr_counter)                          /* IFLA_CAN_BERR_COUNTER */
                size += nla_total_size(sizeof(struct can_berr_counter));
+       if (priv->data_bittiming.bitrate)                       /* IFLA_CAN_DATA_BITTIMING */
+               size += nla_total_size(sizeof(struct can_bittiming));
+       if (priv->data_bittiming_const)                         /* IFLA_CAN_DATA_BITTIMING_CONST */
+               size += nla_total_size(sizeof(struct can_bittiming_const));
 
        return size;
 }
@@ -725,19 +814,34 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
 
        if (priv->do_get_state)
                priv->do_get_state(dev, &state);
-       if (nla_put(skb, IFLA_CAN_BITTIMING,
-                   sizeof(priv->bittiming), &priv->bittiming) ||
+
+       if ((priv->bittiming.bitrate &&
+            nla_put(skb, IFLA_CAN_BITTIMING,
+                    sizeof(priv->bittiming), &priv->bittiming)) ||
+
            (priv->bittiming_const &&
             nla_put(skb, IFLA_CAN_BITTIMING_CONST,
                     sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
+
            nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) ||
            nla_put_u32(skb, IFLA_CAN_STATE, state) ||
            nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
            nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
+
            (priv->do_get_berr_counter &&
             !priv->do_get_berr_counter(dev, &bec) &&
-            nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)))
+            nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
+
+           (priv->data_bittiming.bitrate &&
+            nla_put(skb, IFLA_CAN_DATA_BITTIMING,
+                    sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
+
+           (priv->data_bittiming_const &&
+            nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
+                    sizeof(*priv->data_bittiming_const),
+                    priv->data_bittiming_const)))
                return -EMSGSIZE;
+
        return 0;
 }
 
index aaed97bee4711d1cb2e8b1eb514fc3e343ad21e0..f425ec2c7839de4abe1a481cf94d0fd03435c845 100644 (file)
 
 #define FLEXCAN_MB_CODE_MASK           (0xf0ffffff)
 
+#define FLEXCAN_TIMEOUT_US             (50)
+
 /*
  * FLEXCAN hardware feature flags
  *
@@ -235,9 +237,12 @@ static const struct can_bittiming_const flexcan_bittiming_const = {
 };
 
 /*
- * Abstract off the read/write for arm versus ppc.
+ * Abstract off the read/write for arm versus ppc. This
+ * assumes that PPC uses big-endian registers and everything
+ * else uses little-endian registers, independent of CPU
+ * endianess.
  */
-#if defined(__BIG_ENDIAN)
+#if defined(CONFIG_PPC)
 static inline u32 flexcan_read(void __iomem *addr)
 {
        return in_be32(addr);
@@ -259,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr)
 }
 #endif
 
+static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv)
+{
+       if (!priv->reg_xceiver)
+               return 0;
+
+       return regulator_enable(priv->reg_xceiver);
+}
+
+static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv)
+{
+       if (!priv->reg_xceiver)
+               return 0;
+
+       return regulator_disable(priv->reg_xceiver);
+}
+
 static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
                                              u32 reg_esr)
 {
@@ -266,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
                (reg_esr & FLEXCAN_ESR_ERR_BUS);
 }
 
-static inline void flexcan_chip_enable(struct flexcan_priv *priv)
+static int flexcan_chip_enable(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
        u32 reg;
 
        reg = flexcan_read(&regs->mcr);
        reg &= ~FLEXCAN_MCR_MDIS;
        flexcan_write(reg, &regs->mcr);
 
-       udelay(10);
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
-static inline void flexcan_chip_disable(struct flexcan_priv *priv)
+static int flexcan_chip_disable(struct flexcan_priv *priv)
 {
        struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
        u32 reg;
 
        reg = flexcan_read(&regs->mcr);
        reg |= FLEXCAN_MCR_MDIS;
        flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               usleep_range(10, 20);
+
+       if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_LPM_ACK))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_freeze(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate;
+       u32 reg;
+
+       reg = flexcan_read(&regs->mcr);
+       reg |= FLEXCAN_MCR_HALT;
+       flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && !(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               usleep_range(100, 200);
+
+       if (!(flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_unfreeze(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+       u32 reg;
+
+       reg = flexcan_read(&regs->mcr);
+       reg &= ~FLEXCAN_MCR_HALT;
+       flexcan_write(reg, &regs->mcr);
+
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_FRZ_ACK)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int flexcan_chip_softreset(struct flexcan_priv *priv)
+{
+       struct flexcan_regs __iomem *regs = priv->base;
+       unsigned int timeout = FLEXCAN_TIMEOUT_US / 10;
+
+       flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
+       while (timeout-- && (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST))
+               usleep_range(10, 20);
+
+       if (flexcan_read(&regs->mcr) & FLEXCAN_MCR_SOFTRST)
+               return -ETIMEDOUT;
+
+       return 0;
 }
 
 static int flexcan_get_berr_counter(const struct net_device *dev,
@@ -706,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev)
        u32 reg_mcr, reg_ctrl;
 
        /* enable module */
-       flexcan_chip_enable(priv);
+       err = flexcan_chip_enable(priv);
+       if (err)
+               return err;
 
        /* soft reset */
-       flexcan_write(FLEXCAN_MCR_SOFTRST, &regs->mcr);
-       udelay(10);
-
-       reg_mcr = flexcan_read(&regs->mcr);
-       if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
-               netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n",
-                          reg_mcr);
-               err = -ENODEV;
-               goto out;
-       }
+       err = flexcan_chip_softreset(priv);
+       if (err)
+               goto out_chip_disable;
 
        flexcan_set_bittiming(dev);
 
@@ -785,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev)
        if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES)
                flexcan_write(0x0, &regs->rxfgmask);
 
-       if (priv->reg_xceiver)  {
-               err = regulator_enable(priv->reg_xceiver);
-               if (err)
-                       goto out;
-       }
+       err = flexcan_transceiver_enable(priv);
+       if (err)
+               goto out_chip_disable;
 
        /* synchronize with the can bus */
-       reg_mcr = flexcan_read(&regs->mcr);
-       reg_mcr &= ~FLEXCAN_MCR_HALT;
-       flexcan_write(reg_mcr, &regs->mcr);
+       err = flexcan_chip_unfreeze(priv);
+       if (err)
+               goto out_transceiver_disable;
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
@@ -807,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev)
 
        return 0;
 
- out:
+ out_transceiver_disable:
+       flexcan_transceiver_disable(priv);
+ out_chip_disable:
        flexcan_chip_disable(priv);
        return err;
 }
@@ -822,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev)
 {
        struct flexcan_priv *priv = netdev_priv(dev);
        struct flexcan_regs __iomem *regs = priv->base;
-       u32 reg;
+
+       /* freeze + disable module */
+       flexcan_chip_freeze(priv);
+       flexcan_chip_disable(priv);
 
        /* Disable all interrupts */
        flexcan_write(0, &regs->imask1);
+       flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
+                     &regs->ctrl);
 
-       /* Disable + halt module */
-       reg = flexcan_read(&regs->mcr);
-       reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
-       flexcan_write(reg, &regs->mcr);
-
-       if (priv->reg_xceiver)
-               regulator_disable(priv->reg_xceiver);
+       flexcan_transceiver_disable(priv);
        priv->can.state = CAN_STATE_STOPPED;
 
        return;
@@ -863,7 +947,7 @@ static int flexcan_open(struct net_device *dev)
        /* start chip and queuing */
        err = flexcan_chip_start(dev);
        if (err)
-               goto out_close;
+               goto out_free_irq;
 
        can_led_event(dev, CAN_LED_EVENT_OPEN);
 
@@ -872,6 +956,8 @@ static int flexcan_open(struct net_device *dev)
 
        return 0;
 
+ out_free_irq:
+       free_irq(dev->irq, dev);
  out_close:
        close_candev(dev);
  out_disable_per:
@@ -925,6 +1011,7 @@ static const struct net_device_ops flexcan_netdev_ops = {
        .ndo_open       = flexcan_open,
        .ndo_stop       = flexcan_close,
        .ndo_start_xmit = flexcan_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static int register_flexcandev(struct net_device *dev)
@@ -942,12 +1029,16 @@ static int register_flexcandev(struct net_device *dev)
                goto out_disable_ipg;
 
        /* select "bus clock", chip must be disabled */
-       flexcan_chip_disable(priv);
+       err = flexcan_chip_disable(priv);
+       if (err)
+               goto out_disable_per;
        reg = flexcan_read(&regs->ctrl);
        reg |= FLEXCAN_CTRL_CLK_SRC;
        flexcan_write(reg, &regs->ctrl);
 
-       flexcan_chip_enable(priv);
+       err = flexcan_chip_enable(priv);
+       if (err)
+               goto out_chip_disable;
 
        /* set freeze, halt and activate FIFO, restrict register access */
        reg = flexcan_read(&regs->mcr);
@@ -964,14 +1055,15 @@ static int register_flexcandev(struct net_device *dev)
        if (!(reg & FLEXCAN_MCR_FEN)) {
                netdev_err(dev, "Could not enable RX FIFO, unsupported core\n");
                err = -ENODEV;
-               goto out_disable_per;
+               goto out_chip_disable;
        }
 
        err = register_candev(dev);
 
- out_disable_per:
        /* disable core and turn off clocks */
+ out_chip_disable:
        flexcan_chip_disable(priv);
+ out_disable_per:
        clk_disable_unprepare(priv->clk_per);
  out_disable_ipg:
        clk_disable_unprepare(priv->clk_ipg);
@@ -1041,9 +1133,9 @@ static int flexcan_probe(struct platform_device *pdev)
        of_id = of_match_device(flexcan_of_match, &pdev->dev);
        if (of_id) {
                devtype_data = of_id->data;
-       } else if (pdev->id_entry->driver_data) {
+       } else if (platform_get_device_id(pdev)->driver_data) {
                devtype_data = (struct flexcan_devtype_data *)
-                       pdev->id_entry->driver_data;
+                       platform_get_device_id(pdev)->driver_data;
        } else {
                return -ENODEV;
        }
@@ -1101,21 +1193,24 @@ static int flexcan_probe(struct platform_device *pdev)
 static int flexcan_remove(struct platform_device *pdev)
 {
        struct net_device *dev = platform_get_drvdata(pdev);
+       struct flexcan_priv *priv = netdev_priv(dev);
 
        unregister_flexcandev(dev);
-
+       netif_napi_del(&priv->napi);
        free_candev(dev);
 
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int flexcan_suspend(struct device *device)
+static int __maybe_unused flexcan_suspend(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
+       int err;
 
-       flexcan_chip_disable(priv);
+       err = flexcan_chip_disable(priv);
+       if (err)
+               return err;
 
        if (netif_running(dev)) {
                netif_stop_queue(dev);
@@ -1126,7 +1221,7 @@ static int flexcan_suspend(struct device *device)
        return 0;
 }
 
-static int flexcan_resume(struct device *device)
+static int __maybe_unused flexcan_resume(struct device *device)
 {
        struct net_device *dev = dev_get_drvdata(device);
        struct flexcan_priv *priv = netdev_priv(dev);
@@ -1136,11 +1231,8 @@ static int flexcan_resume(struct device *device)
                netif_device_attach(dev);
                netif_start_queue(dev);
        }
-       flexcan_chip_enable(priv);
-
-       return 0;
+       return flexcan_chip_enable(priv);
 }
-#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume);
 
index ab506d6cab37743a6e207e6bfc3899db749b5148..3fd9fd942c6ef0b38ddaca66492c115f5f5ea771 100644 (file)
@@ -1578,6 +1578,7 @@ static const struct net_device_ops grcan_netdev_ops = {
        .ndo_open       = grcan_open,
        .ndo_stop       = grcan_close,
        .ndo_start_xmit = grcan_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static int grcan_setup_netdev(struct platform_device *ofdev,
index e24e6690d672bfb9f5b2315d2927c1fd8e9b89bd..2382c04dc7807d9c513e64bc1b4f4a2c0ea181e1 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/netdevice.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
+#include <linux/can/skb.h>
 #include <linux/can/error.h>
 
 #include <linux/mfd/janz.h>
@@ -197,9 +198,6 @@ struct ican3_dev {
        struct net_device *ndev;
        struct napi_struct napi;
 
-       /* Device for printing */
-       struct device *dev;
-
        /* module number */
        unsigned int num;
 
@@ -294,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        xord = locl ^ peer;
 
        if ((xord & MSYNC_RB_MASK) == 0x00) {
-               dev_dbg(mod->dev, "no mbox for reading\n");
+               netdev_dbg(mod->ndev, "no mbox for reading\n");
                return -ENOMEM;
        }
 
@@ -339,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        xord = locl ^ peer;
 
        if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) {
-               dev_err(mod->dev, "no mbox for writing\n");
+               netdev_err(mod->ndev, "no mbox for writing\n");
                return -ENOMEM;
        }
 
@@ -541,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        memcpy_fromio(&desc, desc_addr, sizeof(desc));
 
        if (!(desc.control & DESC_VALID)) {
-               dev_dbg(mod->dev, "%s: no free buffers\n", __func__);
+               netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__);
                return -ENOMEM;
        }
 
@@ -572,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg)
        memcpy_fromio(&desc, desc_addr, sizeof(desc));
 
        if (!(desc.control & DESC_VALID)) {
-               dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__);
+               netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__);
                return -ENOMEM;
        }
 
@@ -882,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod,
  */
 static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg)
 {
-       dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data);
+       netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data);
 }
 
 static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
@@ -898,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg)
         * error frame for userspace
         */
        if (msg->spec == MSG_MSGLOST) {
-               dev_err(mod->dev, "lost %d control messages\n", msg->data[0]);
+               netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]);
                return;
        }
 
@@ -938,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
        /* we can only handle the SJA1000 part */
        if (msg->data[1] != CEVTIND_CHIP_SJA1000) {
-               dev_err(mod->dev, "unable to handle errors on non-SJA1000\n");
+               netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n");
                return -ENODEV;
        }
 
        /* check the message length for sanity */
        if (le16_to_cpu(msg->len) < 6) {
-               dev_err(mod->dev, "error message too short\n");
+               netdev_err(mod->ndev, "error message too short\n");
                return -EINVAL;
        }
 
@@ -966,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
         */
        if (isrc == CEVTIND_BEI) {
                int ret;
-               dev_dbg(mod->dev, "bus error interrupt\n");
+               netdev_dbg(mod->ndev, "bus error interrupt\n");
 
                /* TX error */
                if (!(ecc & ECC_DIR)) {
@@ -982,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
                 */
                ret = ican3_set_buserror(mod, 1);
                if (ret) {
-                       dev_err(mod->dev, "unable to re-enable bus-error\n");
+                       netdev_err(mod->ndev, "unable to re-enable bus-error\n");
                        return ret;
                }
 
@@ -997,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
        /* data overrun interrupt */
        if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) {
-               dev_dbg(mod->dev, "data overrun interrupt\n");
+               netdev_dbg(mod->ndev, "data overrun interrupt\n");
                cf->can_id |= CAN_ERR_CRTL;
                cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
                stats->rx_over_errors++;
@@ -1006,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
 
        /* error warning + passive interrupt */
        if (isrc == CEVTIND_EI) {
-               dev_dbg(mod->dev, "error warning + passive interrupt\n");
+               netdev_dbg(mod->ndev, "error warning + passive interrupt\n");
                if (status & SR_BS) {
                        state = CAN_STATE_BUS_OFF;
                        cf->can_id |= CAN_ERR_BUSOFF;
@@ -1087,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
                complete(&mod->termination_comp);
                break;
        default:
-               dev_err(mod->dev, "received an unknown inquiry response\n");
+               netdev_err(mod->ndev, "received an unknown inquiry response\n");
                break;
        }
 }
@@ -1095,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg)
 static void ican3_handle_unknown_message(struct ican3_dev *mod,
                                        struct ican3_msg *msg)
 {
-       dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n",
+       netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n",
                           msg->spec, le16_to_cpu(msg->len));
 }
 
@@ -1104,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod,
  */
 static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
 {
-       dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
+       netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__,
                           mod->num, msg->spec, le16_to_cpu(msg->len));
 
        switch (msg->spec) {
@@ -1133,20 +1131,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg)
  */
 static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb)
 {
-       struct sock *srcsk = skb->sk;
-
-       if (atomic_read(&skb->users) != 1) {
-               struct sk_buff *old_skb = skb;
-
-               skb = skb_clone(old_skb, GFP_ATOMIC);
-               kfree_skb(old_skb);
-               if (!skb)
-                       return;
-       } else {
-               skb_orphan(skb);
-       }
-
-       skb->sk = srcsk;
+       skb = can_create_echo_skb(skb);
+       if (!skb)
+               return;
 
        /* save this skb for tx interrupt echo handling */
        skb_queue_tail(&mod->echoq, skb);
@@ -1322,7 +1309,7 @@ static int ican3_napi(struct napi_struct *napi, int budget)
 
        /* process all communication messages */
        while (true) {
-               struct ican3_msg msg;
+               struct ican3_msg uninitialized_var(msg);
                ret = ican3_recv_msg(mod, &msg);
                if (ret)
                        break;
@@ -1416,7 +1403,7 @@ static int ican3_reset_module(struct ican3_dev *mod)
                msleep(10);
        } while (time_before(jiffies, start + HZ / 4));
 
-       dev_err(mod->dev, "failed to reset CAN module\n");
+       netdev_err(mod->ndev, "failed to reset CAN module\n");
        return -ETIMEDOUT;
 }
 
@@ -1435,7 +1422,7 @@ static int ican3_startup_module(struct ican3_dev *mod)
 
        ret = ican3_reset_module(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to reset module\n");
+               netdev_err(mod->ndev, "unable to reset module\n");
                return ret;
        }
 
@@ -1444,41 +1431,41 @@ static int ican3_startup_module(struct ican3_dev *mod)
 
        ret = ican3_msg_connect(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to connect to module\n");
+               netdev_err(mod->ndev, "unable to connect to module\n");
                return ret;
        }
 
        ican3_init_new_host_interface(mod);
        ret = ican3_msg_newhostif(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to switch to new-style interface\n");
+               netdev_err(mod->ndev, "unable to switch to new-style interface\n");
                return ret;
        }
 
        /* default to "termination on" */
        ret = ican3_set_termination(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to enable termination\n");
+               netdev_err(mod->ndev, "unable to enable termination\n");
                return ret;
        }
 
        /* default to "bus errors enabled" */
        ret = ican3_set_buserror(mod, 1);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-error\n");
+               netdev_err(mod->ndev, "unable to set bus-error\n");
                return ret;
        }
 
        ican3_init_fast_host_interface(mod);
        ret = ican3_msg_fasthostif(mod);
        if (ret) {
-               dev_err(mod->dev, "unable to switch to fast host interface\n");
+               netdev_err(mod->ndev, "unable to switch to fast host interface\n");
                return ret;
        }
 
        ret = ican3_set_id_filter(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to set acceptance filter\n");
+               netdev_err(mod->ndev, "unable to set acceptance filter\n");
                return ret;
        }
 
@@ -1497,14 +1484,14 @@ static int ican3_open(struct net_device *ndev)
        /* open the CAN layer */
        ret = open_candev(ndev);
        if (ret) {
-               dev_err(mod->dev, "unable to start CAN layer\n");
+               netdev_err(mod->ndev, "unable to start CAN layer\n");
                return ret;
        }
 
        /* bring the bus online */
        ret = ican3_set_bus_state(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-on\n");
+               netdev_err(mod->ndev, "unable to set bus-on\n");
                close_candev(ndev);
                return ret;
        }
@@ -1528,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev)
        /* bring the bus offline, stop receiving packets */
        ret = ican3_set_bus_state(mod, false);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-off\n");
+               netdev_err(mod->ndev, "unable to set bus-off\n");
                return ret;
        }
 
@@ -1555,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        /* check that we can actually transmit */
        if (!ican3_txok(mod)) {
-               dev_err(mod->dev, "BUG: no free descriptors\n");
+               netdev_err(mod->ndev, "BUG: no free descriptors\n");
                spin_unlock_irqrestore(&mod->lock, flags);
                return NETDEV_TX_BUSY;
        }
@@ -1607,6 +1594,7 @@ static const struct net_device_ops ican3_netdev_ops = {
        .ndo_open       = ican3_open,
        .ndo_stop       = ican3_stop,
        .ndo_start_xmit = ican3_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 /*
@@ -1667,7 +1655,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode)
        /* bring the bus online */
        ret = ican3_set_bus_state(mod, true);
        if (ret) {
-               dev_err(mod->dev, "unable to set bus-on\n");
+               netdev_err(ndev, "unable to set bus-on\n");
                return ret;
        }
 
@@ -1692,7 +1680,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev,
 
        ret = wait_for_completion_timeout(&mod->buserror_comp, HZ);
        if (ret == 0) {
-               dev_info(mod->dev, "%s timed out\n", __func__);
+               netdev_info(mod->ndev, "%s timed out\n", __func__);
                return -ETIMEDOUT;
        }
 
@@ -1718,7 +1706,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev,
 
        ret = wait_for_completion_timeout(&mod->termination_comp, HZ);
        if (ret == 0) {
-               dev_info(mod->dev, "%s timed out\n", __func__);
+               netdev_info(mod->ndev, "%s timed out\n", __func__);
                return -ETIMEDOUT;
        }
 
@@ -1788,7 +1776,6 @@ static int ican3_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ndev);
        mod = netdev_priv(ndev);
        mod->ndev = ndev;
-       mod->dev = &pdev->dev;
        mod->num = pdata->modno;
        netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS);
        skb_queue_head_init(&mod->echoq);
index cdb9808d12dbc9883250ccceb5ac156be6a4c84d..28c11f81524524fe521eb0c24177fffa76323885 100644 (file)
@@ -601,10 +601,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net)
                          (bt->prop_seg - 1));
        mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK,
                           (bt->phase_seg2 - 1));
-       dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
-                mcp251x_read_reg(spi, CNF1),
-                mcp251x_read_reg(spi, CNF2),
-                mcp251x_read_reg(spi, CNF3));
+       dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n",
+               mcp251x_read_reg(spi, CNF1),
+               mcp251x_read_reg(spi, CNF2),
+               mcp251x_read_reg(spi, CNF3));
 
        return 0;
 }
@@ -672,7 +672,7 @@ static int mcp251x_hw_probe(struct spi_device *spi)
 
 static int mcp251x_power_enable(struct regulator *reg, int enable)
 {
-       if (IS_ERR(reg))
+       if (IS_ERR_OR_NULL(reg))
                return 0;
 
        if (enable)
@@ -996,6 +996,7 @@ static const struct net_device_ops mcp251x_netdev_ops = {
        .ndo_open = mcp251x_open,
        .ndo_stop = mcp251x_stop,
        .ndo_start_xmit = mcp251x_hard_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static const struct of_device_id mcp251x_of_match[] = {
@@ -1155,8 +1156,6 @@ static int mcp251x_can_probe(struct spi_device *spi)
 
        devm_can_led_init(net);
 
-       dev_info(&spi->dev, "probed\n");
-
        return ret;
 
 error_probe:
@@ -1197,9 +1196,7 @@ static int mcp251x_can_remove(struct spi_device *spi)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-
-static int mcp251x_can_suspend(struct device *dev)
+static int __maybe_unused mcp251x_can_suspend(struct device *dev)
 {
        struct spi_device *spi = to_spi_device(dev);
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1221,7 +1218,7 @@ static int mcp251x_can_suspend(struct device *dev)
                priv->after_suspend = AFTER_SUSPEND_DOWN;
        }
 
-       if (!IS_ERR(priv->power)) {
+       if (!IS_ERR_OR_NULL(priv->power)) {
                regulator_disable(priv->power);
                priv->after_suspend |= AFTER_SUSPEND_POWER;
        }
@@ -1229,7 +1226,7 @@ static int mcp251x_can_suspend(struct device *dev)
        return 0;
 }
 
-static int mcp251x_can_resume(struct device *dev)
+static int __maybe_unused mcp251x_can_resume(struct device *dev)
 {
        struct spi_device *spi = to_spi_device(dev);
        struct mcp251x_priv *priv = spi_get_drvdata(spi);
@@ -1249,7 +1246,6 @@ static int mcp251x_can_resume(struct device *dev)
        enable_irq(spi->irq);
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend,
        mcp251x_can_resume);
index b9f3faabb0f30ecbc466664ec6e5ca564fa52409..e0c9be5e2ab74676e8e3bb9fe026b145d3f4d3ab 100644 (file)
@@ -647,9 +647,10 @@ static int mscan_close(struct net_device *dev)
 }
 
 static const struct net_device_ops mscan_netdev_ops = {
-       .ndo_open               = mscan_open,
-       .ndo_stop               = mscan_close,
-       .ndo_start_xmit         = mscan_start_xmit,
+       .ndo_open       = mscan_open,
+       .ndo_stop       = mscan_close,
+       .ndo_start_xmit = mscan_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 int register_mscandev(struct net_device *dev, int mscan_clksrc)
index 6c077eb87b5e90c98b9431bd5dcb3238685ee1ef..6472562efedc921468212f8b8300b88dff6f2e95 100644 (file)
@@ -950,6 +950,7 @@ static const struct net_device_ops pch_can_netdev_ops = {
        .ndo_open               = pch_can_open,
        .ndo_stop               = pch_close,
        .ndo_start_xmit         = pch_xmit,
+       .ndo_change_mtu         = can_change_mtu,
 };
 
 static void pch_can_remove(struct pci_dev *pdev)
index ff2ba86cd4a495cdd29020f02561a1f31926ff11..4b18b87655231c3f5ee445a30dc8b85fcddb265c 100644 (file)
@@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM
          the "platform bus" (Linux abstraction for directly to the
          processor attached devices).  Which can be found on various
          boards from Phytec (http://www.phytec.de) like the PCM027,
-         PCM038.
-
-config CAN_SJA1000_OF_PLATFORM
-       tristate "Generic OF Platform Bus based SJA1000 driver"
-       depends on OF
-       ---help---
-         This driver adds support for the SJA1000 chips connected to
-         the OpenFirmware "platform bus" found on embedded systems with
-         OpenFirmware bindings, e.g. if you have a PowerPC based system
-         you may want to enable this option.
+         PCM038. It also provides the OpenFirmware "platform bus" found
+         on embedded systems with OpenFirmware bindings, e.g. if you
+         have a PowerPC based system you may want to enable this option.
 
 config CAN_EMS_PCMCIA
        tristate "EMS CPC-CARD Card"
index b3d05cbfec3668cfc8df21989adc8b6643465ae3..531d5fcc97e58bded41ac3f3022a2a84a41ba6f0 100644 (file)
@@ -5,7 +5,6 @@
 obj-$(CONFIG_CAN_SJA1000) += sja1000.o
 obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o
 obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o
-obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o
 obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o
 obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o
 obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o
index d790b874ca79ba4cb4d522a8664f24c99ea3ebb8..fd13dbf07d9c0cb3d912c99f326b6e31be965366 100644 (file)
@@ -323,6 +323,7 @@ static int ems_pci_add_card(struct pci_dev *pdev,
                        priv->cdr = EMS_PCI_CDR;
 
                        SET_NETDEV_DEV(dev, &pdev->dev);
+                       dev->dev_id = i;
 
                        if (card->version == 1)
                                /* reset int flag of pita */
index 9e535f2ef52bb03365cc6ccf6f5ac2ababc6e7dc..381de998d2f1655b955bc701add77a30fe44ac21 100644 (file)
@@ -211,6 +211,7 @@ static int ems_pcmcia_add_card(struct pcmcia_device *pdev, unsigned long base)
                priv = netdev_priv(dev);
                priv->priv = card;
                SET_NETDEV_DEV(dev, &pdev->dev);
+               dev->dev_id = i;
 
                priv->irq_flags = IRQF_SHARED;
                dev->irq = pdev->irq;
index c96eb14699d5ad8a00655d71d80c8bd7fcbcf1c9..23b8e1324e25ef9e31a78a8c7591a1c968c01c29 100644 (file)
@@ -270,6 +270,7 @@ static int kvaser_pci_add_chan(struct pci_dev *pdev, int channel,
                 priv->reg_base, board->conf_addr, dev->irq);
 
        SET_NETDEV_DEV(dev, &pdev->dev);
+       dev->dev_id = channel;
 
        /* Register SJA1000 device */
        err = register_sja1000dev(dev);
index 065ca49eb45e72c48c9d1cc5f8fbda0256fdb195..c540e3d12e3d826260dbb590e8045c92fa4efb2b 100644 (file)
@@ -642,6 +642,7 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                icr |= chan->icr_mask;
 
                SET_NETDEV_DEV(dev, &pdev->dev);
+               dev->dev_id = i;
 
                /* Create chain of SJA1000 devices */
                chan->prev_dev = pci_get_drvdata(pdev);
index f7ad754dd2aa1427380b79eabf6c661d6114ba48..dd56133cc4616180bc5841bda60dd576e3ebcd75 100644 (file)
@@ -550,6 +550,7 @@ static int pcan_add_channels(struct pcan_pccard *card)
                priv = netdev_priv(netdev);
                priv->priv = card;
                SET_NETDEV_DEV(netdev, &pdev->dev);
+               netdev->dev_id = i;
 
                priv->irq_flags = IRQF_SHARED;
                netdev->irq = pdev->irq;
index fbb61a0d901fb3c367d2d1dc15a5a524dab43b93..ec39b7cb2287b4764ffbfadffa29ed5286c5c545 100644 (file)
@@ -587,6 +587,7 @@ static int plx_pci_add_card(struct pci_dev *pdev,
                        priv->cdr = ci->cdr;
 
                        SET_NETDEV_DEV(dev, &pdev->dev);
+                       dev->dev_id = i;
 
                        /* Register SJA1000 device */
                        err = register_sja1000dev(dev);
index f17c3018b7c7ffb3f7d75785c3ddd2218b0f3f79..f31499a32d7dcf4fde4eb1a0864af4f15bfb6118 100644 (file)
@@ -106,8 +106,7 @@ static int sja1000_probe_chip(struct net_device *dev)
        struct sja1000_priv *priv = netdev_priv(dev);
 
        if (priv->reg_base && sja1000_is_absent(priv)) {
-               printk(KERN_INFO "%s: probing @0x%lX failed\n",
-                      DRV_NAME, dev->base_addr);
+               netdev_err(dev, "probing failed\n");
                return 0;
        }
        return -1;
@@ -643,9 +642,10 @@ void free_sja1000dev(struct net_device *dev)
 EXPORT_SYMBOL_GPL(free_sja1000dev);
 
 static const struct net_device_ops sja1000_netdev_ops = {
-       .ndo_open               = sja1000_open,
-       .ndo_stop               = sja1000_close,
-       .ndo_start_xmit         = sja1000_start_xmit,
+       .ndo_open       = sja1000_open,
+       .ndo_stop       = sja1000_close,
+       .ndo_start_xmit = sja1000_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 int register_sja1000dev(struct net_device *dev)
diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
deleted file mode 100644 (file)
index 2f6e245..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus
- *
- * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the 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/>.
- */
-
-/* This is a generic driver for SJA1000 chips on the OpenFirmware platform
- * bus found on embedded PowerPC systems. You need a SJA1000 CAN node
- * definition in your flattened device tree source (DTS) file similar to:
- *
- *   can@3,100 {
- *           compatible = "nxp,sja1000";
- *           reg = <3 0x100 0x80>;
- *           interrupts = <2 0>;
- *           interrupt-parent = <&mpic>;
- *           nxp,external-clock-frequency = <16000000>;
- *   };
- *
- * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further
- * information.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/can/dev.h>
-
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include "sja1000.h"
-
-#define DRV_NAME "sja1000_of_platform"
-
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
-MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus");
-MODULE_LICENSE("GPL v2");
-
-#define SJA1000_OFP_CAN_CLOCK  (16000000 / 2)
-
-#define SJA1000_OFP_OCR        OCR_TX0_PULLDOWN
-#define SJA1000_OFP_CDR        (CDR_CBP | CDR_CLK_OFF)
-
-static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg)
-{
-       return ioread8(priv->reg_base + reg);
-}
-
-static void sja1000_ofp_write_reg(const struct sja1000_priv *priv,
-                                 int reg, u8 val)
-{
-       iowrite8(val, priv->reg_base + reg);
-}
-
-static int sja1000_ofp_remove(struct platform_device *ofdev)
-{
-       struct net_device *dev = platform_get_drvdata(ofdev);
-       struct sja1000_priv *priv = netdev_priv(dev);
-       struct device_node *np = ofdev->dev.of_node;
-       struct resource res;
-
-       unregister_sja1000dev(dev);
-       free_sja1000dev(dev);
-       iounmap(priv->reg_base);
-       irq_dispose_mapping(dev->irq);
-
-       of_address_to_resource(np, 0, &res);
-       release_mem_region(res.start, resource_size(&res));
-
-       return 0;
-}
-
-static int sja1000_ofp_probe(struct platform_device *ofdev)
-{
-       struct device_node *np = ofdev->dev.of_node;
-       struct net_device *dev;
-       struct sja1000_priv *priv;
-       struct resource res;
-       u32 prop;
-       int err, irq, res_size;
-       void __iomem *base;
-
-       err = of_address_to_resource(np, 0, &res);
-       if (err) {
-               dev_err(&ofdev->dev, "invalid address\n");
-               return err;
-       }
-
-       res_size = resource_size(&res);
-
-       if (!request_mem_region(res.start, res_size, DRV_NAME)) {
-               dev_err(&ofdev->dev, "couldn't request %pR\n", &res);
-               return -EBUSY;
-       }
-
-       base = ioremap_nocache(res.start, res_size);
-       if (!base) {
-               dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res);
-               err = -ENOMEM;
-               goto exit_release_mem;
-       }
-
-       irq = irq_of_parse_and_map(np, 0);
-       if (irq == 0) {
-               dev_err(&ofdev->dev, "no irq found\n");
-               err = -ENODEV;
-               goto exit_unmap_mem;
-       }
-
-       dev = alloc_sja1000dev(0);
-       if (!dev) {
-               err = -ENOMEM;
-               goto exit_dispose_irq;
-       }
-
-       priv = netdev_priv(dev);
-
-       priv->read_reg = sja1000_ofp_read_reg;
-       priv->write_reg = sja1000_ofp_write_reg;
-
-       err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop);
-       if (!err)
-               priv->can.clock.freq = prop / 2;
-       else
-               priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */
-
-       err = of_property_read_u32(np, "nxp,tx-output-mode", &prop);
-       if (!err)
-               priv->ocr |= prop & OCR_MODE_MASK;
-       else
-               priv->ocr |= OCR_MODE_NORMAL; /* default */
-
-       err = of_property_read_u32(np, "nxp,tx-output-config", &prop);
-       if (!err)
-               priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
-       else
-               priv->ocr |= OCR_TX0_PULLDOWN; /* default */
-
-       err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop);
-       if (!err && prop) {
-               u32 divider = priv->can.clock.freq * 2 / prop;
-
-               if (divider > 1)
-                       priv->cdr |= divider / 2 - 1;
-               else
-                       priv->cdr |= CDR_CLKOUT_MASK;
-       } else {
-               priv->cdr |= CDR_CLK_OFF; /* default */
-       }
-
-       if (!of_property_read_bool(np, "nxp,no-comparator-bypass"))
-               priv->cdr |= CDR_CBP; /* default */
-
-       priv->irq_flags = IRQF_SHARED;
-       priv->reg_base = base;
-
-       dev->irq = irq;
-
-       dev_info(&ofdev->dev,
-                "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n",
-                priv->reg_base, dev->irq, priv->can.clock.freq,
-                priv->ocr, priv->cdr);
-
-       platform_set_drvdata(ofdev, dev);
-       SET_NETDEV_DEV(dev, &ofdev->dev);
-
-       err = register_sja1000dev(dev);
-       if (err) {
-               dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
-                       DRV_NAME, err);
-               goto exit_free_sja1000;
-       }
-
-       return 0;
-
-exit_free_sja1000:
-       free_sja1000dev(dev);
-exit_dispose_irq:
-       irq_dispose_mapping(irq);
-exit_unmap_mem:
-       iounmap(base);
-exit_release_mem:
-       release_mem_region(res.start, res_size);
-
-       return err;
-}
-
-static struct of_device_id sja1000_ofp_table[] = {
-       {.compatible = "nxp,sja1000"},
-       {},
-};
-MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
-
-static struct platform_driver sja1000_ofp_driver = {
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = DRV_NAME,
-               .of_match_table = sja1000_ofp_table,
-       },
-       .probe = sja1000_ofp_probe,
-       .remove = sja1000_ofp_remove,
-};
-
-module_platform_driver(sja1000_ofp_driver);
index 943df645b45905d26df84052184c53e2085a414f..95a844a7ee7b0befa46e7d6dd9704c9ad99fac8b 100644 (file)
 #include <linux/can/dev.h>
 #include <linux/can/platform/sja1000.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
 
 #include "sja1000.h"
 
 #define DRV_NAME "sja1000_platform"
+#define SP_CAN_CLOCK  (16000000 / 2)
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
 MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus");
 MODULE_ALIAS("platform:" DRV_NAME);
 MODULE_LICENSE("GPL v2");
@@ -66,59 +70,16 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val)
        iowrite8(val, priv->reg_base + reg * 4);
 }
 
-static int sp_probe(struct platform_device *pdev)
+static void sp_populate(struct sja1000_priv *priv,
+                       struct sja1000_platform_data *pdata,
+                       unsigned long resource_mem_flags)
 {
-       int err;
-       void __iomem *addr;
-       struct net_device *dev;
-       struct sja1000_priv *priv;
-       struct resource *res_mem, *res_irq;
-       struct sja1000_platform_data *pdata;
-
-       pdata = dev_get_platdata(&pdev->dev);
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platform data provided!\n");
-               err = -ENODEV;
-               goto exit;
-       }
-
-       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res_mem || !res_irq) {
-               err = -ENODEV;
-               goto exit;
-       }
-
-       if (!request_mem_region(res_mem->start, resource_size(res_mem),
-                               DRV_NAME)) {
-               err = -EBUSY;
-               goto exit;
-       }
-
-       addr = ioremap_nocache(res_mem->start, resource_size(res_mem));
-       if (!addr) {
-               err = -ENOMEM;
-               goto exit_release;
-       }
-
-       dev = alloc_sja1000dev(0);
-       if (!dev) {
-               err = -ENOMEM;
-               goto exit_iounmap;
-       }
-       priv = netdev_priv(dev);
-
-       dev->irq = res_irq->start;
-       priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
-       if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
-               priv->irq_flags |= IRQF_SHARED;
-       priv->reg_base = addr;
        /* The CAN clock frequency is half the oscillator clock frequency */
        priv->can.clock.freq = pdata->osc_freq / 2;
        priv->ocr = pdata->ocr;
        priv->cdr = pdata->cdr;
 
-       switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) {
+       switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) {
        case IORESOURCE_MEM_32BIT:
                priv->read_reg = sp_read_reg32;
                priv->write_reg = sp_write_reg32;
@@ -133,6 +94,124 @@ static int sp_probe(struct platform_device *pdev)
                priv->write_reg = sp_write_reg8;
                break;
        }
+}
+
+static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of)
+{
+       int err;
+       u32 prop;
+
+       err = of_property_read_u32(of, "reg-io-width", &prop);
+       if (err)
+               prop = 1; /* 8 bit is default */
+
+       switch (prop) {
+       case 4:
+               priv->read_reg = sp_read_reg32;
+               priv->write_reg = sp_write_reg32;
+               break;
+       case 2:
+               priv->read_reg = sp_read_reg16;
+               priv->write_reg = sp_write_reg16;
+               break;
+       case 1: /* fallthrough */
+       default:
+               priv->read_reg = sp_read_reg8;
+               priv->write_reg = sp_write_reg8;
+       }
+
+       err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop);
+       if (!err)
+               priv->can.clock.freq = prop / 2;
+       else
+               priv->can.clock.freq = SP_CAN_CLOCK; /* default */
+
+       err = of_property_read_u32(of, "nxp,tx-output-mode", &prop);
+       if (!err)
+               priv->ocr |= prop & OCR_MODE_MASK;
+       else
+               priv->ocr |= OCR_MODE_NORMAL; /* default */
+
+       err = of_property_read_u32(of, "nxp,tx-output-config", &prop);
+       if (!err)
+               priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK;
+       else
+               priv->ocr |= OCR_TX0_PULLDOWN; /* default */
+
+       err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop);
+       if (!err && prop) {
+               u32 divider = priv->can.clock.freq * 2 / prop;
+
+               if (divider > 1)
+                       priv->cdr |= divider / 2 - 1;
+               else
+                       priv->cdr |= CDR_CLKOUT_MASK;
+       } else {
+               priv->cdr |= CDR_CLK_OFF; /* default */
+       }
+
+       if (!of_property_read_bool(of, "nxp,no-comparator-bypass"))
+               priv->cdr |= CDR_CBP; /* default */
+}
+
+static int sp_probe(struct platform_device *pdev)
+{
+       int err, irq = 0;
+       void __iomem *addr;
+       struct net_device *dev;
+       struct sja1000_priv *priv;
+       struct resource *res_mem, *res_irq = NULL;
+       struct sja1000_platform_data *pdata;
+       struct device_node *of = pdev->dev.of_node;
+
+       pdata = dev_get_platdata(&pdev->dev);
+       if (!pdata && !of) {
+               dev_err(&pdev->dev, "No platform data provided!\n");
+               return -ENODEV;
+       }
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mem)
+               return -ENODEV;
+
+       if (!devm_request_mem_region(&pdev->dev, res_mem->start,
+                                    resource_size(res_mem), DRV_NAME))
+               return -EBUSY;
+
+       addr = devm_ioremap_nocache(&pdev->dev, res_mem->start,
+                                   resource_size(res_mem));
+       if (!addr)
+               return -ENOMEM;
+
+       if (of)
+               irq = irq_of_parse_and_map(of, 0);
+       else
+               res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+       if (!irq && !res_irq)
+               return -ENODEV;
+
+       dev = alloc_sja1000dev(0);
+       if (!dev)
+               return -ENOMEM;
+       priv = netdev_priv(dev);
+
+       if (res_irq) {
+               irq = res_irq->start;
+               priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
+               if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
+                       priv->irq_flags |= IRQF_SHARED;
+       } else {
+               priv->irq_flags = IRQF_SHARED;
+       }
+
+       dev->irq = irq;
+       priv->reg_base = addr;
+
+       if (of)
+               sp_populate_of(priv, of);
+       else
+               sp_populate(priv, pdata, res_mem->flags);
 
        platform_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
@@ -150,39 +229,32 @@ static int sp_probe(struct platform_device *pdev)
 
  exit_free:
        free_sja1000dev(dev);
- exit_iounmap:
-       iounmap(addr);
- exit_release:
-       release_mem_region(res_mem->start, resource_size(res_mem));
- exit:
        return err;
 }
 
 static int sp_remove(struct platform_device *pdev)
 {
        struct net_device *dev = platform_get_drvdata(pdev);
-       struct sja1000_priv *priv = netdev_priv(dev);
-       struct resource *res;
 
        unregister_sja1000dev(dev);
-
-       if (priv->reg_base)
-               iounmap(priv->reg_base);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
        free_sja1000dev(dev);
 
        return 0;
 }
 
+static 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,
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
+               .of_match_table = sp_of_table,
        },
 };
 
index 3fcdae266377a8141546f239ff805160d6cadbb9..f5b16e0e3a125f4e38a93408e92b8218808339af 100644 (file)
@@ -411,10 +411,16 @@ static void slc_free_netdev(struct net_device *dev)
        slcan_devs[i] = NULL;
 }
 
+static int slcan_change_mtu(struct net_device *dev, int new_mtu)
+{
+       return -EINVAL;
+}
+
 static const struct net_device_ops slc_netdev_ops = {
        .ndo_open               = slc_open,
        .ndo_stop               = slc_close,
        .ndo_start_xmit         = slc_xmit,
+       .ndo_change_mtu         = slcan_change_mtu,
 };
 
 static void slc_setup(struct net_device *dev)
index 9ea0dcde94ce0fe948fd3f059a9084516c8beaee..7d8c8f3672dd993119a28f478e5cc43514aa131c 100644 (file)
@@ -628,6 +628,7 @@ static const struct net_device_ops softing_netdev_ops = {
        .ndo_open = softing_netdev_open,
        .ndo_stop = softing_netdev_stop,
        .ndo_start_xmit = softing_netdev_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static const struct can_bittiming_const softing_btr_const = {
@@ -832,6 +833,7 @@ static int softing_pdev_probe(struct platform_device *pdev)
                        ret = -ENOMEM;
                        goto netdev_failed;
                }
+               netdev->dev_id = j;
                priv = netdev_priv(card->net[j]);
                priv->index = j;
                ret = softing_netdev_register(netdev);
index 2c62fe6c8fa967382796e99bbe1b85c37cd12916..258b9c4856ec6c1726c0e78a64becf19ae8c40d9 100644 (file)
@@ -871,6 +871,7 @@ static const struct net_device_ops ti_hecc_netdev_ops = {
        .ndo_open               = ti_hecc_open,
        .ndo_stop               = ti_hecc_close,
        .ndo_start_xmit         = ti_hecc_xmit,
+       .ndo_change_mtu         = can_change_mtu,
 };
 
 static int ti_hecc_probe(struct platform_device *pdev)
index 52c42fd49510014f909b63efefa9ba1891dc8e11..00f2534dde736f1dd8cda9b016bd6a78f79eeab0 100644 (file)
@@ -883,6 +883,7 @@ static const struct net_device_ops ems_usb_netdev_ops = {
        .ndo_open = ems_usb_open,
        .ndo_stop = ems_usb_close,
        .ndo_start_xmit = ems_usb_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static const struct can_bittiming_const ems_usb_bittiming_const = {
index 7fbe85935f1d1071e7efbd917797a3da19938a70..b7c9e8b11460a3d6bd0e4fe7836f0e07e73eb586 100644 (file)
@@ -888,6 +888,7 @@ static const struct net_device_ops esd_usb2_netdev_ops = {
        .ndo_open = esd_usb2_open,
        .ndo_stop = esd_usb2_close,
        .ndo_start_xmit = esd_usb2_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static const struct can_bittiming_const esd_usb2_bittiming_const = {
@@ -1024,6 +1025,7 @@ static int esd_usb2_probe_one_net(struct usb_interface *intf, int index)
        netdev->netdev_ops = &esd_usb2_netdev_ops;
 
        SET_NETDEV_DEV(netdev, &intf->dev);
+       netdev->dev_id = index;
 
        err = register_candev(netdev);
        if (err) {
index 6c859bba8b650852663a6ac538a0744a44135296..4ca46edc061d761169a85fc58937dee449a4776f 100644 (file)
@@ -473,6 +473,8 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
                return err;
 
        dev->nchannels = msg.u.cardinfo.nchannels;
+       if (dev->nchannels > MAX_NET_DEVICES)
+               return -EINVAL;
 
        return 0;
 }
@@ -1386,6 +1388,7 @@ static const struct net_device_ops kvaser_usb_netdev_ops = {
        .ndo_open = kvaser_usb_open,
        .ndo_stop = kvaser_usb_close,
        .ndo_start_xmit = kvaser_usb_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static const struct can_bittiming_const kvaser_usb_bittiming_const = {
@@ -1527,6 +1530,7 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
        netdev->netdev_ops = &kvaser_usb_netdev_ops;
 
        SET_NETDEV_DEV(netdev, &intf->dev);
+       netdev->dev_id = channel;
 
        dev->nets[channel] = priv;
 
index 0b7a4c3b01a2976176878607bd457a9ea282e21e..644e6ab8a489b162ba399a01faa10cc5b09cf3bb 100644 (file)
@@ -702,6 +702,7 @@ static const struct net_device_ops peak_usb_netdev_ops = {
        .ndo_open = peak_usb_ndo_open,
        .ndo_stop = peak_usb_ndo_stop,
        .ndo_start_xmit = peak_usb_ndo_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 /*
@@ -769,6 +770,7 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
        usb_set_intfdata(intf, dev);
 
        SET_NETDEV_DEV(netdev, &intf->dev);
+       netdev->dev_id = ctrl_idx;
 
        err = register_candev(netdev);
        if (err) {
index a0fa1fd5092ba8243dcba8c6abfa67eac0f60694..cde263459932aff184d919b1881de5c9885831fa 100644 (file)
@@ -887,6 +887,7 @@ static const struct net_device_ops usb_8dev_netdev_ops = {
        .ndo_open = usb_8dev_open,
        .ndo_stop = usb_8dev_close,
        .ndo_start_xmit = usb_8dev_start_xmit,
+       .ndo_change_mtu = can_change_mtu,
 };
 
 static const struct can_bittiming_const usb_8dev_bittiming_const = {
index 0a2a5ee79a177f1d78d9e4b3deb447f82be62757..4e94057ef5cf55df4600496d38b5fce433f851b4 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/if_ether.h>
 #include <linux/can.h>
 #include <linux/can/dev.h>
+#include <linux/can/skb.h>
 #include <linux/slab.h>
 #include <net/rtnetlink.h>
 
@@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
                        stats->rx_packets++;
                        stats->rx_bytes += cfd->len;
                }
-               kfree_skb(skb);
+               consume_skb(skb);
                return NETDEV_TX_OK;
        }
 
        /* perform standard echo handling for CAN network interfaces */
 
        if (loop) {
-               struct sock *srcsk = skb->sk;
 
-               skb = skb_share_check(skb, GFP_ATOMIC);
+               skb = can_create_echo_skb(skb);
                if (!skb)
                        return NETDEV_TX_OK;
 
                /* receive with packet counting */
-               skb->sk = srcsk;
                vcan_rx(skb, dev);
        } else {
                /* no looped packets => no counting */
-               kfree_skb(skb);
+               consume_skb(skb);
        }
        return NETDEV_TX_OK;
 }
index bd8f84b0b894ebfe616a85b365598347d648200f..0932ffbf381b5b5c877b9988318912fcea930473 100644 (file)
@@ -63,10 +63,10 @@ static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
 
                dstats = per_cpu_ptr(dev->dstats, i);
                do {
-                       start = u64_stats_fetch_begin_bh(&dstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&dstats->syncp);
                        tbytes = dstats->tx_bytes;
                        tpackets = dstats->tx_packets;
-               } while (u64_stats_fetch_retry_bh(&dstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
                stats->tx_bytes += tbytes;
                stats->tx_packets += tpackets;
        }
@@ -88,16 +88,10 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
 
 static int dummy_dev_init(struct net_device *dev)
 {
-       int i;
-       dev->dstats = alloc_percpu(struct pcpu_dstats);
+       dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
        if (!dev->dstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_dstats *dstats;
-               dstats = per_cpu_ptr(dev->dstats, i);
-               u64_stats_init(&dstats->syncp);
-       }
        return 0;
 }
 
index c53384d41c96a974df073a383a2ea15b5373a3da..35df0b9e6848b0f1bd964f7b93ed2f18988c6b08 100644 (file)
@@ -749,7 +749,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        spin_unlock_irqrestore(&lp->lock, flags);
 
-       dev_kfree_skb (skb);
+       dev_consume_skb_any (skb);
 
        /* Clear the Tx status stack. */
        {
index 5992860a39c97747e64befccd939f2e1f99e78f4..063557e037f21b8b43fa3d1dfe64a19c870d4789 100644 (file)
@@ -1,23 +1,24 @@
-/*======================================================================
-
-    A PCMCIA ethernet driver for the 3com 3c589 card.
-
-    Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
-
-    3c589_cs.c 1.162 2001/10/13 00:08:50
-
-    The network driver code is based on Donald Becker's 3c589 code:
-
-    Written 1994 by Donald Becker.
-    Copyright 1993 United States Government as represented by the
-    Director, National Security Agency.  This software may be used and
-    distributed according to the terms of the GNU General Public License,
-    incorporated herein by reference.
-    Donald Becker may be reached at becker@scyld.com
-
-    Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
-
-======================================================================*/
+/* ======================================================================
+ *
+ * A PCMCIA ethernet driver for the 3com 3c589 card.
+ *
+ * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
+ *
+ * 3c589_cs.c 1.162 2001/10/13 00:08:50
+ *
+ * The network driver code is based on Donald Becker's 3c589 code:
+ *
+ * Written 1994 by Donald Becker.
+ * Copyright 1993 United States Government as represented by the
+ * Director, National Security Agency.  This software may be used and
+ * distributed according to the terms of the GNU General Public License,
+ * incorporated herein by reference.
+ * Donald Becker may be reached at becker@scyld.com
+ *
+ * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ * ======================================================================
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/ioport.h>
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
 
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
 
-#include <asm/uaccess.h>
-#include <asm/io.h>
 
 /* To minimize the size of the driver source I only define operating
-   constants if they are used several times.  You'll need the manual
-   if you want to understand driver details. */
+ * constants if they are used several times. You'll need the manual
+ * if you want to understand driver details.
+ */
+
 /* Offsets from base I/O address. */
 #define EL3_DATA       0x00
 #define EL3_TIMER      0x0a
@@ -65,7 +68,9 @@
 #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
 
 /* The top five bits written to EL3_CMD are a command, the lower
-   11 bits are the parameter, if applicable. */
+ * 11 bits are the parameter, if applicable.
+ */
+
 enum c509cmd {
        TotalReset      = 0<<11,
        SelectWindow    = 1<<11,
@@ -190,138 +195,142 @@ static const struct net_device_ops el3_netdev_ops = {
 
 static int tc589_probe(struct pcmcia_device *link)
 {
-    struct el3_private *lp;
-    struct net_device *dev;
+       struct el3_private *lp;
+       struct net_device *dev;
 
-    dev_dbg(&link->dev, "3c589_attach()\n");
+       dev_dbg(&link->dev, "3c589_attach()\n");
 
-    /* Create new ethernet device */
-    dev = alloc_etherdev(sizeof(struct el3_private));
-    if (!dev)
-        return -ENOMEM;
-    lp = netdev_priv(dev);
-    link->priv = dev;
-    lp->p_dev = link;
+       /* Create new ethernet device */
+       dev = alloc_etherdev(sizeof(struct el3_private));
+       if (!dev)
+               return -ENOMEM;
+       lp = netdev_priv(dev);
+       link->priv = dev;
+       lp->p_dev = link;
 
-    spin_lock_init(&lp->lock);
-    link->resource[0]->end = 16;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
+       spin_lock_init(&lp->lock);
+       link->resource[0]->end = 16;
+       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
 
-    link->config_flags |= CONF_ENABLE_IRQ;
-    link->config_index = 1;
+       link->config_flags |= CONF_ENABLE_IRQ;
+       link->config_index = 1;
 
-    dev->netdev_ops = &el3_netdev_ops;
-    dev->watchdog_timeo = TX_TIMEOUT;
+       dev->netdev_ops = &el3_netdev_ops;
+       dev->watchdog_timeo = TX_TIMEOUT;
 
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+       SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    return tc589_config(link);
+       return tc589_config(link);
 }
 
 static void tc589_detach(struct pcmcia_device *link)
 {
-    struct net_device *dev = link->priv;
+       struct net_device *dev = link->priv;
 
-    dev_dbg(&link->dev, "3c589_detach\n");
+       dev_dbg(&link->dev, "3c589_detach\n");
 
-    unregister_netdev(dev);
+       unregister_netdev(dev);
 
-    tc589_release(link);
+       tc589_release(link);
 
-    free_netdev(dev);
+       free_netdev(dev);
 } /* tc589_detach */
 
 static int tc589_config(struct pcmcia_device *link)
 {
-    struct net_device *dev = link->priv;
-    __be16 *phys_addr;
-    int ret, i, j, multi = 0, fifo;
-    unsigned int ioaddr;
-    static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
-    u8 *buf;
-    size_t len;
-
-    dev_dbg(&link->dev, "3c589_config\n");
-
-    phys_addr = (__be16 *)dev->dev_addr;
-    /* Is this a 3c562? */
-    if (link->manf_id != MANFID_3COM)
-           dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
-    multi = (link->card_id == PRODID_3COM_3C562);
-
-    link->io_lines = 16;
-
-    /* For the 3c562, the base address must be xx00-xx7f */
-    for (i = j = 0; j < 0x400; j += 0x10) {
-       if (multi && (j & 0x80)) continue;
-       link->resource[0]->start = j ^ 0x300;
-       i = pcmcia_request_io(link);
-       if (i == 0)
-               break;
-    }
-    if (i != 0)
-       goto failed;
-
-    ret = pcmcia_request_irq(link, el3_interrupt);
-    if (ret)
-           goto failed;
-
-    ret = pcmcia_enable_device(link);
-    if (ret)
-           goto failed;
-
-    dev->irq = link->irq;
-    dev->base_addr = link->resource[0]->start;
-    ioaddr = dev->base_addr;
-    EL3WINDOW(0);
-
-    /* The 3c589 has an extra EEPROM for configuration info, including
-       the hardware address.  The 3c562 puts the address in the CIS. */
-    len = pcmcia_get_tuple(link, 0x88, &buf);
-    if (buf && len >= 6) {
-           for (i = 0; i < 3; i++)
-                   phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
-           kfree(buf);
-    } else {
-       kfree(buf); /* 0 < len < 6 */
-       for (i = 0; i < 3; i++)
-           phys_addr[i] = htons(read_eeprom(ioaddr, i));
-       if (phys_addr[0] == htons(0x6060)) {
-           dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
-                   dev->base_addr, dev->base_addr+15);
-           goto failed;
+       struct net_device *dev = link->priv;
+       __be16 *phys_addr;
+       int ret, i, j, multi = 0, fifo;
+       unsigned int ioaddr;
+       static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+       u8 *buf;
+       size_t len;
+
+       dev_dbg(&link->dev, "3c589_config\n");
+
+       phys_addr = (__be16 *)dev->dev_addr;
+       /* Is this a 3c562? */
+       if (link->manf_id != MANFID_3COM)
+               dev_info(&link->dev, "hmmm, is this really a 3Com card??\n");
+       multi = (link->card_id == PRODID_3COM_3C562);
+
+       link->io_lines = 16;
+
+       /* For the 3c562, the base address must be xx00-xx7f */
+       for (i = j = 0; j < 0x400; j += 0x10) {
+               if (multi && (j & 0x80))
+                       continue;
+               link->resource[0]->start = j ^ 0x300;
+               i = pcmcia_request_io(link);
+               if (i == 0)
+                       break;
        }
-    }
-
-    /* The address and resource configuration register aren't loaded from
-       the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
-    outw(0x3f00, ioaddr + 8);
-    fifo = inl(ioaddr);
-
-    /* The if_port symbol can be set when the module is loaded */
-    if ((if_port >= 0) && (if_port <= 3))
-       dev->if_port = if_port;
-    else
-       dev_err(&link->dev, "invalid if_port requested\n");
-
-    SET_NETDEV_DEV(dev, &link->dev);
-
-    if (register_netdev(dev) != 0) {
-           dev_err(&link->dev, "register_netdev() failed\n");
-       goto failed;
-    }
-
-    netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
-               (multi ? "562" : "589"), dev->base_addr, dev->irq,
-               dev->dev_addr);
-    netdev_info(dev, "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
-               (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
-               if_names[dev->if_port]);
-    return 0;
+       if (i != 0)
+               goto failed;
+
+       ret = pcmcia_request_irq(link, el3_interrupt);
+       if (ret)
+               goto failed;
+
+       ret = pcmcia_enable_device(link);
+       if (ret)
+               goto failed;
+
+       dev->irq = link->irq;
+       dev->base_addr = link->resource[0]->start;
+       ioaddr = dev->base_addr;
+       EL3WINDOW(0);
+
+       /* The 3c589 has an extra EEPROM for configuration info, including
+        * the hardware address.  The 3c562 puts the address in the CIS.
+        */
+       len = pcmcia_get_tuple(link, 0x88, &buf);
+       if (buf && len >= 6) {
+               for (i = 0; i < 3; i++)
+                       phys_addr[i] = htons(le16_to_cpu(buf[i*2]));
+               kfree(buf);
+       } else {
+               kfree(buf); /* 0 < len < 6 */
+               for (i = 0; i < 3; i++)
+                       phys_addr[i] = htons(read_eeprom(ioaddr, i));
+               if (phys_addr[0] == htons(0x6060)) {
+                       dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n",
+                                       dev->base_addr, dev->base_addr+15);
+                       goto failed;
+               }
+       }
+
+       /* The address and resource configuration register aren't loaded from
+        * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version.
+        */
+
+       outw(0x3f00, ioaddr + 8);
+       fifo = inl(ioaddr);
+
+       /* The if_port symbol can be set when the module is loaded */
+       if ((if_port >= 0) && (if_port <= 3))
+               dev->if_port = if_port;
+       else
+               dev_err(&link->dev, "invalid if_port requested\n");
+
+       SET_NETDEV_DEV(dev, &link->dev);
+
+       if (register_netdev(dev) != 0) {
+               dev_err(&link->dev, "register_netdev() failed\n");
+               goto failed;
+       }
+
+       netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n",
+                       (multi ? "562" : "589"), dev->base_addr, dev->irq,
+                       dev->dev_addr);
+       netdev_info(dev, "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
+                       (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
+                       if_names[dev->if_port]);
+       return 0;
 
 failed:
-    tc589_release(link);
-    return -ENODEV;
+       tc589_release(link);
+       return -ENODEV;
 } /* tc589_config */
 
 static void tc589_release(struct pcmcia_device *link)
@@ -353,113 +362,120 @@ static int tc589_resume(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-/*
-  Use this for commands that may take time to finish
-*/
+/* Use this for commands that may take time to finish */
+
 static void tc589_wait_for_completion(struct net_device *dev, int cmd)
 {
-    int i = 100;
-    outw(cmd, dev->base_addr + EL3_CMD);
-    while (--i > 0)
-       if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
-    if (i == 0)
-       netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
+       int i = 100;
+       outw(cmd, dev->base_addr + EL3_CMD);
+       while (--i > 0)
+               if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000))
+                       break;
+       if (i == 0)
+               netdev_warn(dev, "command 0x%04x did not complete!\n", cmd);
 }
 
-/*
 Read a word from the EEPROM using the regular EEPROM access register.
-  Assume that we are in register window zero.
-*/
+/* Read a word from the EEPROM using the regular EEPROM access register.
* Assume that we are in register window zero.
+ */
+
 static u16 read_eeprom(unsigned int ioaddr, int index)
 {
-    int i;
-    outw(EEPROM_READ + index, ioaddr + 10);
-    /* Reading the eeprom takes 162 us */
-    for (i = 1620; i >= 0; i--)
-       if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
-           break;
-    return inw(ioaddr + 12);
+       int i;
+       outw(EEPROM_READ + index, ioaddr + 10);
+       /* Reading the eeprom takes 162 us */
+       for (i = 1620; i >= 0; i--)
+               if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
+                       break;
+       return inw(ioaddr + 12);
 }
 
-/*
-  Set transceiver type, perhaps to something other than what the user
-  specified in dev->if_port.
-*/
+/* Set transceiver type, perhaps to something other than what the user
+ * specified in dev->if_port.
+ */
+
 static void tc589_set_xcvr(struct net_device *dev, int if_port)
 {
-    struct el3_private *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-
-    EL3WINDOW(0);
-    switch (if_port) {
-    case 0: case 1: outw(0, ioaddr + 6); break;
-    case 2: outw(3<<14, ioaddr + 6); break;
-    case 3: outw(1<<14, ioaddr + 6); break;
-    }
-    /* On PCMCIA, this just turns on the LED */
-    outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
-    /* 10baseT interface, enable link beat and jabber check. */
-    EL3WINDOW(4);
-    outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
-    EL3WINDOW(1);
-    if (if_port == 2)
-       lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
-    else
-       lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
+       struct el3_private *lp = netdev_priv(dev);
+       unsigned int ioaddr = dev->base_addr;
+
+       EL3WINDOW(0);
+       switch (if_port) {
+       case 0:
+       case 1:
+               outw(0, ioaddr + 6);
+               break;
+       case 2:
+               outw(3<<14, ioaddr + 6);
+               break;
+       case 3:
+               outw(1<<14, ioaddr + 6);
+               break;
+       }
+       /* On PCMCIA, this just turns on the LED */
+       outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+       /* 10baseT interface, enable link beat and jabber check. */
+       EL3WINDOW(4);
+       outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
+       EL3WINDOW(1);
+       if (if_port == 2)
+               lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
+       else
+               lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
 }
 
 static void dump_status(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-    EL3WINDOW(1);
-    netdev_info(dev, "  irq status %04x, rx status %04x, tx status %02x  tx free %04x\n",
-               inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
-               inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
-    EL3WINDOW(4);
-    netdev_info(dev, "  diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
-               inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
-               inw(ioaddr+0x0a));
-    EL3WINDOW(1);
+       unsigned int ioaddr = dev->base_addr;
+       EL3WINDOW(1);
+       netdev_info(dev, "  irq status %04x, rx status %04x, tx status %02x  tx free %04x\n",
+                       inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS),
+                       inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE));
+       EL3WINDOW(4);
+       netdev_info(dev, "  diagnostics: fifo %04x net %04x ethernet %04x media %04x\n",
+                       inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08),
+                       inw(ioaddr+0x0a));
+       EL3WINDOW(1);
 }
 
 /* Reset and restore all of the 3c589 registers. */
 static void tc589_reset(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-    int i;
-
-    EL3WINDOW(0);
-    outw(0x0001, ioaddr + 4);                  /* Activate board. */
-    outw(0x3f00, ioaddr + 8);                  /* Set the IRQ line. */
-
-    /* Set the station address in window 2. */
-    EL3WINDOW(2);
-    for (i = 0; i < 6; i++)
-       outb(dev->dev_addr[i], ioaddr + i);
-
-    tc589_set_xcvr(dev, dev->if_port);
-
-    /* Switch to the stats window, and clear all stats by reading. */
-    outw(StatsDisable, ioaddr + EL3_CMD);
-    EL3WINDOW(6);
-    for (i = 0; i < 9; i++)
-       inb(ioaddr+i);
-    inw(ioaddr + 10);
-    inw(ioaddr + 12);
-
-    /* Switch to register set 1 for normal use. */
-    EL3WINDOW(1);
-
-    set_rx_mode(dev);
-    outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
-    outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
-    outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
-    /* Allow status bits to be seen. */
-    outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
-    /* Ack all pending events, and set active indicator mask. */
-    outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+       unsigned int ioaddr = dev->base_addr;
+       int i;
+
+       EL3WINDOW(0);
+       outw(0x0001, ioaddr + 4);                       /* Activate board. */
+       outw(0x3f00, ioaddr + 8);                       /* Set the IRQ line. */
+
+       /* Set the station address in window 2. */
+       EL3WINDOW(2);
+       for (i = 0; i < 6; i++)
+               outb(dev->dev_addr[i], ioaddr + i);
+
+       tc589_set_xcvr(dev, dev->if_port);
+
+       /* Switch to the stats window, and clear all stats by reading. */
+       outw(StatsDisable, ioaddr + EL3_CMD);
+       EL3WINDOW(6);
+       for (i = 0; i < 9; i++)
+               inb(ioaddr+i);
+       inw(ioaddr + 10);
+       inw(ioaddr + 12);
+
+       /* Switch to register set 1 for normal use. */
+       EL3WINDOW(1);
+
+       set_rx_mode(dev);
+       outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+       outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+       outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+       /* Allow status bits to be seen. */
+       outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+       /* Ack all pending events, and set active indicator mask. */
+       outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
         ioaddr + EL3_CMD);
-    outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+       outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
         | AdapterFailure, ioaddr + EL3_CMD);
 }
 
@@ -478,381 +494,406 @@ static const struct ethtool_ops netdev_ethtool_ops = {
 
 static int el3_config(struct net_device *dev, struct ifmap *map)
 {
-    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
-       if (map->port <= 3) {
-           dev->if_port = map->port;
-           netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
-           tc589_set_xcvr(dev, dev->if_port);
-       } else
-           return -EINVAL;
-    }
-    return 0;
+       if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+               if (map->port <= 3) {
+                       dev->if_port = map->port;
+                       netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]);
+                       tc589_set_xcvr(dev, dev->if_port);
+               } else {
+                       return -EINVAL;
+               }
+       }
+       return 0;
 }
 
 static int el3_open(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
+       struct el3_private *lp = netdev_priv(dev);
+       struct pcmcia_device *link = lp->p_dev;
 
-    if (!pcmcia_dev_present(link))
-       return -ENODEV;
+       if (!pcmcia_dev_present(link))
+               return -ENODEV;
 
-    link->open++;
-    netif_start_queue(dev);
+       link->open++;
+       netif_start_queue(dev);
 
-    tc589_reset(dev);
-    init_timer(&lp->media);
-    lp->media.function = media_check;
-    lp->media.data = (unsigned long) dev;
-    lp->media.expires = jiffies + HZ;
-    add_timer(&lp->media);
+       tc589_reset(dev);
+       init_timer(&lp->media);
+       lp->media.function = media_check;
+       lp->media.data = (unsigned long) dev;
+       lp->media.expires = jiffies + HZ;
+       add_timer(&lp->media);
 
-    dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
+       dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
          dev->name, inw(dev->base_addr + EL3_STATUS));
 
-    return 0;
+       return 0;
 }
 
 static void el3_tx_timeout(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-
-    netdev_warn(dev, "Transmit timed out!\n");
-    dump_status(dev);
-    dev->stats.tx_errors++;
-    dev->trans_start = jiffies; /* prevent tx timeout */
-    /* Issue TX_RESET and TX_START commands. */
-    tc589_wait_for_completion(dev, TxReset);
-    outw(TxEnable, ioaddr + EL3_CMD);
-    netif_wake_queue(dev);
+       unsigned int ioaddr = dev->base_addr;
+
+       netdev_warn(dev, "Transmit timed out!\n");
+       dump_status(dev);
+       dev->stats.tx_errors++;
+       dev->trans_start = jiffies; /* prevent tx timeout */
+       /* Issue TX_RESET and TX_START commands. */
+       tc589_wait_for_completion(dev, TxReset);
+       outw(TxEnable, ioaddr + EL3_CMD);
+       netif_wake_queue(dev);
 }
 
 static void pop_tx_status(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-    int i;
-
-    /* Clear the Tx status stack. */
-    for (i = 32; i > 0; i--) {
-       u_char tx_status = inb(ioaddr + TX_STATUS);
-       if (!(tx_status & 0x84)) break;
-       /* reset transmitter on jabber error or underrun */
-       if (tx_status & 0x30)
-               tc589_wait_for_completion(dev, TxReset);
-       if (tx_status & 0x38) {
-               netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
-               outw(TxEnable, ioaddr + EL3_CMD);
-               dev->stats.tx_aborted_errors++;
+       unsigned int ioaddr = dev->base_addr;
+       int i;
+
+       /* Clear the Tx status stack. */
+       for (i = 32; i > 0; i--) {
+               u_char tx_status = inb(ioaddr + TX_STATUS);
+               if (!(tx_status & 0x84))
+                       break;
+               /* reset transmitter on jabber error or underrun */
+               if (tx_status & 0x30)
+                       tc589_wait_for_completion(dev, TxReset);
+               if (tx_status & 0x38) {
+                       netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status);
+                       outw(TxEnable, ioaddr + EL3_CMD);
+                       dev->stats.tx_aborted_errors++;
+               }
+               outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
        }
-       outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
-    }
 }
 
 static netdev_tx_t el3_start_xmit(struct sk_buff *skb,
                                        struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-    struct el3_private *priv = netdev_priv(dev);
-    unsigned long flags;
+       unsigned int ioaddr = dev->base_addr;
+       struct el3_private *priv = netdev_priv(dev);
+       unsigned long flags;
 
-    netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
+       netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n",
               (long)skb->len, inw(ioaddr + EL3_STATUS));
 
-    spin_lock_irqsave(&priv->lock, flags);
+       spin_lock_irqsave(&priv->lock, flags);
 
-    dev->stats.tx_bytes += skb->len;
+       dev->stats.tx_bytes += skb->len;
 
-    /* Put out the doubleword header... */
-    outw(skb->len, ioaddr + TX_FIFO);
-    outw(0x00, ioaddr + TX_FIFO);
-    /* ... and the packet rounded to a doubleword. */
-    outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+       /* Put out the doubleword header... */
+       outw(skb->len, ioaddr + TX_FIFO);
+       outw(0x00, ioaddr + TX_FIFO);
+       /* ... and the packet rounded to a doubleword. */
+       outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 
-    if (inw(ioaddr + TX_FREE) <= 1536) {
-       netif_stop_queue(dev);
-       /* Interrupt us when the FIFO has room for max-sized packet. */
-       outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
-    }
+       if (inw(ioaddr + TX_FREE) <= 1536) {
+               netif_stop_queue(dev);
+               /* Interrupt us when the FIFO has room for max-sized packet. */
+               outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+       }
 
-    pop_tx_status(dev);
-    spin_unlock_irqrestore(&priv->lock, flags);
-    dev_kfree_skb(skb);
+       pop_tx_status(dev);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       dev_kfree_skb(skb);
 
-    return NETDEV_TX_OK;
+       return NETDEV_TX_OK;
 }
 
 /* The EL3 interrupt handler. */
 static irqreturn_t el3_interrupt(int irq, void *dev_id)
 {
-    struct net_device *dev = (struct net_device *) dev_id;
-    struct el3_private *lp = netdev_priv(dev);
-    unsigned int ioaddr;
-    __u16 status;
-    int i = 0, handled = 1;
+       struct net_device *dev = (struct net_device *) dev_id;
+       struct el3_private *lp = netdev_priv(dev);
+       unsigned int ioaddr;
+       __u16 status;
+       int i = 0, handled = 1;
 
-    if (!netif_device_present(dev))
-       return IRQ_NONE;
+       if (!netif_device_present(dev))
+               return IRQ_NONE;
 
-    ioaddr = dev->base_addr;
+       ioaddr = dev->base_addr;
 
-    netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
+       netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS));
 
-    spin_lock(&lp->lock);
-    while ((status = inw(ioaddr + EL3_STATUS)) &
+       spin_lock(&lp->lock);
+       while ((status = inw(ioaddr + EL3_STATUS)) &
        (IntLatch | RxComplete | StatsFull)) {
-       if ((status & 0xe000) != 0x2000) {
-               netdev_dbg(dev, "interrupt from dead card\n");
-               handled = 0;
-               break;
-       }
-       if (status & RxComplete)
-               el3_rx(dev);
-       if (status & TxAvailable) {
-               netdev_dbg(dev, "    TX room bit was handled.\n");
-               /* There's room in the FIFO for a full-sized packet. */
-               outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
-               netif_wake_queue(dev);
-       }
-       if (status & TxComplete)
-               pop_tx_status(dev);
-       if (status & (AdapterFailure | RxEarly | StatsFull)) {
-           /* Handle all uncommon interrupts. */
-           if (status & StatsFull)             /* Empty statistics. */
-               update_stats(dev);
-           if (status & RxEarly) {             /* Rx early is unused. */
-               el3_rx(dev);
-               outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
-           }
-           if (status & AdapterFailure) {
-               u16 fifo_diag;
-               EL3WINDOW(4);
-               fifo_diag = inw(ioaddr + 4);
-               EL3WINDOW(1);
-               netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
+               if ((status & 0xe000) != 0x2000) {
+                       netdev_dbg(dev, "interrupt from dead card\n");
+                       handled = 0;
+                       break;
+               }
+               if (status & RxComplete)
+                       el3_rx(dev);
+               if (status & TxAvailable) {
+                       netdev_dbg(dev, "    TX room bit was handled.\n");
+                       /* There's room in the FIFO for a full-sized packet. */
+                       outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+                       netif_wake_queue(dev);
+               }
+               if (status & TxComplete)
+                       pop_tx_status(dev);
+               if (status & (AdapterFailure | RxEarly | StatsFull)) {
+                       /* Handle all uncommon interrupts. */
+                       if (status & StatsFull)         /* Empty statistics. */
+                               update_stats(dev);
+                       if (status & RxEarly) {
+                               /* Rx early is unused. */
+                               el3_rx(dev);
+                               outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+                       }
+                       if (status & AdapterFailure) {
+                               u16 fifo_diag;
+                               EL3WINDOW(4);
+                               fifo_diag = inw(ioaddr + 4);
+                               EL3WINDOW(1);
+                               netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n",
                            fifo_diag);
-               if (fifo_diag & 0x0400) {
-                   /* Tx overrun */
-                   tc589_wait_for_completion(dev, TxReset);
-                   outw(TxEnable, ioaddr + EL3_CMD);
+                               if (fifo_diag & 0x0400) {
+                                       /* Tx overrun */
+                                       tc589_wait_for_completion(dev, TxReset);
+                                       outw(TxEnable, ioaddr + EL3_CMD);
+                               }
+                               if (fifo_diag & 0x2000) {
+                                       /* Rx underrun */
+                                       tc589_wait_for_completion(dev, RxReset);
+                                       set_rx_mode(dev);
+                                       outw(RxEnable, ioaddr + EL3_CMD);
+                               }
+                               outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+                       }
                }
-               if (fifo_diag & 0x2000) {
-                   /* Rx underrun */
-                   tc589_wait_for_completion(dev, RxReset);
-                   set_rx_mode(dev);
-                   outw(RxEnable, ioaddr + EL3_CMD);
+               if (++i > 10) {
+                       netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
+                                       status);
+                       /* Clear all interrupts */
+                       outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+                       break;
                }
-               outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
-           }
+               /* Acknowledge the IRQ. */
+               outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
        }
-       if (++i > 10) {
-               netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n",
-                          status);
-               /* Clear all interrupts */
-               outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
-               break;
-       }
-       /* Acknowledge the IRQ. */
-       outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
-    }
-    lp->last_irq = jiffies;
-    spin_unlock(&lp->lock);
-    netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
-              inw(ioaddr + EL3_STATUS));
-    return IRQ_RETVAL(handled);
+       lp->last_irq = jiffies;
+       spin_unlock(&lp->lock);
+       netdev_dbg(dev, "exiting interrupt, status %4.4x.\n",
+                       inw(ioaddr + EL3_STATUS));
+       return IRQ_RETVAL(handled);
 }
 
 static void media_check(unsigned long arg)
 {
-    struct net_device *dev = (struct net_device *)(arg);
-    struct el3_private *lp = netdev_priv(dev);
-    unsigned int ioaddr = dev->base_addr;
-    u16 media, errs;
-    unsigned long flags;
+       struct net_device *dev = (struct net_device *)(arg);
+       struct el3_private *lp = netdev_priv(dev);
+       unsigned int ioaddr = dev->base_addr;
+       u16 media, errs;
+       unsigned long flags;
 
-    if (!netif_device_present(dev)) goto reschedule;
+       if (!netif_device_present(dev))
+               goto reschedule;
 
-    /* Check for pending interrupt with expired latency timer: with
-       this, we can limp along even if the interrupt is blocked */
-    if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
+       /* Check for pending interrupt with expired latency timer: with
+        * this, we can limp along even if the interrupt is blocked
+        */
+       if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
        (inb(ioaddr + EL3_TIMER) == 0xff)) {
-       if (!lp->fast_poll)
-               netdev_warn(dev, "interrupt(s) dropped!\n");
-
-       local_irq_save(flags);
-       el3_interrupt(dev->irq, dev);
-       local_irq_restore(flags);
-
-       lp->fast_poll = HZ;
-    }
-    if (lp->fast_poll) {
-       lp->fast_poll--;
-       lp->media.expires = jiffies + HZ/100;
-       add_timer(&lp->media);
-       return;
-    }
-
-    /* lp->lock guards the EL3 window. Window should always be 1 except
-       when the lock is held */
-    spin_lock_irqsave(&lp->lock, flags);
-    EL3WINDOW(4);
-    media = inw(ioaddr+WN4_MEDIA) & 0xc810;
-
-    /* Ignore collisions unless we've had no irq's recently */
-    if (time_before(jiffies, lp->last_irq + HZ)) {
-       media &= ~0x0010;
-    } else {
-       /* Try harder to detect carrier errors */
-       EL3WINDOW(6);
-       outw(StatsDisable, ioaddr + EL3_CMD);
-       errs = inb(ioaddr + 0);
-       outw(StatsEnable, ioaddr + EL3_CMD);
-       dev->stats.tx_carrier_errors += errs;
-       if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
-    }
+               if (!lp->fast_poll)
+                       netdev_warn(dev, "interrupt(s) dropped!\n");
+
+               local_irq_save(flags);
+               el3_interrupt(dev->irq, dev);
+               local_irq_restore(flags);
+
+               lp->fast_poll = HZ;
+       }
+       if (lp->fast_poll) {
+               lp->fast_poll--;
+               lp->media.expires = jiffies + HZ/100;
+               add_timer(&lp->media);
+               return;
+       }
+
+       /* lp->lock guards the EL3 window. Window should always be 1 except
+        * when the lock is held
+        */
+
+       spin_lock_irqsave(&lp->lock, flags);
+       EL3WINDOW(4);
+       media = inw(ioaddr+WN4_MEDIA) & 0xc810;
+
+       /* Ignore collisions unless we've had no irq's recently */
+       if (time_before(jiffies, lp->last_irq + HZ)) {
+               media &= ~0x0010;
+       } else {
+               /* Try harder to detect carrier errors */
+               EL3WINDOW(6);
+               outw(StatsDisable, ioaddr + EL3_CMD);
+               errs = inb(ioaddr + 0);
+               outw(StatsEnable, ioaddr + EL3_CMD);
+               dev->stats.tx_carrier_errors += errs;
+               if (errs || (lp->media_status & 0x0010))
+                       media |= 0x0010;
+       }
 
-    if (media != lp->media_status) {
-       if ((media & lp->media_status & 0x8000) &&
-           ((lp->media_status ^ media) & 0x0800))
+       if (media != lp->media_status) {
+               if ((media & lp->media_status & 0x8000) &&
+                               ((lp->media_status ^ media) & 0x0800))
                netdev_info(dev, "%s link beat\n",
-                           (lp->media_status & 0x0800 ? "lost" : "found"));
-       else if ((media & lp->media_status & 0x4000) &&
+                               (lp->media_status & 0x0800 ? "lost" : "found"));
+               else if ((media & lp->media_status & 0x4000) &&
                 ((lp->media_status ^ media) & 0x0010))
                netdev_info(dev, "coax cable %s\n",
-                           (lp->media_status & 0x0010 ? "ok" : "problem"));
-       if (dev->if_port == 0) {
-           if (media & 0x8000) {
-               if (media & 0x0800)
-                       netdev_info(dev, "flipped to 10baseT\n");
-               else
+                               (lp->media_status & 0x0010 ? "ok" : "problem"));
+               if (dev->if_port == 0) {
+                       if (media & 0x8000) {
+                               if (media & 0x0800)
+                                       netdev_info(dev, "flipped to 10baseT\n");
+                               else
                        tc589_set_xcvr(dev, 2);
-           } else if (media & 0x4000) {
-               if (media & 0x0010)
-                   tc589_set_xcvr(dev, 1);
-               else
-                   netdev_info(dev, "flipped to 10base2\n");
-           }
+                       } else if (media & 0x4000) {
+                               if (media & 0x0010)
+                                       tc589_set_xcvr(dev, 1);
+                               else
+                                       netdev_info(dev, "flipped to 10base2\n");
+                       }
+               }
+               lp->media_status = media;
        }
-       lp->media_status = media;
-    }
 
-    EL3WINDOW(1);
-    spin_unlock_irqrestore(&lp->lock, flags);
+       EL3WINDOW(1);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
 reschedule:
-    lp->media.expires = jiffies + HZ;
-    add_timer(&lp->media);
+       lp->media.expires = jiffies + HZ;
+       add_timer(&lp->media);
 }
 
 static struct net_device_stats *el3_get_stats(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
-    unsigned long flags;
-    struct pcmcia_device *link = lp->p_dev;
+       struct el3_private *lp = netdev_priv(dev);
+       unsigned long flags;
+       struct pcmcia_device *link = lp->p_dev;
 
-    if (pcmcia_dev_present(link)) {
-       spin_lock_irqsave(&lp->lock, flags);
-       update_stats(dev);
-       spin_unlock_irqrestore(&lp->lock, flags);
-    }
-    return &dev->stats;
+       if (pcmcia_dev_present(link)) {
+               spin_lock_irqsave(&lp->lock, flags);
+               update_stats(dev);
+               spin_unlock_irqrestore(&lp->lock, flags);
+       }
+       return &dev->stats;
 }
 
-/*
-  Update statistics.  We change to register window 6, so this should be run
-  single-threaded if the device is active. This is expected to be a rare
-  operation, and it's simpler for the rest of the driver to assume that
-  window 1 is always valid rather than use a special window-state variable.
-
-  Caller must hold the lock for this
+/* Update statistics.  We change to register window 6, so this should be run
+* single-threaded if the device is active. This is expected to be a rare
+* operation, and it's simpler for the rest of the driver to assume that
+* window 1 is always valid rather than use a special window-state variable.
+*
+* Caller must hold the lock for this
 */
+
 static void update_stats(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-
-    netdev_dbg(dev, "updating the statistics.\n");
-    /* Turn off statistics updates while reading. */
-    outw(StatsDisable, ioaddr + EL3_CMD);
-    /* Switch to the stats window, and read everything. */
-    EL3WINDOW(6);
-    dev->stats.tx_carrier_errors       += inb(ioaddr + 0);
-    dev->stats.tx_heartbeat_errors     += inb(ioaddr + 1);
-    /* Multiple collisions. */         inb(ioaddr + 2);
-    dev->stats.collisions              += inb(ioaddr + 3);
-    dev->stats.tx_window_errors                += inb(ioaddr + 4);
-    dev->stats.rx_fifo_errors          += inb(ioaddr + 5);
-    dev->stats.tx_packets              += inb(ioaddr + 6);
-    /* Rx packets   */                 inb(ioaddr + 7);
-    /* Tx deferrals */                 inb(ioaddr + 8);
-    /* Rx octets */                    inw(ioaddr + 10);
-    /* Tx octets */                    inw(ioaddr + 12);
-
-    /* Back to window 1, and turn statistics back on. */
-    EL3WINDOW(1);
-    outw(StatsEnable, ioaddr + EL3_CMD);
+       unsigned int ioaddr = dev->base_addr;
+
+       netdev_dbg(dev, "updating the statistics.\n");
+       /* Turn off statistics updates while reading. */
+       outw(StatsDisable, ioaddr + EL3_CMD);
+       /* Switch to the stats window, and read everything. */
+       EL3WINDOW(6);
+       dev->stats.tx_carrier_errors    += inb(ioaddr + 0);
+       dev->stats.tx_heartbeat_errors  += inb(ioaddr + 1);
+       /* Multiple collisions. */
+       inb(ioaddr + 2);
+       dev->stats.collisions           += inb(ioaddr + 3);
+       dev->stats.tx_window_errors             += inb(ioaddr + 4);
+       dev->stats.rx_fifo_errors               += inb(ioaddr + 5);
+       dev->stats.tx_packets           += inb(ioaddr + 6);
+       /* Rx packets   */
+       inb(ioaddr + 7);
+       /* Tx deferrals */
+       inb(ioaddr + 8);
+       /* Rx octets */
+       inw(ioaddr + 10);
+       /* Tx octets */
+       inw(ioaddr + 12);
+
+       /* Back to window 1, and turn statistics back on. */
+       EL3WINDOW(1);
+       outw(StatsEnable, ioaddr + EL3_CMD);
 }
 
 static int el3_rx(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-    int worklimit = 32;
-    short rx_status;
+       unsigned int ioaddr = dev->base_addr;
+       int worklimit = 32;
+       short rx_status;
 
-    netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+       netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n",
               inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
-    while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
+       while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
                    worklimit > 0) {
-       worklimit--;
-       if (rx_status & 0x4000) { /* Error, update stats. */
-           short error = rx_status & 0x3800;
-           dev->stats.rx_errors++;
-           switch (error) {
-           case 0x0000:        dev->stats.rx_over_errors++; break;
-           case 0x0800:        dev->stats.rx_length_errors++; break;
-           case 0x1000:        dev->stats.rx_frame_errors++; break;
-           case 0x1800:        dev->stats.rx_length_errors++; break;
-           case 0x2000:        dev->stats.rx_frame_errors++; break;
-           case 0x2800:        dev->stats.rx_crc_errors++; break;
-           }
-       } else {
-           short pkt_len = rx_status & 0x7ff;
-           struct sk_buff *skb;
-
-           skb = netdev_alloc_skb(dev, pkt_len + 5);
-
-           netdev_dbg(dev, "    Receiving packet size %d status %4.4x.\n",
+               worklimit--;
+               if (rx_status & 0x4000) { /* Error, update stats. */
+                       short error = rx_status & 0x3800;
+                       dev->stats.rx_errors++;
+                       switch (error) {
+                       case 0x0000:
+                               dev->stats.rx_over_errors++;
+                               break;
+                       case 0x0800:
+                               dev->stats.rx_length_errors++;
+                               break;
+                       case 0x1000:
+                               dev->stats.rx_frame_errors++;
+                               break;
+                       case 0x1800:
+                               dev->stats.rx_length_errors++;
+                               break;
+                       case 0x2000:
+                               dev->stats.rx_frame_errors++;
+                               break;
+                       case 0x2800:
+                               dev->stats.rx_crc_errors++;
+                               break;
+                       }
+               } else {
+                       short pkt_len = rx_status & 0x7ff;
+                       struct sk_buff *skb;
+
+                       skb = netdev_alloc_skb(dev, pkt_len + 5);
+
+                       netdev_dbg(dev, "    Receiving packet size %d status %4.4x.\n",
                       pkt_len, rx_status);
-           if (skb != NULL) {
-               skb_reserve(skb, 2);
-               insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+                       if (skb != NULL) {
+                               skb_reserve(skb, 2);
+                               insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
                        (pkt_len+3)>>2);
-               skb->protocol = eth_type_trans(skb, dev);
-               netif_rx(skb);
-               dev->stats.rx_packets++;
-               dev->stats.rx_bytes += pkt_len;
-           } else {
-               netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
+                               skb->protocol = eth_type_trans(skb, dev);
+                               netif_rx(skb);
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += pkt_len;
+                       } else {
+                               netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n",
                           pkt_len);
-               dev->stats.rx_dropped++;
-           }
+                               dev->stats.rx_dropped++;
+                       }
+               }
+               /* Pop the top of the Rx FIFO */
+               tc589_wait_for_completion(dev, RxDiscard);
        }
-       /* Pop the top of the Rx FIFO */
-       tc589_wait_for_completion(dev, RxDiscard);
-    }
-    if (worklimit == 0)
-       netdev_warn(dev, "too much work in el3_rx!\n");
-    return 0;
+       if (worklimit == 0)
+               netdev_warn(dev, "too much work in el3_rx!\n");
+       return 0;
 }
 
 static void set_rx_mode(struct net_device *dev)
 {
-    unsigned int ioaddr = dev->base_addr;
-    u16 opts = SetRxFilter | RxStation | RxBroadcast;
-
-    if (dev->flags & IFF_PROMISC)
-       opts |= RxMulticast | RxProm;
-    else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
-       opts |= RxMulticast;
-    outw(opts, ioaddr + EL3_CMD);
+       unsigned int ioaddr = dev->base_addr;
+       u16 opts = SetRxFilter | RxStation | RxBroadcast;
+
+       if (dev->flags & IFF_PROMISC)
+               opts |= RxMulticast | RxProm;
+       else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI))
+               opts |= RxMulticast;
+       outw(opts, ioaddr + EL3_CMD);
 }
 
 static void set_multicast_list(struct net_device *dev)
@@ -867,44 +908,44 @@ static void set_multicast_list(struct net_device *dev)
 
 static int el3_close(struct net_device *dev)
 {
-    struct el3_private *lp = netdev_priv(dev);
-    struct pcmcia_device *link = lp->p_dev;
-    unsigned int ioaddr = dev->base_addr;
-
-    dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
+       struct el3_private *lp = netdev_priv(dev);
+       struct pcmcia_device *link = lp->p_dev;
+       unsigned int ioaddr = dev->base_addr;
+
+       dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name);
+
+       if (pcmcia_dev_present(link)) {
+               /* Turn off statistics ASAP.  We update dev->stats below. */
+               outw(StatsDisable, ioaddr + EL3_CMD);
+
+               /* Disable the receiver and transmitter. */
+               outw(RxDisable, ioaddr + EL3_CMD);
+               outw(TxDisable, ioaddr + EL3_CMD);
+
+               if (dev->if_port == 2)
+                       /* Turn off thinnet power.  Green! */
+                       outw(StopCoax, ioaddr + EL3_CMD);
+               else if (dev->if_port == 1) {
+                       /* Disable link beat and jabber */
+                       EL3WINDOW(4);
+                       outw(0, ioaddr + WN4_MEDIA);
+               }
 
-    if (pcmcia_dev_present(link)) {
-       /* Turn off statistics ASAP.  We update dev->stats below. */
-       outw(StatsDisable, ioaddr + EL3_CMD);
+               /* Switching back to window 0 disables the IRQ. */
+               EL3WINDOW(0);
+               /* But we explicitly zero the IRQ line select anyway. */
+               outw(0x0f00, ioaddr + WN0_IRQ);
 
-       /* Disable the receiver and transmitter. */
-       outw(RxDisable, ioaddr + EL3_CMD);
-       outw(TxDisable, ioaddr + EL3_CMD);
-
-       if (dev->if_port == 2)
-           /* Turn off thinnet power.  Green! */
-           outw(StopCoax, ioaddr + EL3_CMD);
-       else if (dev->if_port == 1) {
-           /* Disable link beat and jabber */
-           EL3WINDOW(4);
-           outw(0, ioaddr + WN4_MEDIA);
+               /* Check if the card still exists */
+               if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
+                       update_stats(dev);
        }
 
-       /* Switching back to window 0 disables the IRQ. */
-       EL3WINDOW(0);
-       /* But we explicitly zero the IRQ line select anyway. */
-       outw(0x0f00, ioaddr + WN0_IRQ);
-
-       /* Check if the card still exists */
-       if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
-           update_stats(dev);
-    }
-
-    link->open--;
-    netif_stop_queue(dev);
-    del_timer_sync(&lp->media);
+       link->open--;
+       netif_stop_queue(dev);
+       del_timer_sync(&lp->media);
 
-    return 0;
+       return 0;
 }
 
 static const struct pcmcia_device_id tc589_ids[] = {
index 0f4241c6e97e7545eed585f445d1f3e01e436277..61477b8e8d24caa9941bc3e706518145f216722a 100644 (file)
@@ -2086,7 +2086,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* ... and the packet rounded to a doubleword. */
                skb_tx_timestamp(skb);
                iowrite32_rep(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-               dev_kfree_skb (skb);
+               dev_consume_skb_any (skb);
                if (ioread16(ioaddr + TxFree) > 1536) {
                        netif_start_queue (dev);        /* AKPM: redundant? */
                } else {
@@ -3294,7 +3294,6 @@ static int __init vortex_init(void)
 
 static void __exit vortex_eisa_cleanup(void)
 {
-       struct vortex_private *vp;
        void __iomem *ioaddr;
 
 #ifdef CONFIG_EISA
@@ -3303,7 +3302,6 @@ static void __exit vortex_eisa_cleanup(void)
 #endif
 
        if (compaq_net_device) {
-               vp = netdev_priv(compaq_net_device);
                ioaddr = ioport_map(compaq_net_device->base_addr,
                                    VORTEX_TOTAL_SIZE);
 
index d2cd80444ade7b5e5a6bdfe1f5e5207f8c02d798..599311f0e05c18eccad98511b3d7d73737dbd1d5 100644 (file)
@@ -404,7 +404,7 @@ static netdev_tx_t __ei_start_xmit(struct sk_buff *skb,
        spin_unlock(&ei_local->page_lock);
        enable_irq_lockdep_irqrestore(dev->irq, &flags);
        skb_tx_timestamp(skb);
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
        dev->stats.tx_bytes += send_length;
 
        return NETDEV_TX_OK;
index 506b0248c4001b48382f3ef6be2ccbc47724c8fa..39b26fe28d1051ff916faceb747da7a64dac711f 100644 (file)
@@ -22,6 +22,7 @@ source "drivers/net/ethernet/adaptec/Kconfig"
 source "drivers/net/ethernet/aeroflex/Kconfig"
 source "drivers/net/ethernet/allwinner/Kconfig"
 source "drivers/net/ethernet/alteon/Kconfig"
+source "drivers/net/ethernet/altera/Kconfig"
 source "drivers/net/ethernet/amd/Kconfig"
 source "drivers/net/ethernet/apple/Kconfig"
 source "drivers/net/ethernet/arc/Kconfig"
@@ -149,6 +150,7 @@ config S6GMAC
          To compile this driver as a module, choose M here. The module
          will be called s6gmac.
 
+source "drivers/net/ethernet/samsung/Kconfig"
 source "drivers/net/ethernet/seeq/Kconfig"
 source "drivers/net/ethernet/silan/Kconfig"
 source "drivers/net/ethernet/sis/Kconfig"
index c0b8789952e711fb77e44fc214d06ee8cac5e8f3..545d0b3b9cb422b2fefa7122b074cd869a9085c2 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_NET_VENDOR_ADAPTEC) += adaptec/
 obj-$(CONFIG_GRETH) += aeroflex/
 obj-$(CONFIG_NET_VENDOR_ALLWINNER) += allwinner/
 obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
+obj-$(CONFIG_ALTERA_TSE) += altera/
 obj-$(CONFIG_NET_VENDOR_AMD) += amd/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
 obj-$(CONFIG_NET_VENDOR_ARC) += arc/
@@ -60,6 +61,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
 obj-$(CONFIG_SH_ETH) += renesas/
 obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
 obj-$(CONFIG_S6GMAC) += s6gmac.o
+obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
 obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
 obj-$(CONFIG_NET_VENDOR_SILAN) += silan/
 obj-$(CONFIG_NET_VENDOR_SIS) += sis/
index c0f68dcd1dc125c422d4d1d084b331a01beee2b3..7ae74d450e8fb8786dae5f0e05e981685c92ef28 100644 (file)
@@ -307,11 +307,6 @@ static int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
        return bfin_mdio_poll();
 }
 
-static int bfin_mdiobus_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static void bfin_mac_adjust_link(struct net_device *dev)
 {
        struct bfin_mac_local *lp = netdev_priv(dev);
@@ -1040,6 +1035,7 @@ static struct ptp_clock_info bfin_ptp_caps = {
        .n_alarm        = 0,
        .n_ext_ts       = 0,
        .n_per_out      = 0,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = bfin_ptp_adjfreq,
        .adjtime        = bfin_ptp_adjtime,
@@ -1086,7 +1082,7 @@ static inline void _tx_reclaim_skb(void)
                tx_list_head->desc_a.config &= ~DMAEN;
                tx_list_head->status.status_word = 0;
                if (tx_list_head->skb) {
-                       dev_kfree_skb(tx_list_head->skb);
+                       dev_consume_skb_any(tx_list_head->skb);
                        tx_list_head->skb = NULL;
                }
                tx_list_head = tx_list_head->next;
@@ -1823,7 +1819,6 @@ static int bfin_mii_bus_probe(struct platform_device *pdev)
                goto out_err_alloc;
        miibus->read = bfin_mdiobus_read;
        miibus->write = bfin_mdiobus_write;
-       miibus->reset = bfin_mdiobus_reset;
 
        miibus->parent = &pdev->dev;
        miibus->name = "bfin_mii_bus";
index c5d75e7aeeb6e7140af25eb7b3b16797dae4f62e..23578dfee249879064c1b86526ee80aead68b79f 100644 (file)
@@ -1213,11 +1213,6 @@ static int greth_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
        return 0;
 }
 
-static int greth_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static void greth_link_change(struct net_device *dev)
 {
        struct greth_private *greth = netdev_priv(dev);
@@ -1332,7 +1327,6 @@ static int greth_mdio_init(struct greth_private *greth)
        snprintf(greth->mdio->id, MII_BUS_ID_SIZE, "%s-%d", greth->mdio->name, greth->irq);
        greth->mdio->read = greth_mdio_read;
        greth->mdio->write = greth_mdio_write;
-       greth->mdio->reset = greth_mdio_reset;
        greth->mdio->priv = greth;
 
        greth->mdio->irq = greth->mdio_irqs;
index 0cc21437478c43a031fbeb09be434e2819797f52..fcaeeb8a4929dbe2364752fe71f283dd46640ce3 100644 (file)
@@ -476,7 +476,7 @@ static int emac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&db->lock, flags);
 
        /* free this SKB */
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -929,6 +929,9 @@ static int emac_resume(struct platform_device *dev)
 }
 
 static const struct of_device_id emac_of_match[] = {
+       {.compatible = "allwinner,sun4i-a10-emac",},
+
+       /* Deprecated */
        {.compatible = "allwinner,sun4i-emac",},
        {},
 };
diff --git a/drivers/net/ethernet/altera/Kconfig b/drivers/net/ethernet/altera/Kconfig
new file mode 100644 (file)
index 0000000..80c1ab7
--- /dev/null
@@ -0,0 +1,8 @@
+config ALTERA_TSE
+       tristate "Altera Triple-Speed Ethernet MAC support"
+       select PHYLIB
+       ---help---
+         This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
+
+         To compile this driver as a module, choose M here. The module
+         will be called alteratse.
diff --git a/drivers/net/ethernet/altera/Makefile b/drivers/net/ethernet/altera/Makefile
new file mode 100644 (file)
index 0000000..d4a187e
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the Altera device drivers.
+#
+
+obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
+altera_tse-objs := altera_tse_main.o altera_tse_ethtool.o \
+altera_msgdma.o altera_sgdma.o altera_utils.o
diff --git a/drivers/net/ethernet/altera/altera_msgdma.c b/drivers/net/ethernet/altera/altera_msgdma.c
new file mode 100644 (file)
index 0000000..3df1866
--- /dev/null
@@ -0,0 +1,202 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/netdevice.h>
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_msgdmahw.h"
+
+/* No initialization work to do for MSGDMA */
+int msgdma_initialize(struct altera_tse_private *priv)
+{
+       return 0;
+}
+
+void msgdma_uninitialize(struct altera_tse_private *priv)
+{
+}
+
+void msgdma_reset(struct altera_tse_private *priv)
+{
+       int counter;
+       struct msgdma_csr *txcsr =
+               (struct msgdma_csr *)priv->tx_dma_csr;
+       struct msgdma_csr *rxcsr =
+               (struct msgdma_csr *)priv->rx_dma_csr;
+
+       /* Reset Rx mSGDMA */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
+       iowrite32(MSGDMA_CSR_CTL_RESET, &rxcsr->control);
+
+       counter = 0;
+       while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               if (tse_bit_is_clear(&rxcsr->status,
+                                    MSGDMA_CSR_STAT_RESETTING))
+                       break;
+               udelay(1);
+       }
+
+       if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
+               netif_warn(priv, drv, priv->dev,
+                          "TSE Rx mSGDMA resetting bit never cleared!\n");
+
+       /* clear all status bits */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &rxcsr->status);
+
+       /* Reset Tx mSGDMA */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status);
+       iowrite32(MSGDMA_CSR_CTL_RESET, &txcsr->control);
+
+       counter = 0;
+       while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               if (tse_bit_is_clear(&txcsr->status,
+                                    MSGDMA_CSR_STAT_RESETTING))
+                       break;
+               udelay(1);
+       }
+
+       if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR)
+               netif_warn(priv, drv, priv->dev,
+                          "TSE Tx mSGDMA resetting bit never cleared!\n");
+
+       /* clear all status bits */
+       iowrite32(MSGDMA_CSR_STAT_MASK, &txcsr->status);
+}
+
+void msgdma_disable_rxirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->rx_dma_csr;
+       tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_enable_rxirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->rx_dma_csr;
+       tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_disable_txirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->tx_dma_csr;
+       tse_clear_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_enable_txirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->tx_dma_csr;
+       tse_set_bit(&csr->control, MSGDMA_CSR_CTL_GLOBAL_INTR);
+}
+
+void msgdma_clear_rxirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->rx_dma_csr;
+       iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status);
+}
+
+void msgdma_clear_txirq(struct altera_tse_private *priv)
+{
+       struct msgdma_csr *csr = priv->tx_dma_csr;
+       iowrite32(MSGDMA_CSR_STAT_IRQ, &csr->status);
+}
+
+/* return 0 to indicate transmit is pending */
+int msgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       struct msgdma_extended_desc *desc = priv->tx_dma_desc;
+
+       iowrite32(lower_32_bits(buffer->dma_addr), &desc->read_addr_lo);
+       iowrite32(upper_32_bits(buffer->dma_addr), &desc->read_addr_hi);
+       iowrite32(0, &desc->write_addr_lo);
+       iowrite32(0, &desc->write_addr_hi);
+       iowrite32(buffer->len, &desc->len);
+       iowrite32(0, &desc->burst_seq_num);
+       iowrite32(MSGDMA_DESC_TX_STRIDE, &desc->stride);
+       iowrite32(MSGDMA_DESC_CTL_TX_SINGLE, &desc->control);
+       return 0;
+}
+
+u32 msgdma_tx_completions(struct altera_tse_private *priv)
+{
+       u32 ready = 0;
+       u32 inuse;
+       u32 status;
+       struct msgdma_csr *txcsr =
+               (struct msgdma_csr *)priv->tx_dma_csr;
+
+       /* Get number of sent descriptors */
+       inuse = ioread32(&txcsr->rw_fill_level) & 0xffff;
+
+       if (inuse) { /* Tx FIFO is not empty */
+               ready = priv->tx_prod - priv->tx_cons - inuse - 1;
+       } else {
+               /* Check for buffered last packet */
+               status = ioread32(&txcsr->status);
+               if (status & MSGDMA_CSR_STAT_BUSY)
+                       ready = priv->tx_prod - priv->tx_cons - 1;
+               else
+                       ready = priv->tx_prod - priv->tx_cons;
+       }
+       return ready;
+}
+
+/* Put buffer to the mSGDMA RX FIFO
+ */
+int msgdma_add_rx_desc(struct altera_tse_private *priv,
+                       struct tse_buffer *rxbuffer)
+{
+       struct msgdma_extended_desc *desc = priv->rx_dma_desc;
+       u32 len = priv->rx_dma_buf_sz;
+       dma_addr_t dma_addr = rxbuffer->dma_addr;
+       u32 control = (MSGDMA_DESC_CTL_END_ON_EOP
+                       | MSGDMA_DESC_CTL_END_ON_LEN
+                       | MSGDMA_DESC_CTL_TR_COMP_IRQ
+                       | MSGDMA_DESC_CTL_EARLY_IRQ
+                       | MSGDMA_DESC_CTL_TR_ERR_IRQ
+                       | MSGDMA_DESC_CTL_GO);
+
+       iowrite32(0, &desc->read_addr_lo);
+       iowrite32(0, &desc->read_addr_hi);
+       iowrite32(lower_32_bits(dma_addr), &desc->write_addr_lo);
+       iowrite32(upper_32_bits(dma_addr), &desc->write_addr_hi);
+       iowrite32(len, &desc->len);
+       iowrite32(0, &desc->burst_seq_num);
+       iowrite32(0x00010001, &desc->stride);
+       iowrite32(control, &desc->control);
+       return 1;
+}
+
+/* status is returned on upper 16 bits,
+ * length is returned in lower 16 bits
+ */
+u32 msgdma_rx_status(struct altera_tse_private *priv)
+{
+       u32 rxstatus = 0;
+       u32 pktlength;
+       u32 pktstatus;
+       struct msgdma_csr *rxcsr =
+               (struct msgdma_csr *)priv->rx_dma_csr;
+       struct msgdma_response *rxresp =
+               (struct msgdma_response *)priv->rx_dma_resp;
+
+       if (ioread32(&rxcsr->resp_fill_level) & 0xffff) {
+               pktlength = ioread32(&rxresp->bytes_transferred);
+               pktstatus = ioread32(&rxresp->status);
+               rxstatus = pktstatus;
+               rxstatus = rxstatus << 16;
+               rxstatus |= (pktlength & 0xffff);
+       }
+       return rxstatus;
+}
diff --git a/drivers/net/ethernet/altera/altera_msgdma.h b/drivers/net/ethernet/altera/altera_msgdma.h
new file mode 100644 (file)
index 0000000..7f0f5bf
--- /dev/null
@@ -0,0 +1,34 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_MSGDMA_H__
+#define __ALTERA_MSGDMA_H__
+
+void msgdma_reset(struct altera_tse_private *);
+void msgdma_enable_txirq(struct altera_tse_private *);
+void msgdma_enable_rxirq(struct altera_tse_private *);
+void msgdma_disable_rxirq(struct altera_tse_private *);
+void msgdma_disable_txirq(struct altera_tse_private *);
+void msgdma_clear_rxirq(struct altera_tse_private *);
+void msgdma_clear_txirq(struct altera_tse_private *);
+u32 msgdma_tx_completions(struct altera_tse_private *);
+int msgdma_add_rx_desc(struct altera_tse_private *, struct tse_buffer *);
+int msgdma_tx_buffer(struct altera_tse_private *, struct tse_buffer *);
+u32 msgdma_rx_status(struct altera_tse_private *);
+int msgdma_initialize(struct altera_tse_private *);
+void msgdma_uninitialize(struct altera_tse_private *);
+
+#endif /*  __ALTERA_MSGDMA_H__ */
diff --git a/drivers/net/ethernet/altera/altera_msgdmahw.h b/drivers/net/ethernet/altera/altera_msgdmahw.h
new file mode 100644 (file)
index 0000000..d7b59ba
--- /dev/null
@@ -0,0 +1,167 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_MSGDMAHW_H__
+#define __ALTERA_MSGDMAHW_H__
+
+/* mSGDMA standard descriptor format
+ */
+struct msgdma_desc {
+       u32 read_addr;  /* data buffer source address */
+       u32 write_addr; /* data buffer destination address */
+       u32 len;        /* the number of bytes to transfer per descriptor */
+       u32 control;    /* characteristics of the transfer */
+};
+
+/* mSGDMA extended descriptor format
+ */
+struct msgdma_extended_desc {
+       u32 read_addr_lo;       /* data buffer source address low bits */
+       u32 write_addr_lo;      /* data buffer destination address low bits */
+       u32 len;                /* the number of bytes to transfer
+                                * per descriptor
+                                */
+       u32 burst_seq_num;      /* bit 31:24 write burst
+                                * bit 23:16 read burst
+                                * bit 15:0  sequence number
+                                */
+       u32 stride;             /* bit 31:16 write stride
+                                * bit 15:0  read stride
+                                */
+       u32 read_addr_hi;       /* data buffer source address high bits */
+       u32 write_addr_hi;      /* data buffer destination address high bits */
+       u32 control;            /* characteristics of the transfer */
+};
+
+/* mSGDMA descriptor control field bit definitions
+ */
+#define MSGDMA_DESC_CTL_SET_CH(x)      ((x) & 0xff)
+#define MSGDMA_DESC_CTL_GEN_SOP                BIT(8)
+#define MSGDMA_DESC_CTL_GEN_EOP                BIT(9)
+#define MSGDMA_DESC_CTL_PARK_READS     BIT(10)
+#define MSGDMA_DESC_CTL_PARK_WRITES    BIT(11)
+#define MSGDMA_DESC_CTL_END_ON_EOP     BIT(12)
+#define MSGDMA_DESC_CTL_END_ON_LEN     BIT(13)
+#define MSGDMA_DESC_CTL_TR_COMP_IRQ    BIT(14)
+#define MSGDMA_DESC_CTL_EARLY_IRQ      BIT(15)
+#define MSGDMA_DESC_CTL_TR_ERR_IRQ     (0xff << 16)
+#define MSGDMA_DESC_CTL_EARLY_DONE     BIT(24)
+/* Writing ‘1’ to the ‘go’ bit commits the entire descriptor into the
+ * descriptor FIFO(s)
+ */
+#define MSGDMA_DESC_CTL_GO             BIT(31)
+
+/* Tx buffer control flags
+ */
+#define MSGDMA_DESC_CTL_TX_FIRST       (MSGDMA_DESC_CTL_GEN_SOP |      \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_MIDDLE      (MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_LAST                (MSGDMA_DESC_CTL_GEN_EOP |      \
+                                        MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_TX_SINGLE      (MSGDMA_DESC_CTL_GEN_SOP |      \
+                                        MSGDMA_DESC_CTL_GEN_EOP |      \
+                                        MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+#define MSGDMA_DESC_CTL_RX_SINGLE      (MSGDMA_DESC_CTL_END_ON_EOP |   \
+                                        MSGDMA_DESC_CTL_END_ON_LEN |   \
+                                        MSGDMA_DESC_CTL_TR_COMP_IRQ |  \
+                                        MSGDMA_DESC_CTL_EARLY_IRQ |    \
+                                        MSGDMA_DESC_CTL_TR_ERR_IRQ |   \
+                                        MSGDMA_DESC_CTL_GO)
+
+/* mSGDMA extended descriptor stride definitions
+ */
+#define MSGDMA_DESC_TX_STRIDE          (0x00010001)
+#define MSGDMA_DESC_RX_STRIDE          (0x00010001)
+
+/* mSGDMA dispatcher control and status register map
+ */
+struct msgdma_csr {
+       u32 status;             /* Read/Clear */
+       u32 control;            /* Read/Write */
+       u32 rw_fill_level;      /* bit 31:16 - write fill level
+                                * bit 15:0  - read fill level
+                                */
+       u32 resp_fill_level;    /* bit 15:0 */
+       u32 rw_seq_num;         /* bit 31:16 - write sequence number
+                                * bit 15:0  - read sequence number
+                                */
+       u32 pad[3];             /* reserved */
+};
+
+/* mSGDMA CSR status register bit definitions
+ */
+#define MSGDMA_CSR_STAT_BUSY                   BIT(0)
+#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY         BIT(1)
+#define MSGDMA_CSR_STAT_DESC_BUF_FULL          BIT(2)
+#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY         BIT(3)
+#define MSGDMA_CSR_STAT_RESP_BUF_FULL          BIT(4)
+#define MSGDMA_CSR_STAT_STOPPED                        BIT(5)
+#define MSGDMA_CSR_STAT_RESETTING              BIT(6)
+#define MSGDMA_CSR_STAT_STOPPED_ON_ERR         BIT(7)
+#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY       BIT(8)
+#define MSGDMA_CSR_STAT_IRQ                    BIT(9)
+#define MSGDMA_CSR_STAT_MASK                   0x3FF
+#define MSGDMA_CSR_STAT_MASK_WITHOUT_IRQ       0x1FF
+
+#define MSGDMA_CSR_STAT_BUSY_GET(v)                    GET_BIT_VALUE(v, 0)
+#define MSGDMA_CSR_STAT_DESC_BUF_EMPTY_GET(v)          GET_BIT_VALUE(v, 1)
+#define MSGDMA_CSR_STAT_DESC_BUF_FULL_GET(v)           GET_BIT_VALUE(v, 2)
+#define MSGDMA_CSR_STAT_RESP_BUF_EMPTY_GET(v)          GET_BIT_VALUE(v, 3)
+#define MSGDMA_CSR_STAT_RESP_BUF_FULL_GET(v)           GET_BIT_VALUE(v, 4)
+#define MSGDMA_CSR_STAT_STOPPED_GET(v)                 GET_BIT_VALUE(v, 5)
+#define MSGDMA_CSR_STAT_RESETTING_GET(v)               GET_BIT_VALUE(v, 6)
+#define MSGDMA_CSR_STAT_STOPPED_ON_ERR_GET(v)          GET_BIT_VALUE(v, 7)
+#define MSGDMA_CSR_STAT_STOPPED_ON_EARLY_GET(v)                GET_BIT_VALUE(v, 8)
+#define MSGDMA_CSR_STAT_IRQ_GET(v)                     GET_BIT_VALUE(v, 9)
+
+/* mSGDMA CSR control register bit definitions
+ */
+#define MSGDMA_CSR_CTL_STOP                    BIT(0)
+#define MSGDMA_CSR_CTL_RESET                   BIT(1)
+#define MSGDMA_CSR_CTL_STOP_ON_ERR             BIT(2)
+#define MSGDMA_CSR_CTL_STOP_ON_EARLY           BIT(3)
+#define MSGDMA_CSR_CTL_GLOBAL_INTR             BIT(4)
+#define MSGDMA_CSR_CTL_STOP_DESCS              BIT(5)
+
+/* mSGDMA CSR fill level bits
+ */
+#define MSGDMA_CSR_WR_FILL_LEVEL_GET(v)                (((v) & 0xffff0000) >> 16)
+#define MSGDMA_CSR_RD_FILL_LEVEL_GET(v)                ((v) & 0x0000ffff)
+#define MSGDMA_CSR_RESP_FILL_LEVEL_GET(v)      ((v) & 0x0000ffff)
+
+/* mSGDMA response register map
+ */
+struct msgdma_response {
+       u32 bytes_transferred;
+       u32 status;
+};
+
+/* mSGDMA response register bit definitions
+ */
+#define MSGDMA_RESP_EARLY_TERM BIT(8)
+#define MSGDMA_RESP_ERR_MASK   0xFF
+
+#endif /* __ALTERA_MSGDMA_H__*/
diff --git a/drivers/net/ethernet/altera/altera_sgdma.c b/drivers/net/ethernet/altera/altera_sgdma.c
new file mode 100644 (file)
index 0000000..0ee9663
--- /dev/null
@@ -0,0 +1,509 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/list.h>
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_sgdmahw.h"
+#include "altera_sgdma.h"
+
+static void sgdma_descrip(struct sgdma_descrip *desc,
+                         struct sgdma_descrip *ndesc,
+                         dma_addr_t ndesc_phys,
+                         dma_addr_t raddr,
+                         dma_addr_t waddr,
+                         u16 length,
+                         int generate_eop,
+                         int rfixed,
+                         int wfixed);
+
+static int sgdma_async_write(struct altera_tse_private *priv,
+                             struct sgdma_descrip *desc);
+
+static int sgdma_async_read(struct altera_tse_private *priv);
+
+static dma_addr_t
+sgdma_txphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc);
+
+static dma_addr_t
+sgdma_rxphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc);
+
+static int sgdma_txbusy(struct altera_tse_private *priv);
+
+static int sgdma_rxbusy(struct altera_tse_private *priv);
+
+static void
+queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer);
+
+static void
+queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer);
+
+static struct tse_buffer *
+dequeue_tx(struct altera_tse_private *priv);
+
+static struct tse_buffer *
+dequeue_rx(struct altera_tse_private *priv);
+
+static struct tse_buffer *
+queue_rx_peekhead(struct altera_tse_private *priv);
+
+int sgdma_initialize(struct altera_tse_private *priv)
+{
+       priv->txctrlreg = SGDMA_CTRLREG_ILASTD;
+
+       priv->rxctrlreg = SGDMA_CTRLREG_IDESCRIP |
+                     SGDMA_CTRLREG_ILASTD;
+
+       INIT_LIST_HEAD(&priv->txlisthd);
+       INIT_LIST_HEAD(&priv->rxlisthd);
+
+       priv->rxdescphys = (dma_addr_t) 0;
+       priv->txdescphys = (dma_addr_t) 0;
+
+       priv->rxdescphys = dma_map_single(priv->device, priv->rx_dma_desc,
+                                         priv->rxdescmem, DMA_BIDIRECTIONAL);
+
+       if (dma_mapping_error(priv->device, priv->rxdescphys)) {
+               sgdma_uninitialize(priv);
+               netdev_err(priv->dev, "error mapping rx descriptor memory\n");
+               return -EINVAL;
+       }
+
+       priv->txdescphys = dma_map_single(priv->device, priv->tx_dma_desc,
+                                         priv->txdescmem, DMA_TO_DEVICE);
+
+       if (dma_mapping_error(priv->device, priv->txdescphys)) {
+               sgdma_uninitialize(priv);
+               netdev_err(priv->dev, "error mapping tx descriptor memory\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void sgdma_uninitialize(struct altera_tse_private *priv)
+{
+       if (priv->rxdescphys)
+               dma_unmap_single(priv->device, priv->rxdescphys,
+                                priv->rxdescmem, DMA_BIDIRECTIONAL);
+
+       if (priv->txdescphys)
+               dma_unmap_single(priv->device, priv->txdescphys,
+                                priv->txdescmem, DMA_TO_DEVICE);
+}
+
+/* This function resets the SGDMA controller and clears the
+ * descriptor memory used for transmits and receives.
+ */
+void sgdma_reset(struct altera_tse_private *priv)
+{
+       u32 *ptxdescripmem = (u32 *)priv->tx_dma_desc;
+       u32 txdescriplen   = priv->txdescmem;
+       u32 *prxdescripmem = (u32 *)priv->rx_dma_desc;
+       u32 rxdescriplen   = priv->rxdescmem;
+       struct sgdma_csr *ptxsgdma = (struct sgdma_csr *)priv->tx_dma_csr;
+       struct sgdma_csr *prxsgdma = (struct sgdma_csr *)priv->rx_dma_csr;
+
+       /* Initialize descriptor memory to 0 */
+       memset(ptxdescripmem, 0, txdescriplen);
+       memset(prxdescripmem, 0, rxdescriplen);
+
+       iowrite32(SGDMA_CTRLREG_RESET, &ptxsgdma->control);
+       iowrite32(0, &ptxsgdma->control);
+
+       iowrite32(SGDMA_CTRLREG_RESET, &prxsgdma->control);
+       iowrite32(0, &prxsgdma->control);
+}
+
+void sgdma_enable_rxirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       priv->rxctrlreg |= SGDMA_CTRLREG_INTEN;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
+}
+
+void sgdma_enable_txirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       priv->txctrlreg |= SGDMA_CTRLREG_INTEN;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_INTEN);
+}
+
+/* for SGDMA, RX interrupts remain enabled after enabling */
+void sgdma_disable_rxirq(struct altera_tse_private *priv)
+{
+}
+
+/* for SGDMA, TX interrupts remain enabled after enabling */
+void sgdma_disable_txirq(struct altera_tse_private *priv)
+{
+}
+
+void sgdma_clear_rxirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
+}
+
+void sgdma_clear_txirq(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+       tse_set_bit(&csr->control, SGDMA_CTRLREG_CLRINT);
+}
+
+/* transmits buffer through SGDMA. Returns number of buffers
+ * transmitted, 0 if not possible.
+ *
+ * tx_lock is held by the caller
+ */
+int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       int pktstx = 0;
+       struct sgdma_descrip *descbase =
+               (struct sgdma_descrip *)priv->tx_dma_desc;
+
+       struct sgdma_descrip *cdesc = &descbase[0];
+       struct sgdma_descrip *ndesc = &descbase[1];
+
+       /* wait 'til the tx sgdma is ready for the next transmit request */
+       if (sgdma_txbusy(priv))
+               return 0;
+
+       sgdma_descrip(cdesc,                    /* current descriptor */
+                     ndesc,                    /* next descriptor */
+                     sgdma_txphysaddr(priv, ndesc),
+                     buffer->dma_addr,         /* address of packet to xmit */
+                     0,                        /* write addr 0 for tx dma */
+                     buffer->len,              /* length of packet */
+                     SGDMA_CONTROL_EOP,        /* Generate EOP */
+                     0,                        /* read fixed */
+                     SGDMA_CONTROL_WR_FIXED);  /* Generate SOP */
+
+       pktstx = sgdma_async_write(priv, cdesc);
+
+       /* enqueue the request to the pending transmit queue */
+       queue_tx(priv, buffer);
+
+       return 1;
+}
+
+
+/* tx_lock held to protect access to queued tx list
+ */
+u32 sgdma_tx_completions(struct altera_tse_private *priv)
+{
+       u32 ready = 0;
+       struct sgdma_descrip *desc = (struct sgdma_descrip *)priv->tx_dma_desc;
+
+       if (!sgdma_txbusy(priv) &&
+           ((desc->control & SGDMA_CONTROL_HW_OWNED) == 0) &&
+           (dequeue_tx(priv))) {
+               ready = 1;
+       }
+
+       return ready;
+}
+
+int sgdma_add_rx_desc(struct altera_tse_private *priv,
+                     struct tse_buffer *rxbuffer)
+{
+       queue_rx(priv, rxbuffer);
+       return sgdma_async_read(priv);
+}
+
+/* status is returned on upper 16 bits,
+ * length is returned in lower 16 bits
+ */
+u32 sgdma_rx_status(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_descrip *base = (struct sgdma_descrip *)priv->rx_dma_desc;
+       struct sgdma_descrip *desc = NULL;
+       int pktsrx;
+       unsigned int rxstatus = 0;
+       unsigned int pktlength = 0;
+       unsigned int pktstatus = 0;
+       struct tse_buffer *rxbuffer = NULL;
+
+       dma_sync_single_for_cpu(priv->device,
+                               priv->rxdescphys,
+                               priv->rxdescmem,
+                               DMA_BIDIRECTIONAL);
+
+       desc = &base[0];
+       if ((ioread32(&csr->status) & SGDMA_STSREG_EOP) ||
+           (desc->status & SGDMA_STATUS_EOP)) {
+               pktlength = desc->bytes_xferred;
+               pktstatus = desc->status & 0x3f;
+               rxstatus = pktstatus;
+               rxstatus = rxstatus << 16;
+               rxstatus |= (pktlength & 0xffff);
+
+               desc->status = 0;
+
+               rxbuffer = dequeue_rx(priv);
+               if (rxbuffer == NULL)
+                       netdev_err(priv->dev,
+                                  "sgdma rx and rx queue empty!\n");
+
+               /* kick the rx sgdma after reaping this descriptor */
+               pktsrx = sgdma_async_read(priv);
+       }
+
+       return rxstatus;
+}
+
+
+/* Private functions */
+static void sgdma_descrip(struct sgdma_descrip *desc,
+                         struct sgdma_descrip *ndesc,
+                         dma_addr_t ndesc_phys,
+                         dma_addr_t raddr,
+                         dma_addr_t waddr,
+                         u16 length,
+                         int generate_eop,
+                         int rfixed,
+                         int wfixed)
+{
+       /* Clear the next descriptor as not owned by hardware */
+       u32 ctrl = ndesc->control;
+       ctrl &= ~SGDMA_CONTROL_HW_OWNED;
+       ndesc->control = ctrl;
+
+       ctrl = 0;
+       ctrl = SGDMA_CONTROL_HW_OWNED;
+       ctrl |= generate_eop;
+       ctrl |= rfixed;
+       ctrl |= wfixed;
+
+       /* Channel is implicitly zero, initialized to 0 by default */
+
+       desc->raddr = raddr;
+       desc->waddr = waddr;
+       desc->next = lower_32_bits(ndesc_phys);
+       desc->control = ctrl;
+       desc->status = 0;
+       desc->rburst = 0;
+       desc->wburst = 0;
+       desc->bytes = length;
+       desc->bytes_xferred = 0;
+}
+
+/* If hardware is busy, don't restart async read.
+ * if status register is 0 - meaning initial state, restart async read,
+ * probably for the first time when populating a receive buffer.
+ * If read status indicate not busy and a status, restart the async
+ * DMA read.
+ */
+static int sgdma_async_read(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       struct sgdma_descrip *descbase =
+               (struct sgdma_descrip *)priv->rx_dma_desc;
+
+       struct sgdma_descrip *cdesc = &descbase[0];
+       struct sgdma_descrip *ndesc = &descbase[1];
+
+       unsigned int sts = ioread32(&csr->status);
+       struct tse_buffer *rxbuffer = NULL;
+
+       if (!sgdma_rxbusy(priv)) {
+               rxbuffer = queue_rx_peekhead(priv);
+               if (rxbuffer == NULL)
+                       return 0;
+
+               sgdma_descrip(cdesc,            /* current descriptor */
+                             ndesc,            /* next descriptor */
+                             sgdma_rxphysaddr(priv, ndesc),
+                             0,                /* read addr 0 for rx dma */
+                             rxbuffer->dma_addr, /* write addr for rx dma */
+                             0,                /* read 'til EOP */
+                             0,                /* EOP: NA for rx dma */
+                             0,                /* read fixed: NA for rx dma */
+                             0);               /* SOP: NA for rx DMA */
+
+               /* clear control and status */
+               iowrite32(0, &csr->control);
+
+               /* If status available, clear those bits */
+               if (sts & 0xf)
+                       iowrite32(0xf, &csr->status);
+
+               dma_sync_single_for_device(priv->device,
+                                          priv->rxdescphys,
+                                          priv->rxdescmem,
+                                          DMA_BIDIRECTIONAL);
+
+               iowrite32(lower_32_bits(sgdma_rxphysaddr(priv, cdesc)),
+                         &csr->next_descrip);
+
+               iowrite32((priv->rxctrlreg | SGDMA_CTRLREG_START),
+                         &csr->control);
+
+               return 1;
+       }
+
+       return 0;
+}
+
+static int sgdma_async_write(struct altera_tse_private *priv,
+                            struct sgdma_descrip *desc)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+
+       if (sgdma_txbusy(priv))
+               return 0;
+
+       /* clear control and status */
+       iowrite32(0, &csr->control);
+       iowrite32(0x1f, &csr->status);
+
+       dma_sync_single_for_device(priv->device, priv->txdescphys,
+                                  priv->txdescmem, DMA_TO_DEVICE);
+
+       iowrite32(lower_32_bits(sgdma_txphysaddr(priv, desc)),
+                 &csr->next_descrip);
+
+       iowrite32((priv->txctrlreg | SGDMA_CTRLREG_START),
+                 &csr->control);
+
+       return 1;
+}
+
+static dma_addr_t
+sgdma_txphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc)
+{
+       dma_addr_t paddr = priv->txdescmem_busaddr;
+       uintptr_t offs = (uintptr_t)desc - (uintptr_t)priv->tx_dma_desc;
+       return (dma_addr_t)((uintptr_t)paddr + offs);
+}
+
+static dma_addr_t
+sgdma_rxphysaddr(struct altera_tse_private *priv,
+                struct sgdma_descrip *desc)
+{
+       dma_addr_t paddr = priv->rxdescmem_busaddr;
+       uintptr_t offs = (uintptr_t)desc - (uintptr_t)priv->rx_dma_desc;
+       return (dma_addr_t)((uintptr_t)paddr + offs);
+}
+
+#define list_remove_head(list, entry, type, member)                    \
+       do {                                                            \
+               entry = NULL;                                           \
+               if (!list_empty(list)) {                                \
+                       entry = list_entry((list)->next, type, member); \
+                       list_del_init(&entry->member);                  \
+               }                                                       \
+       } while (0)
+
+#define list_peek_head(list, entry, type, member)                      \
+       do {                                                            \
+               entry = NULL;                                           \
+               if (!list_empty(list)) {                                \
+                       entry = list_entry((list)->next, type, member); \
+               }                                                       \
+       } while (0)
+
+/* adds a tse_buffer to the tail of a tx buffer list.
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static void
+queue_tx(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       list_add_tail(&buffer->lh, &priv->txlisthd);
+}
+
+
+/* adds a tse_buffer to the tail of a rx buffer list
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static void
+queue_rx(struct altera_tse_private *priv, struct tse_buffer *buffer)
+{
+       list_add_tail(&buffer->lh, &priv->rxlisthd);
+}
+
+/* dequeues a tse_buffer from the transmit buffer list, otherwise
+ * returns NULL if empty.
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static struct tse_buffer *
+dequeue_tx(struct altera_tse_private *priv)
+{
+       struct tse_buffer *buffer = NULL;
+       list_remove_head(&priv->txlisthd, buffer, struct tse_buffer, lh);
+       return buffer;
+}
+
+/* dequeues a tse_buffer from the receive buffer list, otherwise
+ * returns NULL if empty
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list.
+ */
+static struct tse_buffer *
+dequeue_rx(struct altera_tse_private *priv)
+{
+       struct tse_buffer *buffer = NULL;
+       list_remove_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
+       return buffer;
+}
+
+/* dequeues a tse_buffer from the receive buffer list, otherwise
+ * returns NULL if empty
+ * assumes the caller is managing and holding a mutual exclusion
+ * primitive to avoid simultaneous pushes/pops to the list while the
+ * head is being examined.
+ */
+static struct tse_buffer *
+queue_rx_peekhead(struct altera_tse_private *priv)
+{
+       struct tse_buffer *buffer = NULL;
+       list_peek_head(&priv->rxlisthd, buffer, struct tse_buffer, lh);
+       return buffer;
+}
+
+/* check and return rx sgdma status without polling
+ */
+static int sgdma_rxbusy(struct altera_tse_private *priv)
+{
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->rx_dma_csr;
+       return ioread32(&csr->status) & SGDMA_STSREG_BUSY;
+}
+
+/* waits for the tx sgdma to finish it's current operation, returns 0
+ * when it transitions to nonbusy, returns 1 if the operation times out
+ */
+static int sgdma_txbusy(struct altera_tse_private *priv)
+{
+       int delay = 0;
+       struct sgdma_csr *csr = (struct sgdma_csr *)priv->tx_dma_csr;
+
+       /* if DMA is busy, wait for current transactino to finish */
+       while ((ioread32(&csr->status) & SGDMA_STSREG_BUSY) && (delay++ < 100))
+               udelay(1);
+
+       if (ioread32(&csr->status) & SGDMA_STSREG_BUSY) {
+               netdev_err(priv->dev, "timeout waiting for tx dma\n");
+               return 1;
+       }
+       return 0;
+}
diff --git a/drivers/net/ethernet/altera/altera_sgdma.h b/drivers/net/ethernet/altera/altera_sgdma.h
new file mode 100644 (file)
index 0000000..07d4717
--- /dev/null
@@ -0,0 +1,35 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_SGDMA_H__
+#define __ALTERA_SGDMA_H__
+
+void sgdma_reset(struct altera_tse_private *);
+void sgdma_enable_txirq(struct altera_tse_private *);
+void sgdma_enable_rxirq(struct altera_tse_private *);
+void sgdma_disable_rxirq(struct altera_tse_private *);
+void sgdma_disable_txirq(struct altera_tse_private *);
+void sgdma_clear_rxirq(struct altera_tse_private *);
+void sgdma_clear_txirq(struct altera_tse_private *);
+int sgdma_tx_buffer(struct altera_tse_private *priv, struct tse_buffer *);
+u32 sgdma_tx_completions(struct altera_tse_private *);
+int sgdma_add_rx_desc(struct altera_tse_private *priv, struct tse_buffer *);
+void sgdma_status(struct altera_tse_private *);
+u32 sgdma_rx_status(struct altera_tse_private *);
+int sgdma_initialize(struct altera_tse_private *);
+void sgdma_uninitialize(struct altera_tse_private *);
+
+#endif /*  __ALTERA_SGDMA_H__ */
diff --git a/drivers/net/ethernet/altera/altera_sgdmahw.h b/drivers/net/ethernet/altera/altera_sgdmahw.h
new file mode 100644 (file)
index 0000000..ba3334f
--- /dev/null
@@ -0,0 +1,124 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_SGDMAHW_H__
+#define __ALTERA_SGDMAHW_H__
+
+/* SGDMA descriptor structure */
+struct sgdma_descrip {
+       unsigned int    raddr; /* address of data to be read */
+       unsigned int    pad1;
+       unsigned int    waddr;
+       unsigned int    pad2;
+       unsigned int    next;
+       unsigned int    pad3;
+       unsigned short  bytes;
+       unsigned char   rburst;
+       unsigned char   wburst;
+       unsigned short  bytes_xferred;  /* 16 bits, bytes xferred */
+
+       /* bit 0: error
+        * bit 1: length error
+        * bit 2: crc error
+        * bit 3: truncated error
+        * bit 4: phy error
+        * bit 5: collision error
+        * bit 6: reserved
+        * bit 7: status eop for recv case
+        */
+       unsigned char   status;
+
+       /* bit 0: eop
+        * bit 1: read_fixed
+        * bit 2: write fixed
+        * bits 3,4,5,6: Channel (always 0)
+        * bit 7: hardware owned
+        */
+       unsigned char   control;
+} __packed;
+
+
+#define SGDMA_STATUS_ERR               BIT(0)
+#define SGDMA_STATUS_LENGTH_ERR                BIT(1)
+#define SGDMA_STATUS_CRC_ERR           BIT(2)
+#define SGDMA_STATUS_TRUNC_ERR         BIT(3)
+#define SGDMA_STATUS_PHY_ERR           BIT(4)
+#define SGDMA_STATUS_COLL_ERR          BIT(5)
+#define SGDMA_STATUS_EOP               BIT(7)
+
+#define SGDMA_CONTROL_EOP              BIT(0)
+#define SGDMA_CONTROL_RD_FIXED         BIT(1)
+#define SGDMA_CONTROL_WR_FIXED         BIT(2)
+
+/* Channel is always 0, so just zero initialize it */
+
+#define SGDMA_CONTROL_HW_OWNED         BIT(7)
+
+/* SGDMA register space */
+struct sgdma_csr {
+       /* bit 0: error
+        * bit 1: eop
+        * bit 2: descriptor completed
+        * bit 3: chain completed
+        * bit 4: busy
+        * remainder reserved
+        */
+       u32     status;
+       u32     pad1[3];
+
+       /* bit 0: interrupt on error
+        * bit 1: interrupt on eop
+        * bit 2: interrupt after every descriptor
+        * bit 3: interrupt after last descrip in a chain
+        * bit 4: global interrupt enable
+        * bit 5: starts descriptor processing
+        * bit 6: stop core on dma error
+        * bit 7: interrupt on max descriptors
+        * bits 8-15: max descriptors to generate interrupt
+        * bit 16: Software reset
+        * bit 17: clears owned by hardware if 0, does not clear otherwise
+        * bit 18: enables descriptor polling mode
+        * bit 19-26: clocks before polling again
+        * bit 27-30: reserved
+        * bit 31: clear interrupt
+        */
+       u32     control;
+       u32     pad2[3];
+       u32     next_descrip;
+       u32     pad3[3];
+};
+
+
+#define SGDMA_STSREG_ERR       BIT(0) /* Error */
+#define SGDMA_STSREG_EOP       BIT(1) /* EOP */
+#define SGDMA_STSREG_DESCRIP   BIT(2) /* Descriptor completed */
+#define SGDMA_STSREG_CHAIN     BIT(3) /* Chain completed */
+#define SGDMA_STSREG_BUSY      BIT(4) /* Controller busy */
+
+#define SGDMA_CTRLREG_IOE      BIT(0) /* Interrupt on error */
+#define SGDMA_CTRLREG_IOEOP    BIT(1) /* Interrupt on EOP */
+#define SGDMA_CTRLREG_IDESCRIP BIT(2) /* Interrupt after every descriptor */
+#define SGDMA_CTRLREG_ILASTD   BIT(3) /* Interrupt after last descriptor */
+#define SGDMA_CTRLREG_INTEN    BIT(4) /* Global Interrupt enable */
+#define SGDMA_CTRLREG_START    BIT(5) /* starts descriptor processing */
+#define SGDMA_CTRLREG_STOPERR  BIT(6) /* stop on dma error */
+#define SGDMA_CTRLREG_INTMAX   BIT(7) /* Interrupt on max descriptors */
+#define SGDMA_CTRLREG_RESET    BIT(16)/* Software reset */
+#define SGDMA_CTRLREG_COBHW    BIT(17)/* Clears owned by hardware */
+#define SGDMA_CTRLREG_POLL     BIT(18)/* enables descriptor polling mode */
+#define SGDMA_CTRLREG_CLRINT   BIT(31)/* Clears interrupt */
+
+#endif /* __ALTERA_SGDMAHW_H__ */
diff --git a/drivers/net/ethernet/altera/altera_tse.h b/drivers/net/ethernet/altera/altera_tse.h
new file mode 100644 (file)
index 0000000..8feeed0
--- /dev/null
@@ -0,0 +1,486 @@
+/* Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ *   Dalon Westergreen
+ *   Thomas Chou
+ *   Ian Abbott
+ *   Yuriy Kozlov
+ *   Tobias Klauser
+ *   Andriy Smolskyy
+ *   Roman Bulgakov
+ *   Dmytro Mytarchuk
+ *   Matthew Gerlach
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ALTERA_TSE_H__
+#define __ALTERA_TSE_H__
+
+#define ALTERA_TSE_RESOURCE_NAME       "altera_tse"
+
+#include <linux/bitops.h>
+#include <linux/if_vlan.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#define ALTERA_TSE_SW_RESET_WATCHDOG_CNTR      10000
+#define ALTERA_TSE_MAC_FIFO_WIDTH              4       /* TX/RX FIFO width in
+                                                        * bytes
+                                                        */
+/* Rx FIFO default settings */
+#define ALTERA_TSE_RX_SECTION_EMPTY    16
+#define ALTERA_TSE_RX_SECTION_FULL     0
+#define ALTERA_TSE_RX_ALMOST_EMPTY     8
+#define ALTERA_TSE_RX_ALMOST_FULL      8
+
+/* Tx FIFO default settings */
+#define ALTERA_TSE_TX_SECTION_EMPTY    16
+#define ALTERA_TSE_TX_SECTION_FULL     0
+#define ALTERA_TSE_TX_ALMOST_EMPTY     8
+#define ALTERA_TSE_TX_ALMOST_FULL      3
+
+/* MAC function configuration default settings */
+#define ALTERA_TSE_TX_IPG_LENGTH       12
+
+#define GET_BIT_VALUE(v, bit)          (((v) >> (bit)) & 0x1)
+
+/* MAC Command_Config Register Bit Definitions
+ */
+#define MAC_CMDCFG_TX_ENA                      BIT(0)
+#define MAC_CMDCFG_RX_ENA                      BIT(1)
+#define MAC_CMDCFG_XON_GEN                     BIT(2)
+#define MAC_CMDCFG_ETH_SPEED                   BIT(3)
+#define MAC_CMDCFG_PROMIS_EN                   BIT(4)
+#define MAC_CMDCFG_PAD_EN                      BIT(5)
+#define MAC_CMDCFG_CRC_FWD                     BIT(6)
+#define MAC_CMDCFG_PAUSE_FWD                   BIT(7)
+#define MAC_CMDCFG_PAUSE_IGNORE                        BIT(8)
+#define MAC_CMDCFG_TX_ADDR_INS                 BIT(9)
+#define MAC_CMDCFG_HD_ENA                      BIT(10)
+#define MAC_CMDCFG_EXCESS_COL                  BIT(11)
+#define MAC_CMDCFG_LATE_COL                    BIT(12)
+#define MAC_CMDCFG_SW_RESET                    BIT(13)
+#define MAC_CMDCFG_MHASH_SEL                   BIT(14)
+#define MAC_CMDCFG_LOOP_ENA                    BIT(15)
+#define MAC_CMDCFG_TX_ADDR_SEL(v)              (((v) & 0x7) << 16)
+#define MAC_CMDCFG_MAGIC_ENA                   BIT(19)
+#define MAC_CMDCFG_SLEEP                       BIT(20)
+#define MAC_CMDCFG_WAKEUP                      BIT(21)
+#define MAC_CMDCFG_XOFF_GEN                    BIT(22)
+#define MAC_CMDCFG_CNTL_FRM_ENA                        BIT(23)
+#define MAC_CMDCFG_NO_LGTH_CHECK               BIT(24)
+#define MAC_CMDCFG_ENA_10                      BIT(25)
+#define MAC_CMDCFG_RX_ERR_DISC                 BIT(26)
+#define MAC_CMDCFG_DISABLE_READ_TIMEOUT                BIT(27)
+#define MAC_CMDCFG_CNT_RESET                   BIT(31)
+
+#define MAC_CMDCFG_TX_ENA_GET(v)               GET_BIT_VALUE(v, 0)
+#define MAC_CMDCFG_RX_ENA_GET(v)               GET_BIT_VALUE(v, 1)
+#define MAC_CMDCFG_XON_GEN_GET(v)              GET_BIT_VALUE(v, 2)
+#define MAC_CMDCFG_ETH_SPEED_GET(v)            GET_BIT_VALUE(v, 3)
+#define MAC_CMDCFG_PROMIS_EN_GET(v)            GET_BIT_VALUE(v, 4)
+#define MAC_CMDCFG_PAD_EN_GET(v)               GET_BIT_VALUE(v, 5)
+#define MAC_CMDCFG_CRC_FWD_GET(v)              GET_BIT_VALUE(v, 6)
+#define MAC_CMDCFG_PAUSE_FWD_GET(v)            GET_BIT_VALUE(v, 7)
+#define MAC_CMDCFG_PAUSE_IGNORE_GET(v)         GET_BIT_VALUE(v, 8)
+#define MAC_CMDCFG_TX_ADDR_INS_GET(v)          GET_BIT_VALUE(v, 9)
+#define MAC_CMDCFG_HD_ENA_GET(v)               GET_BIT_VALUE(v, 10)
+#define MAC_CMDCFG_EXCESS_COL_GET(v)           GET_BIT_VALUE(v, 11)
+#define MAC_CMDCFG_LATE_COL_GET(v)             GET_BIT_VALUE(v, 12)
+#define MAC_CMDCFG_SW_RESET_GET(v)             GET_BIT_VALUE(v, 13)
+#define MAC_CMDCFG_MHASH_SEL_GET(v)            GET_BIT_VALUE(v, 14)
+#define MAC_CMDCFG_LOOP_ENA_GET(v)             GET_BIT_VALUE(v, 15)
+#define MAC_CMDCFG_TX_ADDR_SEL_GET(v)          (((v) >> 16) & 0x7)
+#define MAC_CMDCFG_MAGIC_ENA_GET(v)            GET_BIT_VALUE(v, 19)
+#define MAC_CMDCFG_SLEEP_GET(v)                        GET_BIT_VALUE(v, 20)
+#define MAC_CMDCFG_WAKEUP_GET(v)               GET_BIT_VALUE(v, 21)
+#define MAC_CMDCFG_XOFF_GEN_GET(v)             GET_BIT_VALUE(v, 22)
+#define MAC_CMDCFG_CNTL_FRM_ENA_GET(v)         GET_BIT_VALUE(v, 23)
+#define MAC_CMDCFG_NO_LGTH_CHECK_GET(v)                GET_BIT_VALUE(v, 24)
+#define MAC_CMDCFG_ENA_10_GET(v)               GET_BIT_VALUE(v, 25)
+#define MAC_CMDCFG_RX_ERR_DISC_GET(v)          GET_BIT_VALUE(v, 26)
+#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27)
+#define MAC_CMDCFG_CNT_RESET_GET(v)            GET_BIT_VALUE(v, 31)
+
+/* MDIO registers within MAC register Space
+ */
+struct altera_tse_mdio {
+       u32 control;    /* PHY device operation control register */
+       u32 status;     /* PHY device operation status register */
+       u32 phy_id1;    /* Bits 31:16 of PHY identifier */
+       u32 phy_id2;    /* Bits 15:0 of PHY identifier */
+       u32 auto_negotiation_advertisement;     /* Auto-negotiation
+                                                        * advertisement
+                                                        * register
+                                                        */
+       u32 remote_partner_base_page_ability;
+
+       u32 reg6;
+       u32 reg7;
+       u32 reg8;
+       u32 reg9;
+       u32 rega;
+       u32 regb;
+       u32 regc;
+       u32 regd;
+       u32 rege;
+       u32 regf;
+       u32 reg10;
+       u32 reg11;
+       u32 reg12;
+       u32 reg13;
+       u32 reg14;
+       u32 reg15;
+       u32 reg16;
+       u32 reg17;
+       u32 reg18;
+       u32 reg19;
+       u32 reg1a;
+       u32 reg1b;
+       u32 reg1c;
+       u32 reg1d;
+       u32 reg1e;
+       u32 reg1f;
+};
+
+/* MAC register Space. Note that some of these registers may or may not be
+ * present depending upon options chosen by the user when the core was
+ * configured and built. Please consult the Altera Triple Speed Ethernet User
+ * Guide for details.
+ */
+struct altera_tse_mac {
+       /* Bits 15:0: MegaCore function revision (0x0800). Bit 31:16: Customer
+        * specific revision
+        */
+       u32 megacore_revision;
+       /* Provides a memory location for user applications to test the device
+        * memory operation.
+        */
+       u32 scratch_pad;
+       /* The host processor uses this register to control and configure the
+        * MAC block
+        */
+       u32 command_config;
+       /* 32-bit primary MAC address word 0 bits 0 to 31 of the primary
+        * MAC address
+        */
+       u32 mac_addr_0;
+       /* 32-bit primary MAC address word 1 bits 32 to 47 of the primary
+        * MAC address
+        */
+       u32 mac_addr_1;
+       /* 14-bit maximum frame length. The MAC receive logic */
+       u32 frm_length;
+       /* The pause quanta is used in each pause frame sent to a remote
+        * Ethernet device, in increments of 512 Ethernet bit times
+        */
+       u32 pause_quanta;
+       /* 12-bit receive FIFO section-empty threshold */
+       u32 rx_section_empty;
+       /* 12-bit receive FIFO section-full threshold */
+       u32 rx_section_full;
+       /* 12-bit transmit FIFO section-empty threshold */
+       u32 tx_section_empty;
+       /* 12-bit transmit FIFO section-full threshold */
+       u32 tx_section_full;
+       /* 12-bit receive FIFO almost-empty threshold */
+       u32 rx_almost_empty;
+       /* 12-bit receive FIFO almost-full threshold */
+       u32 rx_almost_full;
+       /* 12-bit transmit FIFO almost-empty threshold */
+       u32 tx_almost_empty;
+       /* 12-bit transmit FIFO almost-full threshold */
+       u32 tx_almost_full;
+       /* MDIO address of PHY Device 0. Bits 0 to 4 hold a 5-bit PHY address */
+       u32 mdio_phy0_addr;
+       /* MDIO address of PHY Device 1. Bits 0 to 4 hold a 5-bit PHY address */
+       u32 mdio_phy1_addr;
+
+       /* Bit[15:0]—16-bit holdoff quanta */
+       u32 holdoff_quant;
+
+       /* only if 100/1000 BaseX PCS, reserved otherwise */
+       u32 reserved1[5];
+
+       /* Minimum IPG between consecutive transmit frame in terms of bytes */
+       u32 tx_ipg_length;
+
+       /* IEEE 802.3 oEntity Managed Object Support */
+
+       /* The MAC addresses */
+       u32 mac_id_1;
+       u32 mac_id_2;
+
+       /* Number of frames transmitted without error including pause frames */
+       u32 frames_transmitted_ok;
+       /* Number of frames received without error including pause frames */
+       u32 frames_received_ok;
+       /* Number of frames received with a CRC error */
+       u32 frames_check_sequence_errors;
+       /* Frame received with an alignment error */
+       u32 alignment_errors;
+       /* Sum of payload and padding octets of frames transmitted without
+        * error
+        */
+       u32 octets_transmitted_ok;
+       /* Sum of payload and padding octets of frames received without error */
+       u32 octets_received_ok;
+
+       /* IEEE 802.3 oPausedEntity Managed Object Support */
+
+       /* Number of transmitted pause frames */
+       u32 tx_pause_mac_ctrl_frames;
+       /* Number of Received pause frames */
+       u32 rx_pause_mac_ctrl_frames;
+
+       /* IETF MIB (MIB-II) Object Support */
+
+       /* Number of frames received with error */
+       u32 if_in_errors;
+       /* Number of frames transmitted with error */
+       u32 if_out_errors;
+       /* Number of valid received unicast frames */
+       u32 if_in_ucast_pkts;
+       /* Number of valid received multicasts frames (without pause) */
+       u32 if_in_multicast_pkts;
+       /* Number of valid received broadcast frames */
+       u32 if_in_broadcast_pkts;
+       u32 if_out_discards;
+       /* The number of valid unicast frames transmitted */
+       u32 if_out_ucast_pkts;
+       /* The number of valid multicast frames transmitted,
+        * excluding pause frames
+        */
+       u32 if_out_multicast_pkts;
+       u32 if_out_broadcast_pkts;
+
+       /* IETF RMON MIB Object Support */
+
+       /* Counts the number of dropped packets due to internal errors
+        * of the MAC client.
+        */
+       u32 ether_stats_drop_events;
+       /* Total number of bytes received. Good and bad frames. */
+       u32 ether_stats_octets;
+       /* Total number of packets received. Counts good and bad packets. */
+       u32 ether_stats_pkts;
+       /* Number of packets received with less than 64 bytes. */
+       u32 ether_stats_undersize_pkts;
+       /* The number of frames received that are longer than the
+        * value configured in the frm_length register
+        */
+       u32 ether_stats_oversize_pkts;
+       /* Number of received packet with 64 bytes */
+       u32 ether_stats_pkts_64_octets;
+       /* Frames (good and bad) with 65 to 127 bytes */
+       u32 ether_stats_pkts_65to127_octets;
+       /* Frames (good and bad) with 128 to 255 bytes */
+       u32 ether_stats_pkts_128to255_octets;
+       /* Frames (good and bad) with 256 to 511 bytes */
+       u32 ether_stats_pkts_256to511_octets;
+       /* Frames (good and bad) with 512 to 1023 bytes */
+       u32 ether_stats_pkts_512to1023_octets;
+       /* Frames (good and bad) with 1024 to 1518 bytes */
+       u32 ether_stats_pkts_1024to1518_octets;
+
+       /* Any frame length from 1519 to the maximum length configured in the
+        * frm_length register, if it is greater than 1518
+        */
+       u32 ether_stats_pkts_1519tox_octets;
+       /* Too long frames with CRC error */
+       u32 ether_stats_jabbers;
+       /* Too short frames with CRC error */
+       u32 ether_stats_fragments;
+
+       u32 reserved2;
+
+       /* FIFO control register */
+       u32 tx_cmd_stat;
+       u32 rx_cmd_stat;
+
+       /* Extended Statistics Counters */
+       u32 msb_octets_transmitted_ok;
+       u32 msb_octets_received_ok;
+       u32 msb_ether_stats_octets;
+
+       u32 reserved3;
+
+       /* Multicast address resolution table, mapped in the controller address
+        * space
+        */
+       u32 hash_table[64];
+
+       /* Registers 0 to 31 within PHY device 0/1 connected to the MDIO PHY
+        * management interface
+        */
+       struct altera_tse_mdio mdio_phy0;
+       struct altera_tse_mdio mdio_phy1;
+
+       /* 4 Supplemental MAC Addresses */
+       u32 supp_mac_addr_0_0;
+       u32 supp_mac_addr_0_1;
+       u32 supp_mac_addr_1_0;
+       u32 supp_mac_addr_1_1;
+       u32 supp_mac_addr_2_0;
+       u32 supp_mac_addr_2_1;
+       u32 supp_mac_addr_3_0;
+       u32 supp_mac_addr_3_1;
+
+       u32 reserved4[8];
+
+       /* IEEE 1588v2 Feature */
+       u32 tx_period;
+       u32 tx_adjust_fns;
+       u32 tx_adjust_ns;
+       u32 rx_period;
+       u32 rx_adjust_fns;
+       u32 rx_adjust_ns;
+
+       u32 reserved5[42];
+};
+
+/* Transmit and Receive Command Registers Bit Definitions
+ */
+#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC                BIT(17)
+#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16      BIT(18)
+#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16      BIT(25)
+
+/* Wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct tse_buffer {
+       struct list_head lh;
+       struct sk_buff *skb;
+       dma_addr_t dma_addr;
+       u32 len;
+       int mapped_as_page;
+};
+
+struct altera_tse_private;
+
+#define ALTERA_DTYPE_SGDMA 1
+#define ALTERA_DTYPE_MSGDMA 2
+
+/* standard DMA interface for SGDMA and MSGDMA */
+struct altera_dmaops {
+       int altera_dtype;
+       int dmamask;
+       void (*reset_dma)(struct altera_tse_private *);
+       void (*enable_txirq)(struct altera_tse_private *);
+       void (*enable_rxirq)(struct altera_tse_private *);
+       void (*disable_txirq)(struct altera_tse_private *);
+       void (*disable_rxirq)(struct altera_tse_private *);
+       void (*clear_txirq)(struct altera_tse_private *);
+       void (*clear_rxirq)(struct altera_tse_private *);
+       int (*tx_buffer)(struct altera_tse_private *, struct tse_buffer *);
+       u32 (*tx_completions)(struct altera_tse_private *);
+       int (*add_rx_desc)(struct altera_tse_private *, struct tse_buffer *);
+       u32 (*get_rx_status)(struct altera_tse_private *);
+       int (*init_dma)(struct altera_tse_private *);
+       void (*uninit_dma)(struct altera_tse_private *);
+};
+
+/* This structure is private to each device.
+ */
+struct altera_tse_private {
+       struct net_device *dev;
+       struct device *device;
+       struct napi_struct napi;
+
+       /* MAC address space */
+       struct altera_tse_mac __iomem *mac_dev;
+
+       /* TSE Revision */
+       u32     revision;
+
+       /* mSGDMA Rx Dispatcher address space */
+       void __iomem *rx_dma_csr;
+       void __iomem *rx_dma_desc;
+       void __iomem *rx_dma_resp;
+
+       /* mSGDMA Tx Dispatcher address space */
+       void __iomem *tx_dma_csr;
+       void __iomem *tx_dma_desc;
+
+       /* Rx buffers queue */
+       struct tse_buffer *rx_ring;
+       u32 rx_cons;
+       u32 rx_prod;
+       u32 rx_ring_size;
+       u32 rx_dma_buf_sz;
+
+       /* Tx ring buffer */
+       struct tse_buffer *tx_ring;
+       u32 tx_prod;
+       u32 tx_cons;
+       u32 tx_ring_size;
+
+       /* Interrupts */
+       u32 tx_irq;
+       u32 rx_irq;
+
+       /* RX/TX MAC FIFO configs */
+       u32 tx_fifo_depth;
+       u32 rx_fifo_depth;
+       u32 max_mtu;
+
+       /* Hash filter settings */
+       u32 hash_filter;
+       u32 added_unicast;
+
+       /* Descriptor memory info for managing SGDMA */
+       u32 txdescmem;
+       u32 rxdescmem;
+       dma_addr_t rxdescmem_busaddr;
+       dma_addr_t txdescmem_busaddr;
+       u32 txctrlreg;
+       u32 rxctrlreg;
+       dma_addr_t rxdescphys;
+       dma_addr_t txdescphys;
+
+       struct list_head txlisthd;
+       struct list_head rxlisthd;
+
+       /* MAC command_config register protection */
+       spinlock_t mac_cfg_lock;
+       /* Tx path protection */
+       spinlock_t tx_lock;
+       /* Rx DMA & interrupt control protection */
+       spinlock_t rxdma_irq_lock;
+
+       /* PHY */
+       int phy_addr;           /* PHY's MDIO address, -1 for autodetection */
+       phy_interface_t phy_iface;
+       struct mii_bus *mdio;
+       struct phy_device *phydev;
+       int oldspeed;
+       int oldduplex;
+       int oldlink;
+
+       /* ethtool msglvl option */
+       u32 msg_enable;
+
+       struct altera_dmaops *dmaops;
+};
+
+/* Function prototypes
+ */
+void altera_tse_set_ethtool_ops(struct net_device *);
+
+#endif /* __ALTERA_TSE_H__ */
diff --git a/drivers/net/ethernet/altera/altera_tse_ethtool.c b/drivers/net/ethernet/altera/altera_tse_ethtool.c
new file mode 100644 (file)
index 0000000..319ca74
--- /dev/null
@@ -0,0 +1,235 @@
+/* Ethtool support for Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ *   Dalon Westergreen
+ *   Thomas Chou
+ *   Ian Abbott
+ *   Yuriy Kozlov
+ *   Tobias Klauser
+ *   Andriy Smolskyy
+ *   Roman Bulgakov
+ *   Dmytro Mytarchuk
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "altera_tse.h"
+
+#define TSE_STATS_LEN  31
+#define TSE_NUM_REGS   128
+
+static char const stat_gstrings[][ETH_GSTRING_LEN] = {
+       "tx_packets",
+       "rx_packets",
+       "rx_crc_errors",
+       "rx_align_errors",
+       "tx_bytes",
+       "rx_bytes",
+       "tx_pause",
+       "rx_pause",
+       "rx_errors",
+       "tx_errors",
+       "rx_unicast",
+       "rx_multicast",
+       "rx_broadcast",
+       "tx_discards",
+       "tx_unicast",
+       "tx_multicast",
+       "tx_broadcast",
+       "ether_drops",
+       "rx_total_bytes",
+       "rx_total_packets",
+       "rx_undersize",
+       "rx_oversize",
+       "rx_64_bytes",
+       "rx_65_127_bytes",
+       "rx_128_255_bytes",
+       "rx_256_511_bytes",
+       "rx_512_1023_bytes",
+       "rx_1024_1518_bytes",
+       "rx_gte_1519_bytes",
+       "rx_jabbers",
+       "rx_runts",
+};
+
+static void tse_get_drvinfo(struct net_device *dev,
+                           struct ethtool_drvinfo *info)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       u32 rev = ioread32(&priv->mac_dev->megacore_revision);
+
+       strcpy(info->driver, "Altera TSE MAC IP Driver");
+       strcpy(info->version, "v8.0");
+       snprintf(info->fw_version, ETHTOOL_FWVERS_LEN, "v%d.%d",
+                rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
+       sprintf(info->bus_info, "platform");
+}
+
+/* Fill in a buffer with the strings which correspond to the
+ * stats
+ */
+static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+       memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);
+}
+
+static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+                          u64 *buf)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+       u64 ext;
+
+       buf[0] = ioread32(&mac->frames_transmitted_ok);
+       buf[1] = ioread32(&mac->frames_received_ok);
+       buf[2] = ioread32(&mac->frames_check_sequence_errors);
+       buf[3] = ioread32(&mac->alignment_errors);
+
+       /* Extended aOctetsTransmittedOK counter */
+       ext = (u64) ioread32(&mac->msb_octets_transmitted_ok) << 32;
+       ext |= ioread32(&mac->octets_transmitted_ok);
+       buf[4] = ext;
+
+       /* Extended aOctetsReceivedOK counter */
+       ext = (u64) ioread32(&mac->msb_octets_received_ok) << 32;
+       ext |= ioread32(&mac->octets_received_ok);
+       buf[5] = ext;
+
+       buf[6] = ioread32(&mac->tx_pause_mac_ctrl_frames);
+       buf[7] = ioread32(&mac->rx_pause_mac_ctrl_frames);
+       buf[8] = ioread32(&mac->if_in_errors);
+       buf[9] = ioread32(&mac->if_out_errors);
+       buf[10] = ioread32(&mac->if_in_ucast_pkts);
+       buf[11] = ioread32(&mac->if_in_multicast_pkts);
+       buf[12] = ioread32(&mac->if_in_broadcast_pkts);
+       buf[13] = ioread32(&mac->if_out_discards);
+       buf[14] = ioread32(&mac->if_out_ucast_pkts);
+       buf[15] = ioread32(&mac->if_out_multicast_pkts);
+       buf[16] = ioread32(&mac->if_out_broadcast_pkts);
+       buf[17] = ioread32(&mac->ether_stats_drop_events);
+
+       /* Extended etherStatsOctets counter */
+       ext = (u64) ioread32(&mac->msb_ether_stats_octets) << 32;
+       ext |= ioread32(&mac->ether_stats_octets);
+       buf[18] = ext;
+
+       buf[19] = ioread32(&mac->ether_stats_pkts);
+       buf[20] = ioread32(&mac->ether_stats_undersize_pkts);
+       buf[21] = ioread32(&mac->ether_stats_oversize_pkts);
+       buf[22] = ioread32(&mac->ether_stats_pkts_64_octets);
+       buf[23] = ioread32(&mac->ether_stats_pkts_65to127_octets);
+       buf[24] = ioread32(&mac->ether_stats_pkts_128to255_octets);
+       buf[25] = ioread32(&mac->ether_stats_pkts_256to511_octets);
+       buf[26] = ioread32(&mac->ether_stats_pkts_512to1023_octets);
+       buf[27] = ioread32(&mac->ether_stats_pkts_1024to1518_octets);
+       buf[28] = ioread32(&mac->ether_stats_pkts_1519tox_octets);
+       buf[29] = ioread32(&mac->ether_stats_jabbers);
+       buf[30] = ioread32(&mac->ether_stats_fragments);
+}
+
+static int tse_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return TSE_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static u32 tse_get_msglevel(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}
+
+static void tse_set_msglevel(struct net_device *dev, uint32_t data)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       priv->msg_enable = data;
+}
+
+static int tse_reglen(struct net_device *dev)
+{
+       return TSE_NUM_REGS * sizeof(u32);
+}
+
+static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                        void *regbuf)
+{
+       int i;
+       struct altera_tse_private *priv = netdev_priv(dev);
+       u32 *tse_mac_regs = (u32 *)priv->mac_dev;
+       u32 *buf = regbuf;
+
+       /* Set version to a known value, so ethtool knows
+        * how to do any special formatting of this data.
+        * This version number will need to change if and
+        * when this register table is changed.
+        */
+
+       regs->version = 1;
+
+       for (i = 0; i < TSE_NUM_REGS; i++)
+               buf[i] = ioread32(&tse_mac_regs[i]);
+}
+
+static int tse_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+
+       if (phydev == NULL)
+               return -ENODEV;
+
+       return phy_ethtool_gset(phydev, cmd);
+}
+
+static int tse_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+
+       if (phydev == NULL)
+               return -ENODEV;
+
+       return phy_ethtool_sset(phydev, cmd);
+}
+
+static const struct ethtool_ops tse_ethtool_ops = {
+       .get_drvinfo = tse_get_drvinfo,
+       .get_regs_len = tse_reglen,
+       .get_regs = tse_get_regs,
+       .get_link = ethtool_op_get_link,
+       .get_settings = tse_get_settings,
+       .set_settings = tse_set_settings,
+       .get_strings = tse_gstrings,
+       .get_sset_count = tse_sset_count,
+       .get_ethtool_stats = tse_fill_stats,
+       .get_msglevel = tse_get_msglevel,
+       .set_msglevel = tse_set_msglevel,
+};
+
+void altera_tse_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &tse_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c
new file mode 100644 (file)
index 0000000..c70a29e
--- /dev/null
@@ -0,0 +1,1543 @@
+/* Altera Triple-Speed Ethernet MAC driver
+ * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
+ *
+ * Contributors:
+ *   Dalon Westergreen
+ *   Thomas Chou
+ *   Ian Abbott
+ *   Yuriy Kozlov
+ *   Tobias Klauser
+ *   Andriy Smolskyy
+ *   Roman Bulgakov
+ *   Dmytro Mytarchuk
+ *   Matthew Gerlach
+ *
+ * Original driver contributed by SLS.
+ * Major updates contributed by GlobalLogic
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/skbuff.h>
+#include <asm/cacheflush.h>
+
+#include "altera_utils.h"
+#include "altera_tse.h"
+#include "altera_sgdma.h"
+#include "altera_msgdma.h"
+
+static atomic_t instance_count = ATOMIC_INIT(~0);
+/* Module parameters */
+static int debug = -1;
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
+
+static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+                                       NETIF_MSG_LINK | NETIF_MSG_IFUP |
+                                       NETIF_MSG_IFDOWN);
+
+#define RX_DESCRIPTORS 64
+static int dma_rx_num = RX_DESCRIPTORS;
+module_param(dma_rx_num, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_rx_num, "Number of descriptors in the RX list");
+
+#define TX_DESCRIPTORS 64
+static int dma_tx_num = TX_DESCRIPTORS;
+module_param(dma_tx_num, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_tx_num, "Number of descriptors in the TX list");
+
+
+#define POLL_PHY (-1)
+
+/* Make sure DMA buffer size is larger than the max frame size
+ * plus some alignment offset and a VLAN header. If the max frame size is
+ * 1518, a VLAN header would be additional 4 bytes and additional
+ * headroom for alignment is 2 bytes, 2048 is just fine.
+ */
+#define ALTERA_RXDMABUFFER_SIZE        2048
+
+/* Allow network stack to resume queueing packets after we've
+ * finished transmitting at least 1/4 of the packets in the queue.
+ */
+#define TSE_TX_THRESH(x)       (x->tx_ring_size / 4)
+
+#define TXQUEUESTOP_THRESHHOLD 2
+
+static struct of_device_id altera_tse_ids[];
+
+static inline u32 tse_tx_avail(struct altera_tse_private *priv)
+{
+       return priv->tx_cons + priv->tx_ring_size - priv->tx_prod - 1;
+}
+
+/* MDIO specific functions
+ */
+static int altera_tse_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv;
+       unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0;
+       u32 data;
+
+       /* set MDIO address */
+       iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr);
+
+       /* get the data */
+       data = ioread32(&mdio_regs[regnum]) & 0xffff;
+       return data;
+}
+
+static int altera_tse_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+                                u16 value)
+{
+       struct altera_tse_mac *mac = (struct altera_tse_mac *)bus->priv;
+       unsigned int *mdio_regs = (unsigned int *)&mac->mdio_phy0;
+
+       /* set MDIO address */
+       iowrite32((mii_id & 0x1f), &mac->mdio_phy0_addr);
+
+       /* write the data */
+       iowrite32((u32) value, &mdio_regs[regnum]);
+       return 0;
+}
+
+static int altera_tse_mdio_create(struct net_device *dev, unsigned int id)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       int ret;
+       int i;
+       struct device_node *mdio_node = NULL;
+       struct mii_bus *mdio = NULL;
+       struct device_node *child_node = NULL;
+
+       for_each_child_of_node(priv->device->of_node, child_node) {
+               if (of_device_is_compatible(child_node, "altr,tse-mdio")) {
+                       mdio_node = child_node;
+                       break;
+               }
+       }
+
+       if (mdio_node) {
+               netdev_dbg(dev, "FOUND MDIO subnode\n");
+       } else {
+               netdev_dbg(dev, "NO MDIO subnode\n");
+               return 0;
+       }
+
+       mdio = mdiobus_alloc();
+       if (mdio == NULL) {
+               netdev_err(dev, "Error allocating MDIO bus\n");
+               return -ENOMEM;
+       }
+
+       mdio->name = ALTERA_TSE_RESOURCE_NAME;
+       mdio->read = &altera_tse_mdio_read;
+       mdio->write = &altera_tse_mdio_write;
+       snprintf(mdio->id, MII_BUS_ID_SIZE, "%s-%u", mdio->name, id);
+
+       mdio->irq = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
+       if (mdio->irq == NULL) {
+               ret = -ENOMEM;
+               goto out_free_mdio;
+       }
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               mdio->irq[i] = PHY_POLL;
+
+       mdio->priv = priv->mac_dev;
+       mdio->parent = priv->device;
+
+       ret = of_mdiobus_register(mdio, mdio_node);
+       if (ret != 0) {
+               netdev_err(dev, "Cannot register MDIO bus %s\n",
+                          mdio->id);
+               goto out_free_mdio_irq;
+       }
+
+       if (netif_msg_drv(priv))
+               netdev_info(dev, "MDIO bus %s: created\n", mdio->id);
+
+       priv->mdio = mdio;
+       return 0;
+out_free_mdio_irq:
+       kfree(mdio->irq);
+out_free_mdio:
+       mdiobus_free(mdio);
+       mdio = NULL;
+       return ret;
+}
+
+static void altera_tse_mdio_destroy(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+
+       if (priv->mdio == NULL)
+               return;
+
+       if (netif_msg_drv(priv))
+               netdev_info(dev, "MDIO bus %s: removed\n",
+                           priv->mdio->id);
+
+       mdiobus_unregister(priv->mdio);
+       kfree(priv->mdio->irq);
+       mdiobus_free(priv->mdio);
+       priv->mdio = NULL;
+}
+
+static int tse_init_rx_buffer(struct altera_tse_private *priv,
+                             struct tse_buffer *rxbuffer, int len)
+{
+       rxbuffer->skb = netdev_alloc_skb_ip_align(priv->dev, len);
+       if (!rxbuffer->skb)
+               return -ENOMEM;
+
+       rxbuffer->dma_addr = dma_map_single(priv->device, rxbuffer->skb->data,
+                                               len,
+                                               DMA_FROM_DEVICE);
+
+       if (dma_mapping_error(priv->device, rxbuffer->dma_addr)) {
+               netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+               dev_kfree_skb_any(rxbuffer->skb);
+               return -EINVAL;
+       }
+       rxbuffer->len = len;
+       return 0;
+}
+
+static void tse_free_rx_buffer(struct altera_tse_private *priv,
+                              struct tse_buffer *rxbuffer)
+{
+       struct sk_buff *skb = rxbuffer->skb;
+       dma_addr_t dma_addr = rxbuffer->dma_addr;
+
+       if (skb != NULL) {
+               if (dma_addr)
+                       dma_unmap_single(priv->device, dma_addr,
+                                        rxbuffer->len,
+                                        DMA_FROM_DEVICE);
+               dev_kfree_skb_any(skb);
+               rxbuffer->skb = NULL;
+               rxbuffer->dma_addr = 0;
+       }
+}
+
+/* Unmap and free Tx buffer resources
+ */
+static void tse_free_tx_buffer(struct altera_tse_private *priv,
+                              struct tse_buffer *buffer)
+{
+       if (buffer->dma_addr) {
+               if (buffer->mapped_as_page)
+                       dma_unmap_page(priv->device, buffer->dma_addr,
+                                      buffer->len, DMA_TO_DEVICE);
+               else
+                       dma_unmap_single(priv->device, buffer->dma_addr,
+                                        buffer->len, DMA_TO_DEVICE);
+               buffer->dma_addr = 0;
+       }
+       if (buffer->skb) {
+               dev_kfree_skb_any(buffer->skb);
+               buffer->skb = NULL;
+       }
+}
+
+static int alloc_init_skbufs(struct altera_tse_private *priv)
+{
+       unsigned int rx_descs = priv->rx_ring_size;
+       unsigned int tx_descs = priv->tx_ring_size;
+       int ret = -ENOMEM;
+       int i;
+
+       /* Create Rx ring buffer */
+       priv->rx_ring = kcalloc(rx_descs, sizeof(struct tse_buffer),
+                               GFP_KERNEL);
+       if (!priv->rx_ring)
+               goto err_rx_ring;
+
+       /* Create Tx ring buffer */
+       priv->tx_ring = kcalloc(tx_descs, sizeof(struct tse_buffer),
+                               GFP_KERNEL);
+       if (!priv->tx_ring)
+               goto err_tx_ring;
+
+       priv->tx_cons = 0;
+       priv->tx_prod = 0;
+
+       /* Init Rx ring */
+       for (i = 0; i < rx_descs; i++) {
+               ret = tse_init_rx_buffer(priv, &priv->rx_ring[i],
+                                        priv->rx_dma_buf_sz);
+               if (ret)
+                       goto err_init_rx_buffers;
+       }
+
+       priv->rx_cons = 0;
+       priv->rx_prod = 0;
+
+       return 0;
+err_init_rx_buffers:
+       while (--i >= 0)
+               tse_free_rx_buffer(priv, &priv->rx_ring[i]);
+       kfree(priv->tx_ring);
+err_tx_ring:
+       kfree(priv->rx_ring);
+err_rx_ring:
+       return ret;
+}
+
+static void free_skbufs(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       unsigned int rx_descs = priv->rx_ring_size;
+       unsigned int tx_descs = priv->tx_ring_size;
+       int i;
+
+       /* Release the DMA TX/RX socket buffers */
+       for (i = 0; i < rx_descs; i++)
+               tse_free_rx_buffer(priv, &priv->rx_ring[i]);
+       for (i = 0; i < tx_descs; i++)
+               tse_free_tx_buffer(priv, &priv->tx_ring[i]);
+
+
+       kfree(priv->tx_ring);
+}
+
+/* Reallocate the skb for the reception process
+ */
+static inline void tse_rx_refill(struct altera_tse_private *priv)
+{
+       unsigned int rxsize = priv->rx_ring_size;
+       unsigned int entry;
+       int ret;
+
+       for (; priv->rx_cons - priv->rx_prod > 0;
+                       priv->rx_prod++) {
+               entry = priv->rx_prod % rxsize;
+               if (likely(priv->rx_ring[entry].skb == NULL)) {
+                       ret = tse_init_rx_buffer(priv, &priv->rx_ring[entry],
+                               priv->rx_dma_buf_sz);
+                       if (unlikely(ret != 0))
+                               break;
+                       priv->dmaops->add_rx_desc(priv, &priv->rx_ring[entry]);
+               }
+       }
+}
+
+/* Pull out the VLAN tag and fix up the packet
+ */
+static inline void tse_rx_vlan(struct net_device *dev, struct sk_buff *skb)
+{
+       struct ethhdr *eth_hdr;
+       u16 vid;
+       if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
+           !__vlan_get_tag(skb, &vid)) {
+               eth_hdr = (struct ethhdr *)skb->data;
+               memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+               skb_pull(skb, VLAN_HLEN);
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
+       }
+}
+
+/* Receive a packet: retrieve and pass over to upper levels
+ */
+static int tse_rx(struct altera_tse_private *priv, int limit)
+{
+       unsigned int count = 0;
+       unsigned int next_entry;
+       struct sk_buff *skb;
+       unsigned int entry = priv->rx_cons % priv->rx_ring_size;
+       u32 rxstatus;
+       u16 pktlength;
+       u16 pktstatus;
+
+       while ((rxstatus = priv->dmaops->get_rx_status(priv)) != 0) {
+               pktstatus = rxstatus >> 16;
+               pktlength = rxstatus & 0xffff;
+
+               if ((pktstatus & 0xFF) || (pktlength == 0))
+                       netdev_err(priv->dev,
+                                  "RCV pktstatus %08X pktlength %08X\n",
+                                  pktstatus, pktlength);
+
+               count++;
+               next_entry = (++priv->rx_cons) % priv->rx_ring_size;
+
+               skb = priv->rx_ring[entry].skb;
+               if (unlikely(!skb)) {
+                       netdev_err(priv->dev,
+                                  "%s: Inconsistent Rx descriptor chain\n",
+                                  __func__);
+                       priv->dev->stats.rx_dropped++;
+                       break;
+               }
+               priv->rx_ring[entry].skb = NULL;
+
+               skb_put(skb, pktlength);
+
+               /* make cache consistent with receive packet buffer */
+               dma_sync_single_for_cpu(priv->device,
+                                       priv->rx_ring[entry].dma_addr,
+                                       priv->rx_ring[entry].len,
+                                       DMA_FROM_DEVICE);
+
+               dma_unmap_single(priv->device, priv->rx_ring[entry].dma_addr,
+                                priv->rx_ring[entry].len, DMA_FROM_DEVICE);
+
+               if (netif_msg_pktdata(priv)) {
+                       netdev_info(priv->dev, "frame received %d bytes\n",
+                                   pktlength);
+                       print_hex_dump(KERN_ERR, "data: ", DUMP_PREFIX_OFFSET,
+                                      16, 1, skb->data, pktlength, true);
+               }
+
+               tse_rx_vlan(priv->dev, skb);
+
+               skb->protocol = eth_type_trans(skb, priv->dev);
+               skb_checksum_none_assert(skb);
+
+               napi_gro_receive(&priv->napi, skb);
+
+               priv->dev->stats.rx_packets++;
+               priv->dev->stats.rx_bytes += pktlength;
+
+               entry = next_entry;
+       }
+
+       tse_rx_refill(priv);
+       return count;
+}
+
+/* Reclaim resources after transmission completes
+ */
+static int tse_tx_complete(struct altera_tse_private *priv)
+{
+       unsigned int txsize = priv->tx_ring_size;
+       u32 ready;
+       unsigned int entry;
+       struct tse_buffer *tx_buff;
+       int txcomplete = 0;
+
+       spin_lock(&priv->tx_lock);
+
+       ready = priv->dmaops->tx_completions(priv);
+
+       /* Free sent buffers */
+       while (ready && (priv->tx_cons != priv->tx_prod)) {
+               entry = priv->tx_cons % txsize;
+               tx_buff = &priv->tx_ring[entry];
+
+               if (netif_msg_tx_done(priv))
+                       netdev_dbg(priv->dev, "%s: curr %d, dirty %d\n",
+                                  __func__, priv->tx_prod, priv->tx_cons);
+
+               if (likely(tx_buff->skb))
+                       priv->dev->stats.tx_packets++;
+
+               tse_free_tx_buffer(priv, tx_buff);
+               priv->tx_cons++;
+
+               txcomplete++;
+               ready--;
+       }
+
+       if (unlikely(netif_queue_stopped(priv->dev) &&
+                    tse_tx_avail(priv) > TSE_TX_THRESH(priv))) {
+               netif_tx_lock(priv->dev);
+               if (netif_queue_stopped(priv->dev) &&
+                   tse_tx_avail(priv) > TSE_TX_THRESH(priv)) {
+                       if (netif_msg_tx_done(priv))
+                               netdev_dbg(priv->dev, "%s: restart transmit\n",
+                                          __func__);
+                       netif_wake_queue(priv->dev);
+               }
+               netif_tx_unlock(priv->dev);
+       }
+
+       spin_unlock(&priv->tx_lock);
+       return txcomplete;
+}
+
+/* NAPI polling function
+ */
+static int tse_poll(struct napi_struct *napi, int budget)
+{
+       struct altera_tse_private *priv =
+                       container_of(napi, struct altera_tse_private, napi);
+       int rxcomplete = 0;
+       int txcomplete = 0;
+       unsigned long int flags;
+
+       txcomplete = tse_tx_complete(priv);
+
+       rxcomplete = tse_rx(priv, budget);
+
+       if (rxcomplete >= budget || txcomplete > 0)
+               return rxcomplete;
+
+       napi_gro_flush(napi, false);
+       __napi_complete(napi);
+
+       netdev_dbg(priv->dev,
+                  "NAPI Complete, did %d packets with budget %d\n",
+                  txcomplete+rxcomplete, budget);
+
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       priv->dmaops->enable_rxirq(priv);
+       priv->dmaops->enable_txirq(priv);
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+       return rxcomplete + txcomplete;
+}
+
+/* DMA TX & RX FIFO interrupt routing
+ */
+static irqreturn_t altera_isr(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct altera_tse_private *priv;
+       unsigned long int flags;
+
+
+       if (unlikely(!dev)) {
+               pr_err("%s: invalid dev pointer\n", __func__);
+               return IRQ_NONE;
+       }
+       priv = netdev_priv(dev);
+
+       /* turn off desc irqs and enable napi rx */
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+
+       if (likely(napi_schedule_prep(&priv->napi))) {
+               priv->dmaops->disable_rxirq(priv);
+               priv->dmaops->disable_txirq(priv);
+               __napi_schedule(&priv->napi);
+       }
+
+       /* reset IRQs */
+       priv->dmaops->clear_rxirq(priv);
+       priv->dmaops->clear_txirq(priv);
+
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+/* Transmit a packet (called by the kernel). Dispatches
+ * either the SGDMA method for transmitting or the
+ * MSGDMA method, assumes no scatter/gather support,
+ * implying an assumption that there's only one
+ * physically contiguous fragment starting at
+ * skb->data, for length of skb_headlen(skb).
+ */
+static int tse_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       unsigned int txsize = priv->tx_ring_size;
+       unsigned int entry;
+       struct tse_buffer *buffer = NULL;
+       int nfrags = skb_shinfo(skb)->nr_frags;
+       unsigned int nopaged_len = skb_headlen(skb);
+       enum netdev_tx ret = NETDEV_TX_OK;
+       dma_addr_t dma_addr;
+       int txcomplete = 0;
+
+       spin_lock_bh(&priv->tx_lock);
+
+       if (unlikely(tse_tx_avail(priv) < nfrags + 1)) {
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+                       /* This is a hard error, log it. */
+                       netdev_err(priv->dev,
+                                  "%s: Tx list full when queue awake\n",
+                                  __func__);
+               }
+               ret = NETDEV_TX_BUSY;
+               goto out;
+       }
+
+       /* Map the first skb fragment */
+       entry = priv->tx_prod % txsize;
+       buffer = &priv->tx_ring[entry];
+
+       dma_addr = dma_map_single(priv->device, skb->data, nopaged_len,
+                                 DMA_TO_DEVICE);
+       if (dma_mapping_error(priv->device, dma_addr)) {
+               netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);
+               ret = NETDEV_TX_OK;
+               goto out;
+       }
+
+       buffer->skb = skb;
+       buffer->dma_addr = dma_addr;
+       buffer->len = nopaged_len;
+
+       /* Push data out of the cache hierarchy into main memory */
+       dma_sync_single_for_device(priv->device, buffer->dma_addr,
+                                  buffer->len, DMA_TO_DEVICE);
+
+       txcomplete = priv->dmaops->tx_buffer(priv, buffer);
+
+       skb_tx_timestamp(skb);
+
+       priv->tx_prod++;
+       dev->stats.tx_bytes += skb->len;
+
+       if (unlikely(tse_tx_avail(priv) <= TXQUEUESTOP_THRESHHOLD)) {
+               if (netif_msg_hw(priv))
+                       netdev_dbg(priv->dev, "%s: stop transmitted packets\n",
+                                  __func__);
+               netif_stop_queue(dev);
+       }
+
+out:
+       spin_unlock_bh(&priv->tx_lock);
+
+       return ret;
+}
+
+/* Called every time the controller might need to be made
+ * aware of new link state.  The PHY code conveys this
+ * information through variables in the phydev structure, and this
+ * function converts those variables into the appropriate
+ * register values, and can bring down the device if needed.
+ */
+static void altera_tse_adjust_link(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       int new_state = 0;
+
+       /* only change config if there is a link */
+       spin_lock(&priv->mac_cfg_lock);
+       if (phydev->link) {
+               /* Read old config */
+               u32 cfg_reg = ioread32(&priv->mac_dev->command_config);
+
+               /* Check duplex */
+               if (phydev->duplex != priv->oldduplex) {
+                       new_state = 1;
+                       if (!(phydev->duplex))
+                               cfg_reg |= MAC_CMDCFG_HD_ENA;
+                       else
+                               cfg_reg &= ~MAC_CMDCFG_HD_ENA;
+
+                       netdev_dbg(priv->dev, "%s: Link duplex = 0x%x\n",
+                                  dev->name, phydev->duplex);
+
+                       priv->oldduplex = phydev->duplex;
+               }
+
+               /* Check speed */
+               if (phydev->speed != priv->oldspeed) {
+                       new_state = 1;
+                       switch (phydev->speed) {
+                       case 1000:
+                               cfg_reg |= MAC_CMDCFG_ETH_SPEED;
+                               cfg_reg &= ~MAC_CMDCFG_ENA_10;
+                               break;
+                       case 100:
+                               cfg_reg &= ~MAC_CMDCFG_ETH_SPEED;
+                               cfg_reg &= ~MAC_CMDCFG_ENA_10;
+                               break;
+                       case 10:
+                               cfg_reg &= ~MAC_CMDCFG_ETH_SPEED;
+                               cfg_reg |= MAC_CMDCFG_ENA_10;
+                               break;
+                       default:
+                               if (netif_msg_link(priv))
+                                       netdev_warn(dev, "Speed (%d) is not 10/100/1000!\n",
+                                                   phydev->speed);
+                               break;
+                       }
+                       priv->oldspeed = phydev->speed;
+               }
+               iowrite32(cfg_reg, &priv->mac_dev->command_config);
+
+               if (!priv->oldlink) {
+                       new_state = 1;
+                       priv->oldlink = 1;
+               }
+       } else if (priv->oldlink) {
+               new_state = 1;
+               priv->oldlink = 0;
+               priv->oldspeed = 0;
+               priv->oldduplex = -1;
+       }
+
+       if (new_state && netif_msg_link(priv))
+               phy_print_status(phydev);
+
+       spin_unlock(&priv->mac_cfg_lock);
+}
+static struct phy_device *connect_local_phy(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       char phy_id_fmt[MII_BUS_ID_SIZE + 3];
+       int ret;
+
+       if (priv->phy_addr != POLL_PHY) {
+               snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT,
+                        priv->mdio->id, priv->phy_addr);
+
+               netdev_dbg(dev, "trying to attach to %s\n", phy_id_fmt);
+
+               phydev = phy_connect(dev, phy_id_fmt, &altera_tse_adjust_link,
+                                    priv->phy_iface);
+               if (IS_ERR(phydev))
+                       netdev_err(dev, "Could not attach to PHY\n");
+
+       } else {
+               phydev = phy_find_first(priv->mdio);
+               if (phydev == NULL) {
+                       netdev_err(dev, "No PHY found\n");
+                       return phydev;
+               }
+
+               ret = phy_connect_direct(dev, phydev, &altera_tse_adjust_link,
+                               priv->phy_iface);
+               if (ret != 0) {
+                       netdev_err(dev, "Could not attach to PHY\n");
+                       phydev = NULL;
+               }
+       }
+       return phydev;
+}
+
+/* Initialize driver's PHY state, and attach to the PHY
+ */
+static int init_phy(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct phy_device *phydev;
+       struct device_node *phynode;
+
+       priv->oldlink = 0;
+       priv->oldspeed = 0;
+       priv->oldduplex = -1;
+
+       phynode = of_parse_phandle(priv->device->of_node, "phy-handle", 0);
+
+       if (!phynode) {
+               netdev_dbg(dev, "no phy-handle found\n");
+               if (!priv->mdio) {
+                       netdev_err(dev,
+                                  "No phy-handle nor local mdio specified\n");
+                       return -ENODEV;
+               }
+               phydev = connect_local_phy(dev);
+       } else {
+               netdev_dbg(dev, "phy-handle found\n");
+               phydev = of_phy_connect(dev, phynode,
+                       &altera_tse_adjust_link, 0, priv->phy_iface);
+       }
+
+       if (!phydev) {
+               netdev_err(dev, "Could not find the PHY\n");
+               return -ENODEV;
+       }
+
+       /* Stop Advertising 1000BASE Capability if interface is not GMII
+        * Note: Checkpatch throws CHECKs for the camel case defines below,
+        * it's ok to ignore.
+        */
+       if ((priv->phy_iface == PHY_INTERFACE_MODE_MII) ||
+           (priv->phy_iface == PHY_INTERFACE_MODE_RMII))
+               phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
+                                        SUPPORTED_1000baseT_Full);
+
+       /* Broken HW is sometimes missing the pull-up resistor on the
+        * MDIO line, which results in reads to non-existent devices returning
+        * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
+        * device as well.
+        * Note: phydev->phy_id is the result of reading the UID PHY registers.
+        */
+       if (phydev->phy_id == 0) {
+               netdev_err(dev, "Bad PHY UID 0x%08x\n", phydev->phy_id);
+               phy_disconnect(phydev);
+               return -ENODEV;
+       }
+
+       netdev_dbg(dev, "attached to PHY %d UID 0x%08x Link = %d\n",
+                  phydev->addr, phydev->phy_id, phydev->link);
+
+       priv->phydev = phydev;
+       return 0;
+}
+
+static void tse_update_mac_addr(struct altera_tse_private *priv, u8 *addr)
+{
+       struct altera_tse_mac *mac = priv->mac_dev;
+       u32 msb;
+       u32 lsb;
+
+       msb = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+       lsb = ((addr[5] << 8) | addr[4]) & 0xffff;
+
+       /* Set primary MAC address */
+       iowrite32(msb, &mac->mac_addr_0);
+       iowrite32(lsb, &mac->mac_addr_1);
+}
+
+/* MAC software reset.
+ * When reset is triggered, the MAC function completes the current
+ * transmission or reception, and subsequently disables the transmit and
+ * receive logic, flushes the receive FIFO buffer, and resets the statistics
+ * counters.
+ */
+static int reset_mac(struct altera_tse_private *priv)
+{
+       void __iomem *cmd_cfg_reg = &priv->mac_dev->command_config;
+       int counter;
+       u32 dat;
+
+       dat = ioread32(cmd_cfg_reg);
+       dat &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA);
+       dat |= MAC_CMDCFG_SW_RESET | MAC_CMDCFG_CNT_RESET;
+       iowrite32(dat, cmd_cfg_reg);
+
+       counter = 0;
+       while (counter++ < ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               if (tse_bit_is_clear(cmd_cfg_reg, MAC_CMDCFG_SW_RESET))
+                       break;
+               udelay(1);
+       }
+
+       if (counter >= ALTERA_TSE_SW_RESET_WATCHDOG_CNTR) {
+               dat = ioread32(cmd_cfg_reg);
+               dat &= ~MAC_CMDCFG_SW_RESET;
+               iowrite32(dat, cmd_cfg_reg);
+               return -1;
+       }
+       return 0;
+}
+
+/* Initialize MAC core registers
+*/
+static int init_mac(struct altera_tse_private *priv)
+{
+       struct altera_tse_mac *mac = priv->mac_dev;
+       unsigned int cmd = 0;
+       u32 frm_length;
+
+       /* Setup Rx FIFO */
+       iowrite32(priv->rx_fifo_depth - ALTERA_TSE_RX_SECTION_EMPTY,
+                 &mac->rx_section_empty);
+       iowrite32(ALTERA_TSE_RX_SECTION_FULL, &mac->rx_section_full);
+       iowrite32(ALTERA_TSE_RX_ALMOST_EMPTY, &mac->rx_almost_empty);
+       iowrite32(ALTERA_TSE_RX_ALMOST_FULL, &mac->rx_almost_full);
+
+       /* Setup Tx FIFO */
+       iowrite32(priv->tx_fifo_depth - ALTERA_TSE_TX_SECTION_EMPTY,
+                 &mac->tx_section_empty);
+       iowrite32(ALTERA_TSE_TX_SECTION_FULL, &mac->tx_section_full);
+       iowrite32(ALTERA_TSE_TX_ALMOST_EMPTY, &mac->tx_almost_empty);
+       iowrite32(ALTERA_TSE_TX_ALMOST_FULL, &mac->tx_almost_full);
+
+       /* MAC Address Configuration */
+       tse_update_mac_addr(priv, priv->dev->dev_addr);
+
+       /* MAC Function Configuration */
+       frm_length = ETH_HLEN + priv->dev->mtu + ETH_FCS_LEN;
+       iowrite32(frm_length, &mac->frm_length);
+       iowrite32(ALTERA_TSE_TX_IPG_LENGTH, &mac->tx_ipg_length);
+
+       /* Disable RX/TX shift 16 for alignment of all received frames on 16-bit
+        * start address
+        */
+       tse_clear_bit(&mac->rx_cmd_stat, ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16);
+       tse_clear_bit(&mac->tx_cmd_stat, ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 |
+                                        ALTERA_TSE_TX_CMD_STAT_OMIT_CRC);
+
+       /* Set the MAC options */
+       cmd = ioread32(&mac->command_config);
+       cmd |= MAC_CMDCFG_PAD_EN;       /* Padding Removal on Receive */
+       cmd &= ~MAC_CMDCFG_CRC_FWD;     /* CRC Removal */
+       cmd |= MAC_CMDCFG_RX_ERR_DISC;  /* Automatically discard frames
+                                        * with CRC errors
+                                        */
+       cmd |= MAC_CMDCFG_CNTL_FRM_ENA;
+       cmd &= ~MAC_CMDCFG_TX_ENA;
+       cmd &= ~MAC_CMDCFG_RX_ENA;
+       iowrite32(cmd, &mac->command_config);
+
+       if (netif_msg_hw(priv))
+               dev_dbg(priv->device,
+                       "MAC post-initialization: CMD_CONFIG = 0x%08x\n", cmd);
+
+       return 0;
+}
+
+/* Start/stop MAC transmission logic
+ */
+static void tse_set_mac(struct altera_tse_private *priv, bool enable)
+{
+       struct altera_tse_mac *mac = priv->mac_dev;
+       u32 value = ioread32(&mac->command_config);
+
+       if (enable)
+               value |= MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA;
+       else
+               value &= ~(MAC_CMDCFG_TX_ENA | MAC_CMDCFG_RX_ENA);
+
+       iowrite32(value, &mac->command_config);
+}
+
+/* Change the MTU
+ */
+static int tse_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       unsigned int max_mtu = priv->max_mtu;
+       unsigned int min_mtu = ETH_ZLEN + ETH_FCS_LEN;
+
+       if (netif_running(dev)) {
+               netdev_err(dev, "must be stopped to change its MTU\n");
+               return -EBUSY;
+       }
+
+       if ((new_mtu < min_mtu) || (new_mtu > max_mtu)) {
+               netdev_err(dev, "invalid MTU, max MTU is: %u\n", max_mtu);
+               return -EINVAL;
+       }
+
+       dev->mtu = new_mtu;
+       netdev_update_features(dev);
+
+       return 0;
+}
+
+static void altera_tse_set_mcfilter(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+       int i;
+       struct netdev_hw_addr *ha;
+
+       /* clear the hash filter */
+       for (i = 0; i < 64; i++)
+               iowrite32(0, &(mac->hash_table[i]));
+
+       netdev_for_each_mc_addr(ha, dev) {
+               unsigned int hash = 0;
+               int mac_octet;
+
+               for (mac_octet = 5; mac_octet >= 0; mac_octet--) {
+                       unsigned char xor_bit = 0;
+                       unsigned char octet = ha->addr[mac_octet];
+                       unsigned int bitshift;
+
+                       for (bitshift = 0; bitshift < 8; bitshift++)
+                               xor_bit ^= ((octet >> bitshift) & 0x01);
+
+                       hash = (hash << 1) | xor_bit;
+               }
+               iowrite32(1, &(mac->hash_table[hash]));
+       }
+}
+
+
+static void altera_tse_set_mcfilterall(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+       int i;
+
+       /* set the hash filter */
+       for (i = 0; i < 64; i++)
+               iowrite32(1, &(mac->hash_table[i]));
+}
+
+/* Set or clear the multicast filter for this adaptor
+ */
+static void tse_set_rx_mode_hashfilter(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+
+       spin_lock(&priv->mac_cfg_lock);
+
+       if (dev->flags & IFF_PROMISC)
+               tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+
+       if (dev->flags & IFF_ALLMULTI)
+               altera_tse_set_mcfilterall(dev);
+       else
+               altera_tse_set_mcfilter(dev);
+
+       spin_unlock(&priv->mac_cfg_lock);
+}
+
+/* Set or clear the multicast filter for this adaptor
+ */
+static void tse_set_rx_mode(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       struct altera_tse_mac *mac = priv->mac_dev;
+
+       spin_lock(&priv->mac_cfg_lock);
+
+       if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+           !netdev_mc_empty(dev) || !netdev_uc_empty(dev))
+               tse_set_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+       else
+               tse_clear_bit(&mac->command_config, MAC_CMDCFG_PROMIS_EN);
+
+       spin_unlock(&priv->mac_cfg_lock);
+}
+
+/* Open and initialize the interface
+ */
+static int tse_open(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       int ret = 0;
+       int i;
+       unsigned long int flags;
+
+       /* Reset and configure TSE MAC and probe associated PHY */
+       ret = priv->dmaops->init_dma(priv);
+       if (ret != 0) {
+               netdev_err(dev, "Cannot initialize DMA\n");
+               goto phy_error;
+       }
+
+       if (netif_msg_ifup(priv))
+               netdev_warn(dev, "device MAC address %pM\n",
+                           dev->dev_addr);
+
+       if ((priv->revision < 0xd00) || (priv->revision > 0xe00))
+               netdev_warn(dev, "TSE revision %x\n", priv->revision);
+
+       spin_lock(&priv->mac_cfg_lock);
+       ret = reset_mac(priv);
+       if (ret)
+               netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+
+       ret = init_mac(priv);
+       spin_unlock(&priv->mac_cfg_lock);
+       if (ret) {
+               netdev_err(dev, "Cannot init MAC core (error: %d)\n", ret);
+               goto alloc_skbuf_error;
+       }
+
+       priv->dmaops->reset_dma(priv);
+
+       /* Create and initialize the TX/RX descriptors chains. */
+       priv->rx_ring_size = dma_rx_num;
+       priv->tx_ring_size = dma_tx_num;
+       ret = alloc_init_skbufs(priv);
+       if (ret) {
+               netdev_err(dev, "DMA descriptors initialization failed\n");
+               goto alloc_skbuf_error;
+       }
+
+
+       /* Register RX interrupt */
+       ret = request_irq(priv->rx_irq, altera_isr, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret) {
+               netdev_err(dev, "Unable to register RX interrupt %d\n",
+                          priv->rx_irq);
+               goto init_error;
+       }
+
+       /* Register TX interrupt */
+       ret = request_irq(priv->tx_irq, altera_isr, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret) {
+               netdev_err(dev, "Unable to register TX interrupt %d\n",
+                          priv->tx_irq);
+               goto tx_request_irq_error;
+       }
+
+       /* Enable DMA interrupts */
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       priv->dmaops->enable_rxirq(priv);
+       priv->dmaops->enable_txirq(priv);
+
+       /* Setup RX descriptor chain */
+       for (i = 0; i < priv->rx_ring_size; i++)
+               priv->dmaops->add_rx_desc(priv, &priv->rx_ring[i]);
+
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+       /* Start MAC Rx/Tx */
+       spin_lock(&priv->mac_cfg_lock);
+       tse_set_mac(priv, true);
+       spin_unlock(&priv->mac_cfg_lock);
+
+       if (priv->phydev)
+               phy_start(priv->phydev);
+
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       return 0;
+
+tx_request_irq_error:
+       free_irq(priv->rx_irq, dev);
+init_error:
+       free_skbufs(dev);
+alloc_skbuf_error:
+       if (priv->phydev) {
+               phy_disconnect(priv->phydev);
+               priv->phydev = NULL;
+       }
+phy_error:
+       return ret;
+}
+
+/* Stop TSE MAC interface and put the device in an inactive state
+ */
+static int tse_shutdown(struct net_device *dev)
+{
+       struct altera_tse_private *priv = netdev_priv(dev);
+       int ret;
+       unsigned long int flags;
+
+       /* Stop and disconnect the PHY */
+       if (priv->phydev) {
+               phy_stop(priv->phydev);
+               phy_disconnect(priv->phydev);
+               priv->phydev = NULL;
+       }
+
+       netif_stop_queue(dev);
+       napi_disable(&priv->napi);
+
+       /* Disable DMA interrupts */
+       spin_lock_irqsave(&priv->rxdma_irq_lock, flags);
+       priv->dmaops->disable_rxirq(priv);
+       priv->dmaops->disable_txirq(priv);
+       spin_unlock_irqrestore(&priv->rxdma_irq_lock, flags);
+
+       /* Free the IRQ lines */
+       free_irq(priv->rx_irq, dev);
+       free_irq(priv->tx_irq, dev);
+
+       /* disable and reset the MAC, empties fifo */
+       spin_lock(&priv->mac_cfg_lock);
+       spin_lock(&priv->tx_lock);
+
+       ret = reset_mac(priv);
+       if (ret)
+               netdev_err(dev, "Cannot reset MAC core (error: %d)\n", ret);
+       priv->dmaops->reset_dma(priv);
+       free_skbufs(dev);
+
+       spin_unlock(&priv->tx_lock);
+       spin_unlock(&priv->mac_cfg_lock);
+
+       priv->dmaops->uninit_dma(priv);
+
+       return 0;
+}
+
+static struct net_device_ops altera_tse_netdev_ops = {
+       .ndo_open               = tse_open,
+       .ndo_stop               = tse_shutdown,
+       .ndo_start_xmit         = tse_start_xmit,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_rx_mode        = tse_set_rx_mode,
+       .ndo_change_mtu         = tse_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+
+static int request_and_map(struct platform_device *pdev, const char *name,
+                          struct resource **res, void __iomem **ptr)
+{
+       struct resource *region;
+       struct device *device = &pdev->dev;
+
+       *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       if (*res == NULL) {
+               dev_err(device, "resource %s not defined\n", name);
+               return -ENODEV;
+       }
+
+       region = devm_request_mem_region(device, (*res)->start,
+                                        resource_size(*res), dev_name(device));
+       if (region == NULL) {
+               dev_err(device, "unable to request %s\n", name);
+               return -EBUSY;
+       }
+
+       *ptr = devm_ioremap_nocache(device, region->start,
+                                   resource_size(region));
+       if (*ptr == NULL) {
+               dev_err(device, "ioremap_nocache of %s failed!", name);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/* Probe Altera TSE MAC device
+ */
+static int altera_tse_probe(struct platform_device *pdev)
+{
+       struct net_device *ndev;
+       int ret = -ENODEV;
+       struct resource *control_port;
+       struct resource *dma_res;
+       struct altera_tse_private *priv;
+       const unsigned char *macaddr;
+       struct device_node *np = pdev->dev.of_node;
+       void __iomem *descmap;
+       const struct of_device_id *of_id = NULL;
+
+       ndev = alloc_etherdev(sizeof(struct altera_tse_private));
+       if (!ndev) {
+               dev_err(&pdev->dev, "Could not allocate network device\n");
+               return -ENODEV;
+       }
+
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+
+       priv = netdev_priv(ndev);
+       priv->device = &pdev->dev;
+       priv->dev = ndev;
+       priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+       of_id = of_match_device(altera_tse_ids, &pdev->dev);
+
+       if (of_id)
+               priv->dmaops = (struct altera_dmaops *)of_id->data;
+
+
+       if (priv->dmaops &&
+           priv->dmaops->altera_dtype == ALTERA_DTYPE_SGDMA) {
+               /* Get the mapped address to the SGDMA descriptor memory */
+               ret = request_and_map(pdev, "s1", &dma_res, &descmap);
+               if (ret)
+                       goto out_free;
+
+               /* Start of that memory is for transmit descriptors */
+               priv->tx_dma_desc = descmap;
+
+               /* First half is for tx descriptors, other half for tx */
+               priv->txdescmem = resource_size(dma_res)/2;
+
+               priv->txdescmem_busaddr = (dma_addr_t)dma_res->start;
+
+               priv->rx_dma_desc = (void __iomem *)((uintptr_t)(descmap +
+                                                    priv->txdescmem));
+               priv->rxdescmem = resource_size(dma_res)/2;
+               priv->rxdescmem_busaddr = dma_res->start;
+               priv->rxdescmem_busaddr += priv->txdescmem;
+
+               if (upper_32_bits(priv->rxdescmem_busaddr)) {
+                       dev_dbg(priv->device,
+                               "SGDMA bus addresses greater than 32-bits\n");
+                       goto out_free;
+               }
+               if (upper_32_bits(priv->txdescmem_busaddr)) {
+                       dev_dbg(priv->device,
+                               "SGDMA bus addresses greater than 32-bits\n");
+                       goto out_free;
+               }
+       } else if (priv->dmaops &&
+                  priv->dmaops->altera_dtype == ALTERA_DTYPE_MSGDMA) {
+               ret = request_and_map(pdev, "rx_resp", &dma_res,
+                                     &priv->rx_dma_resp);
+               if (ret)
+                       goto out_free;
+
+               ret = request_and_map(pdev, "tx_desc", &dma_res,
+                                     &priv->tx_dma_desc);
+               if (ret)
+                       goto out_free;
+
+               priv->txdescmem = resource_size(dma_res);
+               priv->txdescmem_busaddr = dma_res->start;
+
+               ret = request_and_map(pdev, "rx_desc", &dma_res,
+                                     &priv->rx_dma_desc);
+               if (ret)
+                       goto out_free;
+
+               priv->rxdescmem = resource_size(dma_res);
+               priv->rxdescmem_busaddr = dma_res->start;
+
+       } else {
+               goto out_free;
+       }
+
+       if (!dma_set_mask(priv->device, DMA_BIT_MASK(priv->dmaops->dmamask)))
+               dma_set_coherent_mask(priv->device,
+                                     DMA_BIT_MASK(priv->dmaops->dmamask));
+       else if (!dma_set_mask(priv->device, DMA_BIT_MASK(32)))
+               dma_set_coherent_mask(priv->device, DMA_BIT_MASK(32));
+       else
+               goto out_free;
+
+       /* MAC address space */
+       ret = request_and_map(pdev, "control_port", &control_port,
+                             (void __iomem **)&priv->mac_dev);
+       if (ret)
+               goto out_free;
+
+       /* xSGDMA Rx Dispatcher address space */
+       ret = request_and_map(pdev, "rx_csr", &dma_res,
+                             &priv->rx_dma_csr);
+       if (ret)
+               goto out_free;
+
+
+       /* xSGDMA Tx Dispatcher address space */
+       ret = request_and_map(pdev, "tx_csr", &dma_res,
+                             &priv->tx_dma_csr);
+       if (ret)
+               goto out_free;
+
+
+       /* Rx IRQ */
+       priv->rx_irq = platform_get_irq_byname(pdev, "rx_irq");
+       if (priv->rx_irq == -ENXIO) {
+               dev_err(&pdev->dev, "cannot obtain Rx IRQ\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       /* Tx IRQ */
+       priv->tx_irq = platform_get_irq_byname(pdev, "tx_irq");
+       if (priv->tx_irq == -ENXIO) {
+               dev_err(&pdev->dev, "cannot obtain Tx IRQ\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       /* get FIFO depths from device tree */
+       if (of_property_read_u32(pdev->dev.of_node, "rx-fifo-depth",
+                                &priv->rx_fifo_depth)) {
+               dev_err(&pdev->dev, "cannot obtain rx-fifo-depth\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       if (of_property_read_u32(pdev->dev.of_node, "tx-fifo-depth",
+                                &priv->rx_fifo_depth)) {
+               dev_err(&pdev->dev, "cannot obtain tx-fifo-depth\n");
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       /* get hash filter settings for this instance */
+       priv->hash_filter =
+               of_property_read_bool(pdev->dev.of_node,
+                                     "altr,has-hash-multicast-filter");
+
+       /* get supplemental address settings for this instance */
+       priv->added_unicast =
+               of_property_read_bool(pdev->dev.of_node,
+                                     "altr,has-supplementary-unicast");
+
+       /* Max MTU is 1500, ETH_DATA_LEN */
+       priv->max_mtu = ETH_DATA_LEN;
+
+       /* Get the max mtu from the device tree. Note that the
+        * "max-frame-size" parameter is actually max mtu. Definition
+        * in the ePAPR v1.1 spec and usage differ, so go with usage.
+        */
+       of_property_read_u32(pdev->dev.of_node, "max-frame-size",
+                            &priv->max_mtu);
+
+       /* The DMA buffer size already accounts for an alignment bias
+        * to avoid unaligned access exceptions for the NIOS processor,
+        */
+       priv->rx_dma_buf_sz = ALTERA_RXDMABUFFER_SIZE;
+
+       /* get default MAC address from device tree */
+       macaddr = of_get_mac_address(pdev->dev.of_node);
+       if (macaddr)
+               ether_addr_copy(ndev->dev_addr, macaddr);
+       else
+               eth_hw_addr_random(ndev);
+
+       priv->phy_iface = of_get_phy_mode(np);
+
+       /* try to get PHY address from device tree, use PHY autodetection if
+        * no valid address is given
+        */
+       if (of_property_read_u32(pdev->dev.of_node, "phy-addr",
+                                &priv->phy_addr)) {
+               priv->phy_addr = POLL_PHY;
+       }
+
+       if (!((priv->phy_addr == POLL_PHY) ||
+             ((priv->phy_addr >= 0) && (priv->phy_addr < PHY_MAX_ADDR)))) {
+               dev_err(&pdev->dev, "invalid phy-addr specified %d\n",
+                       priv->phy_addr);
+               goto out_free;
+       }
+
+       /* Create/attach to MDIO bus */
+       ret = altera_tse_mdio_create(ndev,
+                                    atomic_add_return(1, &instance_count));
+
+       if (ret)
+               goto out_free;
+
+       /* initialize netdev */
+       ether_setup(ndev);
+       ndev->mem_start = control_port->start;
+       ndev->mem_end = control_port->end;
+       ndev->netdev_ops = &altera_tse_netdev_ops;
+       altera_tse_set_ethtool_ops(ndev);
+
+       altera_tse_netdev_ops.ndo_set_rx_mode = tse_set_rx_mode;
+
+       if (priv->hash_filter)
+               altera_tse_netdev_ops.ndo_set_rx_mode =
+                       tse_set_rx_mode_hashfilter;
+
+       /* Scatter/gather IO is not supported,
+        * so it is turned off
+        */
+       ndev->hw_features &= ~NETIF_F_SG;
+       ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
+
+       /* VLAN offloading of tagging, stripping and filtering is not
+        * supported by hardware, but driver will accommodate the
+        * extra 4-byte VLAN tag for processing by upper layers
+        */
+       ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+
+       /* setup NAPI interface */
+       netif_napi_add(ndev, &priv->napi, tse_poll, NAPI_POLL_WEIGHT);
+
+       spin_lock_init(&priv->mac_cfg_lock);
+       spin_lock_init(&priv->tx_lock);
+       spin_lock_init(&priv->rxdma_irq_lock);
+
+       ret = register_netdev(ndev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register TSE net device\n");
+               goto out_free_mdio;
+       }
+
+       platform_set_drvdata(pdev, ndev);
+
+       priv->revision = ioread32(&priv->mac_dev->megacore_revision);
+
+       if (netif_msg_probe(priv))
+               dev_info(&pdev->dev, "Altera TSE MAC version %d.%d at 0x%08lx irq %d/%d\n",
+                        (priv->revision >> 8) & 0xff,
+                        priv->revision & 0xff,
+                        (unsigned long) control_port->start, priv->rx_irq,
+                        priv->tx_irq);
+
+       ret = init_phy(ndev);
+       if (ret != 0) {
+               netdev_err(ndev, "Cannot attach to PHY (error: %d)\n", ret);
+               goto out_free_mdio;
+       }
+       return 0;
+
+out_free_mdio:
+       altera_tse_mdio_destroy(ndev);
+out_free:
+       free_netdev(ndev);
+       return ret;
+}
+
+/* Remove Altera TSE MAC device
+ */
+static int altera_tse_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+
+       platform_set_drvdata(pdev, NULL);
+       altera_tse_mdio_destroy(ndev);
+       unregister_netdev(ndev);
+       free_netdev(ndev);
+
+       return 0;
+}
+
+struct altera_dmaops altera_dtype_sgdma = {
+       .altera_dtype = ALTERA_DTYPE_SGDMA,
+       .dmamask = 32,
+       .reset_dma = sgdma_reset,
+       .enable_txirq = sgdma_enable_txirq,
+       .enable_rxirq = sgdma_enable_rxirq,
+       .disable_txirq = sgdma_disable_txirq,
+       .disable_rxirq = sgdma_disable_rxirq,
+       .clear_txirq = sgdma_clear_txirq,
+       .clear_rxirq = sgdma_clear_rxirq,
+       .tx_buffer = sgdma_tx_buffer,
+       .tx_completions = sgdma_tx_completions,
+       .add_rx_desc = sgdma_add_rx_desc,
+       .get_rx_status = sgdma_rx_status,
+       .init_dma = sgdma_initialize,
+       .uninit_dma = sgdma_uninitialize,
+};
+
+struct altera_dmaops altera_dtype_msgdma = {
+       .altera_dtype = ALTERA_DTYPE_MSGDMA,
+       .dmamask = 64,
+       .reset_dma = msgdma_reset,
+       .enable_txirq = msgdma_enable_txirq,
+       .enable_rxirq = msgdma_enable_rxirq,
+       .disable_txirq = msgdma_disable_txirq,
+       .disable_rxirq = msgdma_disable_rxirq,
+       .clear_txirq = msgdma_clear_txirq,
+       .clear_rxirq = msgdma_clear_rxirq,
+       .tx_buffer = msgdma_tx_buffer,
+       .tx_completions = msgdma_tx_completions,
+       .add_rx_desc = msgdma_add_rx_desc,
+       .get_rx_status = msgdma_rx_status,
+       .init_dma = msgdma_initialize,
+       .uninit_dma = msgdma_uninitialize,
+};
+
+static struct of_device_id altera_tse_ids[] = {
+       { .compatible = "altr,tse-msgdma-1.0", .data = &altera_dtype_msgdma, },
+       { .compatible = "altr,tse-1.0", .data = &altera_dtype_sgdma, },
+       { .compatible = "ALTR,tse-1.0", .data = &altera_dtype_sgdma, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, altera_tse_ids);
+
+static struct platform_driver altera_tse_driver = {
+       .probe          = altera_tse_probe,
+       .remove         = altera_tse_remove,
+       .suspend        = NULL,
+       .resume         = NULL,
+       .driver         = {
+               .name   = ALTERA_TSE_RESOURCE_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = altera_tse_ids,
+       },
+};
+
+module_platform_driver(altera_tse_driver);
+
+MODULE_AUTHOR("Altera Corporation");
+MODULE_DESCRIPTION("Altera Triple Speed Ethernet MAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/ethernet/altera/altera_utils.c b/drivers/net/ethernet/altera/altera_utils.c
new file mode 100644 (file)
index 0000000..70fa13f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "altera_tse.h"
+#include "altera_utils.h"
+
+void tse_set_bit(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       value |= bit_mask;
+       iowrite32(value, ioaddr);
+}
+
+void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       value &= ~bit_mask;
+       iowrite32(value, ioaddr);
+}
+
+int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       return (value & bit_mask) ? 1 : 0;
+}
+
+int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask)
+{
+       u32 value = ioread32(ioaddr);
+       return (value & bit_mask) ? 0 : 1;
+}
diff --git a/drivers/net/ethernet/altera/altera_utils.h b/drivers/net/ethernet/altera/altera_utils.h
new file mode 100644 (file)
index 0000000..ce1db36
--- /dev/null
@@ -0,0 +1,27 @@
+/* Altera TSE SGDMA and MSGDMA Linux driver
+ * Copyright (C) 2014 Altera Corporation. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+
+#ifndef __ALTERA_UTILS_H__
+#define __ALTERA_UTILS_H__
+
+void tse_set_bit(void __iomem *ioaddr, u32 bit_mask);
+void tse_clear_bit(void __iomem *ioaddr, u32 bit_mask);
+int tse_bit_is_set(void __iomem *ioaddr, u32 bit_mask);
+int tse_bit_is_clear(void __iomem *ioaddr, u32 bit_mask);
+
+#endif /* __ALTERA_UTILS_H__*/
index 18e542f7853d384c60ae6aec96e2ae1a1a19e3d7..98a10d555b793e029d20b6694ba1fab7cd13a053 100644 (file)
@@ -578,7 +578,7 @@ int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
        outs++;
        /* Kick the lance: transmit now */
        WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        spin_lock_irqsave(&lp->devlock, flags);
        if (TX_BUFFS_AVAIL)
index 9793767996a2a8e836259adde6fa0a342cd0f4d0..87e727b921dc0a20f99a6bdb084d2a6e3b168f9e 100644 (file)
@@ -472,7 +472,7 @@ am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
        if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
                netif_stop_queue(dev);
 
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
index 2061b471fd161b92cd9c4161fa15b955b63a28e2..26efaaa5e73fd292de512fc428e9af84126fcbb9 100644 (file)
@@ -720,6 +720,9 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
        int rx_pkt_limit = budget;
        unsigned long flags;
 
+       if (rx_pkt_limit <= 0)
+               goto rx_not_empty;
+
        do{
                /* process receive packets until we use the quota*/
                /* If we own the next entry, it's a new packet. Send it up. */
index 9339cccfe05a35977493a0fbaf766b91f49f8acb..e7cc9174e364162c68652e8c083e1d66fd5eefa0 100644 (file)
@@ -549,35 +549,35 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
        struct pcnet32_rx_head *new_rx_ring;
        struct sk_buff **new_skb_list;
        int new, overlap;
+       unsigned int entries = 1 << size;
 
        new_rx_ring = pci_alloc_consistent(lp->pci_dev,
                                           sizeof(struct pcnet32_rx_head) *
-                                          (1 << size),
+                                          entries,
                                           &new_ring_dma_addr);
        if (new_rx_ring == NULL) {
                netif_err(lp, drv, dev, "Consistent memory allocation failed\n");
                return;
        }
-       memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+       memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * entries);
 
-       new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t), GFP_ATOMIC);
+       new_dma_addr_list = kcalloc(entries, sizeof(dma_addr_t), GFP_ATOMIC);
        if (!new_dma_addr_list)
                goto free_new_rx_ring;
 
-       new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *),
-                              GFP_ATOMIC);
+       new_skb_list = kcalloc(entries, sizeof(struct sk_buff *), GFP_ATOMIC);
        if (!new_skb_list)
                goto free_new_lists;
 
        /* first copy the current receive buffers */
-       overlap = min(size, lp->rx_ring_size);
+       overlap = min(entries, lp->rx_ring_size);
        for (new = 0; new < overlap; new++) {
                new_rx_ring[new] = lp->rx_ring[new];
                new_dma_addr_list[new] = lp->rx_dma_addr[new];
                new_skb_list[new] = lp->rx_skbuff[new];
        }
        /* now allocate any new buffers needed */
-       for (; new < size; new++) {
+       for (; new < entries; new++) {
                struct sk_buff *rx_skbuff;
                new_skb_list[new] = netdev_alloc_skb(dev, PKT_BUF_SKB);
                rx_skbuff = new_skb_list[new];
@@ -592,6 +592,13 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
                new_dma_addr_list[new] =
                            pci_map_single(lp->pci_dev, rx_skbuff->data,
                                           PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+               if (pci_dma_mapping_error(lp->pci_dev,
+                                         new_dma_addr_list[new])) {
+                       netif_err(lp, drv, dev, "%s dma mapping failed\n",
+                                 __func__);
+                       dev_kfree_skb(new_skb_list[new]);
+                       goto free_all_new;
+               }
                new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]);
                new_rx_ring[new].buf_length = cpu_to_le16(NEG_BUF_SIZE);
                new_rx_ring[new].status = cpu_to_le16(0x8000);
@@ -599,8 +606,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
        /* and free any unneeded buffers */
        for (; new < lp->rx_ring_size; new++) {
                if (lp->rx_skbuff[new]) {
-                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
-                                        PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       if (!pci_dma_mapping_error(lp->pci_dev,
+                                                  lp->rx_dma_addr[new]))
+                               pci_unmap_single(lp->pci_dev,
+                                                lp->rx_dma_addr[new],
+                                                PKT_BUF_SIZE,
+                                                PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(lp->rx_skbuff[new]);
                }
        }
@@ -612,7 +623,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
                            lp->rx_ring_size, lp->rx_ring,
                            lp->rx_ring_dma_addr);
 
-       lp->rx_ring_size = (1 << size);
+       lp->rx_ring_size = entries;
        lp->rx_mod_mask = lp->rx_ring_size - 1;
        lp->rx_len_bits = (size << 4);
        lp->rx_ring = new_rx_ring;
@@ -624,8 +635,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
 free_all_new:
        while (--new >= lp->rx_ring_size) {
                if (new_skb_list[new]) {
-                       pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
-                                        PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       if (!pci_dma_mapping_error(lp->pci_dev,
+                                                  new_dma_addr_list[new]))
+                               pci_unmap_single(lp->pci_dev,
+                                                new_dma_addr_list[new],
+                                                PKT_BUF_SIZE,
+                                                PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(new_skb_list[new]);
                }
        }
@@ -634,8 +649,7 @@ free_new_lists:
        kfree(new_dma_addr_list);
 free_new_rx_ring:
        pci_free_consistent(lp->pci_dev,
-                           sizeof(struct pcnet32_rx_head) *
-                           (1 << size),
+                           sizeof(struct pcnet32_rx_head) * entries,
                            new_rx_ring,
                            new_ring_dma_addr);
 }
@@ -650,8 +664,12 @@ static void pcnet32_purge_rx_ring(struct net_device *dev)
                lp->rx_ring[i].status = 0;      /* CPU owns buffer */
                wmb();          /* Make sure adapter sees owner change */
                if (lp->rx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
-                                        PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       if (!pci_dma_mapping_error(lp->pci_dev,
+                                                  lp->rx_dma_addr[i]))
+                               pci_unmap_single(lp->pci_dev,
+                                                lp->rx_dma_addr[i],
+                                                PKT_BUF_SIZE,
+                                                PCI_DMA_FROMDEVICE);
                        dev_kfree_skb_any(lp->rx_skbuff[i]);
                }
                lp->rx_skbuff[i] = NULL;
@@ -930,6 +948,12 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
                lp->tx_dma_addr[x] =
                        pci_map_single(lp->pci_dev, skb->data, skb->len,
                                       PCI_DMA_TODEVICE);
+               if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[x])) {
+                       netif_printk(lp, hw, KERN_DEBUG, dev,
+                                    "DMA mapping error at line: %d!\n",
+                                    __LINE__);
+                       goto clean_up;
+               }
                lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
                wmb();  /* Make sure owner changes after all others are visible */
                lp->tx_ring[x].status = cpu_to_le16(status);
@@ -1142,24 +1166,36 @@ static void pcnet32_rx_entry(struct net_device *dev,
 
        if (pkt_len > rx_copybreak) {
                struct sk_buff *newskb;
+               dma_addr_t new_dma_addr;
 
                newskb = netdev_alloc_skb(dev, PKT_BUF_SKB);
+               /*
+                * map the new buffer, if mapping fails, drop the packet and
+                * reuse the old buffer
+                */
                if (newskb) {
                        skb_reserve(newskb, NET_IP_ALIGN);
-                       skb = lp->rx_skbuff[entry];
-                       pci_unmap_single(lp->pci_dev,
-                                        lp->rx_dma_addr[entry],
-                                        PKT_BUF_SIZE,
-                                        PCI_DMA_FROMDEVICE);
-                       skb_put(skb, pkt_len);
-                       lp->rx_skbuff[entry] = newskb;
-                       lp->rx_dma_addr[entry] =
-                                           pci_map_single(lp->pci_dev,
-                                                          newskb->data,
-                                                          PKT_BUF_SIZE,
-                                                          PCI_DMA_FROMDEVICE);
-                       rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]);
-                       rx_in_place = 1;
+                       new_dma_addr = pci_map_single(lp->pci_dev,
+                                                     newskb->data,
+                                                     PKT_BUF_SIZE,
+                                                     PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(lp->pci_dev, new_dma_addr)) {
+                               netif_err(lp, rx_err, dev,
+                                         "DMA mapping error.\n");
+                               dev_kfree_skb(newskb);
+                               skb = NULL;
+                       } else {
+                               skb = lp->rx_skbuff[entry];
+                               pci_unmap_single(lp->pci_dev,
+                                                lp->rx_dma_addr[entry],
+                                                PKT_BUF_SIZE,
+                                                PCI_DMA_FROMDEVICE);
+                               skb_put(skb, pkt_len);
+                               lp->rx_skbuff[entry] = newskb;
+                               lp->rx_dma_addr[entry] = new_dma_addr;
+                               rxp->base = cpu_to_le32(new_dma_addr);
+                               rx_in_place = 1;
+                       }
                } else
                        skb = NULL;
        } else
@@ -2229,9 +2265,12 @@ static void pcnet32_purge_tx_ring(struct net_device *dev)
                lp->tx_ring[i].status = 0;      /* CPU owns buffer */
                wmb();          /* Make sure adapter sees owner change */
                if (lp->tx_skbuff[i]) {
-                       pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
-                                        lp->tx_skbuff[i]->len,
-                                        PCI_DMA_TODEVICE);
+                       if (!pci_dma_mapping_error(lp->pci_dev,
+                                                  lp->tx_dma_addr[i]))
+                               pci_unmap_single(lp->pci_dev,
+                                                lp->tx_dma_addr[i],
+                                                lp->tx_skbuff[i]->len,
+                                                PCI_DMA_TODEVICE);
                        dev_kfree_skb_any(lp->tx_skbuff[i]);
                }
                lp->tx_skbuff[i] = NULL;
@@ -2264,10 +2303,19 @@ static int pcnet32_init_ring(struct net_device *dev)
                }
 
                rmb();
-               if (lp->rx_dma_addr[i] == 0)
+               if (lp->rx_dma_addr[i] == 0) {
                        lp->rx_dma_addr[i] =
                            pci_map_single(lp->pci_dev, rx_skbuff->data,
                                           PKT_BUF_SIZE, PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(lp->pci_dev,
+                                                 lp->rx_dma_addr[i])) {
+                               /* there is not much we can do at this point */
+                               netif_err(lp, drv, dev,
+                                         "%s pci dma mapping error\n",
+                                         __func__);
+                               return -1;
+                       }
+               }
                lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]);
                lp->rx_ring[i].buf_length = cpu_to_le16(NEG_BUF_SIZE);
                wmb();          /* Make sure owner changes after all others are visible */
@@ -2397,9 +2445,14 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
 
        lp->tx_ring[entry].misc = 0x00000000;
 
-       lp->tx_skbuff[entry] = skb;
        lp->tx_dma_addr[entry] =
            pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[entry])) {
+               dev_kfree_skb_any(skb);
+               dev->stats.tx_dropped++;
+               goto drop_packet;
+       }
+       lp->tx_skbuff[entry] = skb;
        lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
        wmb();                  /* Make sure owner changes after all others are visible */
        lp->tx_ring[entry].status = cpu_to_le16(status);
@@ -2414,6 +2467,7 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
                lp->tx_full = 1;
                netif_stop_queue(dev);
        }
+drop_packet:
        spin_unlock_irqrestore(&lp->lock, flags);
        return NETDEV_TX_OK;
 }
index e92ffd6e1c15fdbd2aaaa21f9335fb25bc142d20..17bb9ce96260df20eba44a9f215778a62c28373e 100644 (file)
@@ -535,7 +535,7 @@ static int alx_alloc_descriptors(struct alx_priv *alx)
        if (!alx->descmem.virt)
                goto out_free;
 
-       alx->txq.tpd = (void *)alx->descmem.virt;
+       alx->txq.tpd = alx->descmem.virt;
        alx->txq.tpd_dma = alx->descmem.dma;
 
        /* alignment requirement for next block */
@@ -1097,7 +1097,7 @@ static netdev_tx_t alx_start_xmit(struct sk_buff *skb,
        return NETDEV_TX_OK;
 
 drop:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
@@ -1248,19 +1248,13 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         * shared register for the high 32 bits, so only a single, aligned,
         * 4 GB physical address range can be used for descriptors.
         */
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) &&
-           !dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+       if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) {
                dev_dbg(&pdev->dev, "DMA to 64-BIT addresses\n");
        } else {
-               err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
                if (err) {
-                       err = dma_set_coherent_mask(&pdev->dev,
-                                                   DMA_BIT_MASK(32));
-                       if (err) {
-                               dev_err(&pdev->dev,
-                                       "No usable DMA config, aborting\n");
-                               goto out_pci_disable;
-                       }
+                       dev_err(&pdev->dev, "No usable DMA config, aborting\n");
+                       goto out_pci_disable;
                }
        }
 
@@ -1292,6 +1286,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        alx = netdev_priv(netdev);
        spin_lock_init(&alx->hw.mdio_lock);
        spin_lock_init(&alx->irq_lock);
+       spin_lock_init(&alx->stats_lock);
        alx->dev = netdev;
        alx->hw.pdev = pdev;
        alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP |
index 4d3258dd0a88143d77f8e39febf16800ce41ad2d..e11bf18fbbd19880cb5ea1557dbc0d78cbeccfd4 100644 (file)
@@ -832,7 +832,7 @@ static int atl1c_sw_init(struct atl1c_adapter *adapter)
 }
 
 static inline void atl1c_clean_buffer(struct pci_dev *pdev,
-                               struct atl1c_buffer *buffer_info, int in_irq)
+                               struct atl1c_buffer *buffer_info)
 {
        u16 pci_driection;
        if (buffer_info->flags & ATL1C_BUFFER_FREE)
@@ -850,12 +850,8 @@ static inline void atl1c_clean_buffer(struct pci_dev *pdev,
                        pci_unmap_page(pdev, buffer_info->dma,
                                        buffer_info->length, pci_driection);
        }
-       if (buffer_info->skb) {
-               if (in_irq)
-                       dev_kfree_skb_irq(buffer_info->skb);
-               else
-                       dev_kfree_skb(buffer_info->skb);
-       }
+       if (buffer_info->skb)
+               dev_consume_skb_any(buffer_info->skb);
        buffer_info->dma = 0;
        buffer_info->skb = NULL;
        ATL1C_SET_BUFFER_STATE(buffer_info, ATL1C_BUFFER_FREE);
@@ -875,7 +871,7 @@ static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
        ring_count = tpd_ring->count;
        for (index = 0; index < ring_count; index++) {
                buffer_info = &tpd_ring->buffer_info[index];
-               atl1c_clean_buffer(pdev, buffer_info, 0);
+               atl1c_clean_buffer(pdev, buffer_info);
        }
 
        /* Zero out Tx-buffers */
@@ -899,7 +895,7 @@ static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter)
 
        for (j = 0; j < rfd_ring->count; j++) {
                buffer_info = &rfd_ring->buffer_info[j];
-               atl1c_clean_buffer(pdev, buffer_info, 0);
+               atl1c_clean_buffer(pdev, buffer_info);
        }
        /* zero out the descriptor ring */
        memset(rfd_ring->desc, 0, rfd_ring->size);
@@ -1562,7 +1558,7 @@ static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter,
 
        while (next_to_clean != hw_next_to_clean) {
                buffer_info = &tpd_ring->buffer_info[next_to_clean];
-               atl1c_clean_buffer(pdev, buffer_info, 1);
+               atl1c_clean_buffer(pdev, buffer_info);
                if (++next_to_clean == tpd_ring->count)
                        next_to_clean = 0;
                atomic_set(&tpd_ring->next_to_clean, next_to_clean);
@@ -1977,17 +1973,17 @@ static int atl1c_tso_csum(struct atl1c_adapter *adapter,
                          enum atl1c_trans_queue type)
 {
        struct pci_dev *pdev = adapter->pdev;
+       unsigned short offload_type;
        u8 hdr_len;
        u32 real_len;
-       unsigned short offload_type;
-       int err;
 
        if (skb_is_gso(skb)) {
-               if (skb_header_cloned(skb)) {
-                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-                       if (unlikely(err))
-                               return -1;
-               }
+               int err;
+
+               err = skb_cow_head(skb, 0);
+               if (err < 0)
+                       return err;
+
                offload_type = skb_shinfo(skb)->gso_type;
 
                if (offload_type & SKB_GSO_TCPV4) {
@@ -2085,7 +2081,7 @@ static void atl1c_tx_rollback(struct atl1c_adapter *adpt,
        while (index != tpd_ring->next_to_use) {
                tpd = ATL1C_TPD_DESC(tpd_ring, index);
                buffer_info = &tpd_ring->buffer_info[index];
-               atl1c_clean_buffer(adpt->pdev, buffer_info, 0);
+               atl1c_clean_buffer(adpt->pdev, buffer_info);
                memset(tpd, 0, sizeof(struct atl1c_tpd_desc));
                if (++index == tpd_ring->count)
                        index = 0;
@@ -2258,7 +2254,7 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
                /* roll back tpd/buffer */
                atl1c_tx_rollback(adapter, tpd, type);
                spin_unlock_irqrestore(&adapter->tx_lock, flags);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        } else {
                atl1c_tx_queue(adapter, skb, tpd, type);
                spin_unlock_irqrestore(&adapter->tx_lock, flags);
index d5c2d3e912e57e1aae51b4bc265a95420f89822b..4345332533adb5f9108fd7d9a1fbc7a138109a3c 100644 (file)
@@ -1641,17 +1641,17 @@ static u16 atl1e_cal_tdp_req(const struct sk_buff *skb)
 static int atl1e_tso_csum(struct atl1e_adapter *adapter,
                       struct sk_buff *skb, struct atl1e_tpd_desc *tpd)
 {
+       unsigned short offload_type;
        u8 hdr_len;
        u32 real_len;
-       unsigned short offload_type;
-       int err;
 
        if (skb_is_gso(skb)) {
-               if (skb_header_cloned(skb)) {
-                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-                       if (unlikely(err))
-                               return -1;
-               }
+               int err;
+
+               err = skb_cow_head(skb, 0);
+               if (err < 0)
+                       return err;
+
                offload_type = skb_shinfo(skb)->gso_type;
 
                if (offload_type & SKB_GSO_TCPV4) {
@@ -2436,7 +2436,7 @@ err_reset:
 err_register:
 err_sw_init:
 err_eeprom:
-       iounmap(adapter->hw.hw_addr);
+       pci_iounmap(pdev, adapter->hw.hw_addr);
 err_init_netdev:
 err_ioremap:
        free_netdev(netdev);
@@ -2474,7 +2474,7 @@ static void atl1e_remove(struct pci_dev *pdev)
        unregister_netdev(netdev);
        atl1e_free_ring_resources(adapter);
        atl1e_force_ps(&adapter->hw);
-       iounmap(adapter->hw.hw_addr);
+       pci_iounmap(pdev, adapter->hw.hw_addr);
        pci_release_regions(pdev);
        free_netdev(netdev);
        pci_disable_device(pdev);
index 287272dd69daefcbf7a0599742e00e03072f3f70..dfd0e91fa726852818b48b2853e9d60533d01dd7 100644 (file)
@@ -2118,18 +2118,17 @@ static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
 }
 
 static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
-       struct tx_packet_desc *ptpd)
+                   struct tx_packet_desc *ptpd)
 {
        u8 hdr_len, ip_off;
        u32 real_len;
-       int err;
 
        if (skb_shinfo(skb)->gso_size) {
-               if (skb_header_cloned(skb)) {
-                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-                       if (unlikely(err))
-                               return -1;
-               }
+               int err;
+
+               err = skb_cow_head(skb, 0);
+               if (err < 0)
+                       return err;
 
                if (skb->protocol == htons(ETH_P_IP)) {
                        struct iphdr *iph = ip_hdr(skb);
@@ -2175,7 +2174,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
                        return 3;
                }
        }
-       return false;
+       return 0;
 }
 
 static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
index 265ce1b752ed0b169a927f6dad148e694ca4c5a2..78befb522a528268fae32c68649ead0a01263366 100644 (file)
@@ -55,6 +55,7 @@ static const char atl2_driver_name[] = "atl2";
 static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver";
 static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation.";
 static const char atl2_driver_version[] = ATL2_DRV_VERSION;
+static const struct ethtool_ops atl2_ethtool_ops;
 
 MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>");
 MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver");
@@ -71,8 +72,6 @@ static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = {
 };
 MODULE_DEVICE_TABLE(pci, atl2_pci_tbl);
 
-static void atl2_set_ethtool_ops(struct net_device *netdev);
-
 static void atl2_check_options(struct atl2_adapter *adapter);
 
 /**
@@ -1397,7 +1396,7 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        atl2_setup_pcicmd(pdev);
 
        netdev->netdev_ops = &atl2_netdev_ops;
-       atl2_set_ethtool_ops(netdev);
+       SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops);
        netdev->watchdog_timeo = 5 * HZ;
        strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
@@ -2105,11 +2104,6 @@ static const struct ethtool_ops atl2_ethtool_ops = {
        .set_eeprom             = atl2_set_eeprom,
 };
 
-static void atl2_set_ethtool_ops(struct net_device *netdev)
-{
-       SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops);
-}
-
 #define LBYTESWAP(a)  ((((a) & 0x00ff00ff) << 8) | \
        (((a) & 0xff00ff00) >> 8))
 #define LONGSWAP(a)   ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16))
index 3f97d9fd0a71b66ec28c9db4fcc1df63ccf71b29..85dbddd03722b20a861f53cba7fe00b6cb66f3db 100644 (file)
@@ -60,6 +60,17 @@ config BCM63XX_ENET
          This driver supports the ethernet MACs in the Broadcom 63xx
          MIPS chipset family (BCM63XX).
 
+config BCMGENET
+       tristate "Broadcom GENET internal MAC support"
+       depends on OF
+       select MII
+       select PHYLIB
+       select FIXED_PHY if BCMGENET=y
+       select BCM7XXX_PHY
+       help
+         This driver supports the built-in Ethernet MACs found in the
+         Broadcom BCM7xxx Set Top Box family chipset.
+
 config BNX2
        tristate "Broadcom NetXtremeII support"
        depends on PCI
index 68efa1a3fb8820ed71ca1e565cf08c9f243bc55e..fd639a0d4c7d64b2b7db5eb084087502e3c6d63a 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_B44) += b44.o
 obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o
+obj-$(CONFIG_BCMGENET) += genet/
 obj-$(CONFIG_BNX2) += bnx2.o
 obj-$(CONFIG_CNIC) += cnic.o
 obj-$(CONFIG_BNX2X) += bnx2x/
index 1f7b5aa114fae3ee3adf589af58e5def31fc84d7..05ba6258901794ab51842ddc8d630f4d1286798d 100644 (file)
@@ -1484,6 +1484,10 @@ static int b44_open(struct net_device *dev)
        add_timer(&bp->timer);
 
        b44_enable_ints(bp);
+
+       if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+               phy_start(bp->phydev);
+
        netif_start_queue(dev);
 out:
        return err;
@@ -1646,6 +1650,9 @@ static int b44_close(struct net_device *dev)
 
        netif_stop_queue(dev);
 
+       if (bp->flags & B44_FLAG_EXTERNAL_PHY)
+               phy_stop(bp->phydev);
+
        napi_disable(&bp->napi);
 
        del_timer_sync(&bp->timer);
@@ -1678,7 +1685,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev,
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin_bh(&hwstat->syncp);
+               start = u64_stats_fetch_begin_irq(&hwstat->syncp);
 
                /* Convert HW stats into rtnl_link_stats64 stats. */
                nstat->rx_packets = hwstat->rx_pkts;
@@ -1712,7 +1719,7 @@ static struct rtnl_link_stats64 *b44_get_stats64(struct net_device *dev,
                /* Carrier lost counter seems to be broken for some devices */
                nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
 #endif
-       } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start));
 
        return nstat;
 }
@@ -2066,12 +2073,12 @@ static void b44_get_ethtool_stats(struct net_device *dev,
        do {
                data_src = &hwstat->tx_good_octets;
                data_dst = data;
-               start = u64_stats_fetch_begin_bh(&hwstat->syncp);
+               start = u64_stats_fetch_begin_irq(&hwstat->syncp);
 
                for (i = 0; i < ARRAY_SIZE(b44_gstrings); i++)
                        *data_dst++ = *data_src++;
 
-       } while (u64_stats_fetch_retry_bh(&hwstat->syncp, start));
+       } while (u64_stats_fetch_retry_irq(&hwstat->syncp, start));
 }
 
 static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -2222,7 +2229,12 @@ static void b44_adjust_link(struct net_device *dev)
        }
 
        if (status_changed) {
-               b44_check_phy(bp);
+               u32 val = br32(bp, B44_TX_CTRL);
+               if (bp->flags & B44_FLAG_FULL_DUPLEX)
+                       val |= TX_CTRL_DUPLEX;
+               else
+                       val &= ~TX_CTRL_DUPLEX;
+               bw32(bp, B44_TX_CTRL, val);
                phy_print_status(phydev);
        }
 }
index b9a5fb6400d3cf1917511dec27c92486a46f12fc..a7d11f5565d69342ad296471a9a5d44f8d7c51d5 100644 (file)
@@ -1722,9 +1722,6 @@ static const struct net_device_ops bcm_enet_ops = {
        .ndo_set_rx_mode        = bcm_enet_set_multicast_list,
        .ndo_do_ioctl           = bcm_enet_ioctl,
        .ndo_change_mtu         = bcm_enet_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller = bcm_enet_netpoll,
-#endif
 };
 
 /*
index 9d2dedadf2dfb7e0090be24064e46f63112bce3e..a8efb18e42fa66a01fd1950977db55b96ab15022 100644 (file)
@@ -85,7 +85,7 @@ MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax);
 
 static int disable_msi = 0;
 
-module_param(disable_msi, int, 0);
+module_param(disable_msi, int, S_IRUGO);
 MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
 
 typedef enum {
@@ -2507,6 +2507,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent)
 
        bp->fw_wr_seq++;
        msg_data |= bp->fw_wr_seq;
+       bp->fw_last_msg = msg_data;
 
        bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data);
 
@@ -2885,7 +2886,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
                sw_cons = BNX2_NEXT_TX_BD(sw_cons);
 
                tx_bytes += skb->len;
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                tx_pkt++;
                if (tx_pkt == budget)
                        break;
@@ -3132,6 +3133,9 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
        struct l2_fhdr *rx_hdr;
        int rx_pkt = 0, pg_ring_used = 0;
 
+       if (budget <= 0)
+               return rx_pkt;
+
        hw_cons = bnx2_get_hw_rx_cons(bnapi);
        sw_cons = rxr->rx_cons;
        sw_prod = rxr->rx_prod;
@@ -4000,8 +4004,23 @@ bnx2_setup_wol(struct bnx2 *bp)
                        wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
        }
 
-       if (!(bp->flags & BNX2_FLAG_NO_WOL))
-               bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 1, 0);
+       if (!(bp->flags & BNX2_FLAG_NO_WOL)) {
+               u32 val;
+
+               wol_msg |= BNX2_DRV_MSG_DATA_WAIT3;
+               if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) {
+                       bnx2_fw_sync(bp, wol_msg, 1, 0);
+                       return;
+               }
+               /* Tell firmware not to power down the PHY yet, otherwise
+                * the chip will take a long time to respond to MMIO reads.
+                */
+               val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE);
+               bnx2_shmem_wr(bp, BNX2_PORT_FEATURE,
+                             val | BNX2_PORT_FEATURE_ASF_ENABLED);
+               bnx2_fw_sync(bp, wol_msg, 1, 0);
+               bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val);
+       }
 
 }
 
@@ -4033,9 +4052,22 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
 
                        if (bp->wol)
                                pci_set_power_state(bp->pdev, PCI_D3hot);
-               } else {
-                       pci_set_power_state(bp->pdev, PCI_D3hot);
+                       break;
+
                }
+               if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) {
+                       u32 val;
+
+                       /* Tell firmware not to power down the PHY yet,
+                        * otherwise the other port may not respond to
+                        * MMIO reads.
+                        */
+                       val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION);
+                       val &= ~BNX2_CONDITION_PM_STATE_MASK;
+                       val |= BNX2_CONDITION_PM_STATE_UNPREP;
+                       bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val);
+               }
+               pci_set_power_state(bp->pdev, PCI_D3hot);
 
                /* No more memory access after this point until
                 * device is brought back to D0.
@@ -6206,7 +6238,7 @@ bnx2_free_irq(struct bnx2 *bp)
 static void
 bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
 {
-       int i, total_vecs, rc;
+       int i, total_vecs;
        struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC];
        struct net_device *dev = bp->dev;
        const int len = sizeof(bp->irq_tbl[0].name);
@@ -6229,16 +6261,9 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
 #ifdef BCM_CNIC
        total_vecs++;
 #endif
-       rc = -ENOSPC;
-       while (total_vecs >= BNX2_MIN_MSIX_VEC) {
-               rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs);
-               if (rc <= 0)
-                       break;
-               if (rc > 0)
-                       total_vecs = rc;
-       }
-
-       if (rc != 0)
+       total_vecs = pci_enable_msix_range(bp->pdev, msix_ent,
+                                          BNX2_MIN_MSIX_VEC, total_vecs);
+       if (total_vecs < 0)
                return;
 
        msix_vecs = total_vecs;
@@ -6611,7 +6636,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
        if (dma_mapping_error(&bp->pdev->dev, mapping)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -6704,7 +6729,7 @@ dma_error:
                               PCI_DMA_TODEVICE);
        }
 
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
index f1cf2c44e7ed549519fe2eaf860d0d01302b032d..e341bc366fa5f1d003a9355516a8ebdd81811ac8 100644 (file)
@@ -6900,6 +6900,7 @@ struct bnx2 {
 
        u16                     fw_wr_seq;
        u16                     fw_drv_pulse_wr_seq;
+       u32                     fw_last_msg;
 
        int                     rx_max_ring;
        int                     rx_ring_size;
@@ -7406,6 +7407,10 @@ struct bnx2_rv2p_fw_file {
 #define BNX2_CONDITION_MFW_RUN_NCSI             0x00006000
 #define BNX2_CONDITION_MFW_RUN_NONE             0x0000e000
 #define BNX2_CONDITION_MFW_RUN_MASK             0x0000e000
+#define BNX2_CONDITION_PM_STATE_MASK            0x00030000
+#define BNX2_CONDITION_PM_STATE_FULL            0x00030000
+#define BNX2_CONDITION_PM_STATE_PREP            0x00020000
+#define BNX2_CONDITION_PM_STATE_UNPREP          0x00010000
 
 #define BNX2_BC_STATE_DEBUG_CMD                        0x1dc
 #define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE      0x42440000
index 391f29ef6d2e172849c61140b7c88f99eff365fb..4d8f8aba0ea5d93be5e288a31da7fc12903af71f 100644 (file)
@@ -26,8 +26,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.78.17-0"
-#define DRV_MODULE_RELDATE      "2013/04/11"
+#define DRV_MODULE_VERSION      "1.78.19-0"
+#define DRV_MODULE_RELDATE      "2014/02/10"
 #define BNX2X_BC_VER            0x040200
 
 #if defined(CONFIG_DCB)
@@ -75,13 +75,22 @@ enum bnx2x_int_mode {
 #define BNX2X_MSG_DCB                  0x8000000
 
 /* regular debug print */
+#define DP_INNER(fmt, ...)                                     \
+       pr_notice("[%s:%d(%s)]" fmt,                            \
+                 __func__, __LINE__,                           \
+                 bp->dev ? (bp->dev->name) : "?",              \
+                 ##__VA_ARGS__);
+
 #define DP(__mask, fmt, ...)                                   \
 do {                                                           \
        if (unlikely(bp->msg_enable & (__mask)))                \
-               pr_notice("[%s:%d(%s)]" fmt,                    \
-                         __func__, __LINE__,                   \
-                         bp->dev ? (bp->dev->name) : "?",      \
-                         ##__VA_ARGS__);                       \
+               DP_INNER(fmt, ##__VA_ARGS__);                   \
+} while (0)
+
+#define DP_AND(__mask, fmt, ...)                               \
+do {                                                           \
+       if (unlikely((bp->msg_enable & (__mask)) == __mask))    \
+               DP_INNER(fmt, ##__VA_ARGS__);                   \
 } while (0)
 
 #define DP_CONT(__mask, fmt, ...)                              \
@@ -1146,10 +1155,6 @@ struct bnx2x_port {
                        (offsetof(struct bnx2x_eth_stats, stat_name) / 4)
 
 /* slow path */
-
-/* slow path work-queue */
-extern struct workqueue_struct *bnx2x_wq;
-
 #define BNX2X_MAX_NUM_OF_VFS   64
 #define BNX2X_VF_CID_WND       4 /* log num of queues per VF. HW config. */
 #define BNX2X_CIDS_PER_VF      (1 << BNX2X_VF_CID_WND)
@@ -1261,6 +1266,7 @@ struct bnx2x_slowpath {
        union {
                struct client_init_ramrod_data  init_data;
                struct client_update_ramrod_data update_data;
+               struct tpa_update_ramrod_data tpa_data;
        } q_rdata;
 
        union {
@@ -1392,7 +1398,7 @@ struct bnx2x_fw_stats_data {
 };
 
 /* Public slow path states */
-enum {
+enum sp_rtnl_flag {
        BNX2X_SP_RTNL_SETUP_TC,
        BNX2X_SP_RTNL_TX_TIMEOUT,
        BNX2X_SP_RTNL_FAN_FAILURE,
@@ -1403,6 +1409,12 @@ enum {
        BNX2X_SP_RTNL_RX_MODE,
        BNX2X_SP_RTNL_HYPERVISOR_VLAN,
        BNX2X_SP_RTNL_TX_STOP,
+       BNX2X_SP_RTNL_GET_DRV_VERSION,
+};
+
+enum bnx2x_iov_flag {
+       BNX2X_IOV_HANDLE_VF_MSG,
+       BNX2X_IOV_HANDLE_FLR,
 };
 
 struct bnx2x_prev_path_list {
@@ -1603,6 +1615,8 @@ struct bnx2x {
        int                     mrrs;
 
        struct delayed_work     sp_task;
+       struct delayed_work     iov_task;
+
        atomic_t                interrupt_occurred;
        struct delayed_work     sp_rtnl_task;
 
@@ -1693,6 +1707,10 @@ struct bnx2x {
        struct bnx2x_slowpath   *slowpath;
        dma_addr_t              slowpath_mapping;
 
+       /* Mechanism protecting the drv_info_to_mcp */
+       struct mutex            drv_info_mutex;
+       bool                    drv_info_mng_owner;
+
        /* Total number of FW statistics requests */
        u8                      fw_stats_num;
 
@@ -1882,6 +1900,9 @@ struct bnx2x {
        /* operation indication for the sp_rtnl task */
        unsigned long                           sp_rtnl_state;
 
+       /* Indication of the IOV tasks */
+       unsigned long                           iov_task_state;
+
        /* DCBX Negotiation results */
        struct dcbx_features                    dcbx_local_feat;
        u32                                     dcbx_error;
@@ -2525,6 +2546,8 @@ enum {
 
 void bnx2x_set_local_cmng(struct bnx2x *bp);
 
+void bnx2x_update_mng_version(struct bnx2x *bp);
+
 #define MCPR_SCRATCH_BASE(bp) \
        (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH)
 
index 9d7419e0390bd526d52e850f0d54c3863c920ffd..9261d5313b5be2bd361612640535fbf9c2810438 100644 (file)
@@ -61,10 +61,14 @@ static void bnx2x_add_all_napi(struct bnx2x *bp)
 
 static int bnx2x_calc_num_queues(struct bnx2x *bp)
 {
-       return  bnx2x_num_queues ?
-                min_t(int, bnx2x_num_queues, BNX2X_MAX_QUEUES(bp)) :
-                min_t(int, netif_get_num_default_rss_queues(),
-                      BNX2X_MAX_QUEUES(bp));
+       int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues();
+
+       /* Reduce memory usage in kdump environment by using only one queue */
+       if (reset_devices)
+               nq = 1;
+
+       nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp));
+       return nq;
 }
 
 /**
@@ -868,6 +872,8 @@ static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
        if (unlikely(bp->panic))
                return 0;
 #endif
+       if (budget <= 0)
+               return rx_pkt;
 
        bd_cons = fp->rx_bd_cons;
        bd_prod = fp->rx_bd_prod;
@@ -1638,36 +1644,16 @@ int bnx2x_enable_msix(struct bnx2x *bp)
        DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
           msix_vec);
 
-       rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec);
-
+       rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0],
+                                  BNX2X_MIN_MSIX_VEC_CNT(bp), msix_vec);
        /*
         * reconfigure number of tx/rx queues according to available
         * MSI-X vectors
         */
-       if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) {
-               /* how less vectors we will have? */
-               int diff = msix_vec - rc;
-
-               BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
-
-               rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc);
-
-               if (rc) {
-                       BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc);
-                       goto no_msix;
-               }
-               /*
-                * decrease number of queues by number of unallocated entries
-                */
-               bp->num_ethernet_queues -= diff;
-               bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
-
-               BNX2X_DEV_INFO("New queue configuration set: %d\n",
-                              bp->num_queues);
-       } else if (rc > 0) {
+       if (rc == -ENOSPC) {
                /* Get by with single vector */
-               rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], 1);
-               if (rc) {
+               rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], 1, 1);
+               if (rc < 0) {
                        BNX2X_DEV_INFO("Single MSI-X is not attainable rc %d\n",
                                       rc);
                        goto no_msix;
@@ -1680,8 +1666,22 @@ int bnx2x_enable_msix(struct bnx2x *bp)
                bp->num_ethernet_queues = 1;
                bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
        } else if (rc < 0) {
-               BNX2X_DEV_INFO("MSI-X is not attainable  rc %d\n", rc);
+               BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc);
                goto no_msix;
+       } else if (rc < msix_vec) {
+               /* how less vectors we will have? */
+               int diff = msix_vec - rc;
+
+               BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
+
+               /*
+                * decrease number of queues by number of unallocated entries
+                */
+               bp->num_ethernet_queues -= diff;
+               bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
+
+               BNX2X_DEV_INFO("New queue configuration set: %d\n",
+                              bp->num_queues);
        }
 
        bp->flags |= USING_MSIX_FLAG;
@@ -1873,7 +1873,7 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
 }
 
 u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
-                      void *accel_priv)
+                      void *accel_priv, select_queue_fallback_t fallback)
 {
        struct bnx2x *bp = netdev_priv(dev);
 
@@ -1895,7 +1895,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
        }
 
        /* select a non-FCoE queue */
-       return __netdev_pick_tx(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
+       return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp);
 }
 
 void bnx2x_set_num_queues(struct bnx2x *bp)
@@ -2234,8 +2234,10 @@ static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
                sizeof(struct per_queue_stats) * num_queue_stats +
                sizeof(struct stats_counter);
 
-       BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping,
-                       bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+       bp->fw_stats = BNX2X_PCI_ALLOC(&bp->fw_stats_mapping,
+                                      bp->fw_stats_data_sz + bp->fw_stats_req_sz);
+       if (!bp->fw_stats)
+               goto alloc_mem_err;
 
        /* Set shortcuts */
        bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats;
@@ -2802,6 +2804,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
        if (CNIC_ENABLED(bp))
                bnx2x_load_cnic(bp);
 
+       if (IS_PF(bp))
+               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
+
        if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) {
                /* mark driver is loaded in shmem2 */
                u32 val;
@@ -3028,6 +3033,10 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link)
        bp->state = BNX2X_STATE_CLOSED;
        bp->cnic_loaded = false;
 
+       /* Clear driver version indication in shmem */
+       if (IS_PF(bp))
+               bnx2x_update_mng_version(bp);
+
        /* Check if there are pending parity attentions. If there are - set
         * RECOVERY_IN_PROGRESS.
         */
@@ -3875,7 +3884,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                                     xmit_type);
                }
 
-               /* Add the macs to the parsing BD this is a vf */
+               /* Add the macs to the parsing BD if this is a vf or if
+                * Tx Switching is enabled.
+                */
                if (IS_VF(bp)) {
                        /* override GRE parameters in BD */
                        bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi,
@@ -3883,6 +3894,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                              &pbd_e2->data.mac_addr.src_lo,
                                              eth->h_source);
 
+                       bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
+                                             &pbd_e2->data.mac_addr.dst_mid,
+                                             &pbd_e2->data.mac_addr.dst_lo,
+                                             eth->h_dest);
+               } else if (bp->flags & TX_SWITCHING) {
                        bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi,
                                              &pbd_e2->data.mac_addr.dst_mid,
                                              &pbd_e2->data.mac_addr.dst_lo,
@@ -4363,14 +4379,17 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
 
        if (!IS_FCOE_IDX(index)) {
                /* status blocks */
-               if (!CHIP_IS_E1x(bp))
-                       BNX2X_PCI_ALLOC(sb->e2_sb,
-                               &bnx2x_fp(bp, index, status_blk_mapping),
-                               sizeof(struct host_hc_status_block_e2));
-               else
-                       BNX2X_PCI_ALLOC(sb->e1x_sb,
-                               &bnx2x_fp(bp, index, status_blk_mapping),
-                           sizeof(struct host_hc_status_block_e1x));
+               if (!CHIP_IS_E1x(bp)) {
+                       sb->e2_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping),
+                                                   sizeof(struct host_hc_status_block_e2));
+                       if (!sb->e2_sb)
+                               goto alloc_mem_err;
+               } else {
+                       sb->e1x_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping),
+                                                    sizeof(struct host_hc_status_block_e1x));
+                       if (!sb->e1x_sb)
+                               goto alloc_mem_err;
+               }
        }
 
        /* FCoE Queue uses Default SB and doesn't ACK the SB, thus no need to
@@ -4389,35 +4408,49 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
                           "allocating tx memory of fp %d cos %d\n",
                           index, cos);
 
-                       BNX2X_ALLOC(txdata->tx_buf_ring,
-                               sizeof(struct sw_tx_bd) * NUM_TX_BD);
-                       BNX2X_PCI_ALLOC(txdata->tx_desc_ring,
-                               &txdata->tx_desc_mapping,
-                               sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+                       txdata->tx_buf_ring = kcalloc(NUM_TX_BD,
+                                                     sizeof(struct sw_tx_bd),
+                                                     GFP_KERNEL);
+                       if (!txdata->tx_buf_ring)
+                               goto alloc_mem_err;
+                       txdata->tx_desc_ring = BNX2X_PCI_ALLOC(&txdata->tx_desc_mapping,
+                                                              sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+                       if (!txdata->tx_desc_ring)
+                               goto alloc_mem_err;
                }
        }
 
        /* Rx */
        if (!skip_rx_queue(bp, index)) {
                /* fastpath rx rings: rx_buf rx_desc rx_comp */
-               BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring),
-                               sizeof(struct sw_rx_bd) * NUM_RX_BD);
-               BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring),
-                               &bnx2x_fp(bp, index, rx_desc_mapping),
-                               sizeof(struct eth_rx_bd) * NUM_RX_BD);
+               bnx2x_fp(bp, index, rx_buf_ring) =
+                       kcalloc(NUM_RX_BD, sizeof(struct sw_rx_bd), GFP_KERNEL);
+               if (!bnx2x_fp(bp, index, rx_buf_ring))
+                       goto alloc_mem_err;
+               bnx2x_fp(bp, index, rx_desc_ring) =
+                       BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_desc_mapping),
+                                       sizeof(struct eth_rx_bd) * NUM_RX_BD);
+               if (!bnx2x_fp(bp, index, rx_desc_ring))
+                       goto alloc_mem_err;
 
                /* Seed all CQEs by 1s */
-               BNX2X_PCI_FALLOC(bnx2x_fp(bp, index, rx_comp_ring),
-                                &bnx2x_fp(bp, index, rx_comp_mapping),
-                                sizeof(struct eth_fast_path_rx_cqe) *
-                                NUM_RCQ_BD);
+               bnx2x_fp(bp, index, rx_comp_ring) =
+                       BNX2X_PCI_FALLOC(&bnx2x_fp(bp, index, rx_comp_mapping),
+                                        sizeof(struct eth_fast_path_rx_cqe) * NUM_RCQ_BD);
+               if (!bnx2x_fp(bp, index, rx_comp_ring))
+                       goto alloc_mem_err;
 
                /* SGE ring */
-               BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring),
-                               sizeof(struct sw_rx_page) * NUM_RX_SGE);
-               BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring),
-                               &bnx2x_fp(bp, index, rx_sge_mapping),
-                               BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+               bnx2x_fp(bp, index, rx_page_ring) =
+                       kcalloc(NUM_RX_SGE, sizeof(struct sw_rx_page),
+                               GFP_KERNEL);
+               if (!bnx2x_fp(bp, index, rx_page_ring))
+                       goto alloc_mem_err;
+               bnx2x_fp(bp, index, rx_sge_ring) =
+                       BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_sge_mapping),
+                                       BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+               if (!bnx2x_fp(bp, index, rx_sge_ring))
+                       goto alloc_mem_err;
                /* RX BD ring */
                bnx2x_set_next_page_rx_bd(fp);
 
@@ -4773,12 +4806,8 @@ void bnx2x_tx_timeout(struct net_device *dev)
                bnx2x_panic();
 #endif
 
-       smp_mb__before_clear_bit();
-       set_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state);
-       smp_mb__after_clear_bit();
-
        /* This allows the netif to be shutdown gracefully before resetting */
-       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_TIMEOUT, 0);
 }
 
 int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -4906,3 +4935,15 @@ void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id,
        disable = disable ? 1 : (usec ? 0 : 1);
        storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable);
 }
+
+void bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag,
+                           u32 verbose)
+{
+       smp_mb__before_clear_bit();
+       set_bit(flag, &bp->sp_rtnl_state);
+       smp_mb__after_clear_bit();
+       DP((BNX2X_MSG_SP | verbose), "Scheduling sp_rtnl task [Flag: %d]\n",
+          flag);
+       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+}
+EXPORT_SYMBOL(bnx2x_schedule_sp_rtnl);
index 17d1689aec6b83cd002bed8a62ad7b6d06cba1b6..05f4f5f52635b64668a3397427c6b1483f057eb7 100644 (file)
@@ -47,31 +47,26 @@ extern int bnx2x_num_queues;
                } \
        } while (0)
 
-#define BNX2X_PCI_ALLOC(x, y, size) \
-       do { \
-               x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
-               if (x == NULL) \
-                       goto alloc_mem_err; \
-               DP(NETIF_MSG_HW, "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \
-                  (unsigned long long)(*y), x); \
-       } while (0)
-
-#define BNX2X_PCI_FALLOC(x, y, size) \
-       do { \
-               x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
-               if (x == NULL) \
-                       goto alloc_mem_err; \
-               memset((void *)x, 0xFFFFFFFF, size); \
-               DP(NETIF_MSG_HW, "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n",\
-                  (unsigned long long)(*y), x); \
-       } while (0)
-
-#define BNX2X_ALLOC(x, size) \
-       do { \
-               x = kzalloc(size, GFP_KERNEL); \
-               if (x == NULL) \
-                       goto alloc_mem_err; \
-       } while (0)
+#define BNX2X_PCI_ALLOC(y, size)                                       \
+({                                                                     \
+       void *x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+       if (x)                                                          \
+               DP(NETIF_MSG_HW,                                        \
+                  "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n",        \
+                  (unsigned long long)(*y), x);                        \
+       x;                                                              \
+})
+#define BNX2X_PCI_FALLOC(y, size)                                      \
+({                                                                     \
+       void *x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+       if (x) {                                                        \
+               memset(x, 0xff, size);                                  \
+               DP(NETIF_MSG_HW,                                        \
+                  "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n",       \
+                  (unsigned long long)(*y), x);                        \
+       }                                                               \
+       x;                                                              \
+})
 
 /*********************** Interfaces ****************************
  *  Functions that need to be implemented by each driver version
@@ -496,7 +491,7 @@ int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos);
 
 /* select_queue callback */
 u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb,
-                      void *accel_priv);
+                      void *accel_priv, select_queue_fallback_t fallback);
 
 static inline void bnx2x_update_rx_prod(struct bnx2x *bp,
                                        struct bnx2x_fastpath *fp,
@@ -936,7 +931,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp)
        else /* CHIP_IS_E1X */
                start_params->network_cos_mode = FW_WRR;
 
-       start_params->gre_tunnel_mode = IPGRE_TUNNEL;
+       start_params->gre_tunnel_mode = L2GRE_TUNNEL;
        start_params->gre_tunnel_rss = GRE_INNER_HEADERS_RSS;
 
        return bnx2x_func_state_change(bp, &func_params);
@@ -1324,4 +1319,7 @@ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len);
 int bnx2x_drain_tx_queues(struct bnx2x *bp);
 void bnx2x_squeeze_objects(struct bnx2x *bp);
 
+void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag,
+                           u32 verbose);
+
 #endif /* BNX2X_CMN_H */
index fdace204b0549aa2599edd67c1c3112e0c4bf9de..97ea5421dd96f41bc3daf7a899ef9f1ddaab0931 100644 (file)
@@ -710,8 +710,7 @@ static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp)
         * as we are handling an attention on a work queue which must be
         * flushed at some rtnl-locked contexts (e.g. if down)
         */
-       if (!test_and_set_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state))
-               schedule_delayed_work(&bp->sp_rtnl_task, 0);
+       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_SETUP_TC, 0);
 }
 
 void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
@@ -764,10 +763,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
                        if (IS_MF(bp))
                                bnx2x_link_sync_notify(bp);
 
-                       set_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state);
-
-                       schedule_delayed_work(&bp->sp_rtnl_task, 0);
-
+                       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_STOP, 0);
                        return;
                }
        case BNX2X_DCBX_STATE_TX_PAUSED:
index 38fc794c1655d9d011d425ccce35cfa41ee43889..b6de05e3149b5604d818d5496cbbc23ab7bf64e8 100644 (file)
@@ -2969,8 +2969,9 @@ static void bnx2x_self_test(struct net_device *dev,
 #define IS_PORT_STAT(i) \
        ((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT)
 #define IS_FUNC_STAT(i)                (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC)
-#define IS_MF_MODE_STAT(bp) \
-                       (IS_MF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS))
+#define HIDE_PORT_STAT(bp) \
+               ((IS_MF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS)) || \
+                IS_VF(bp))
 
 /* ethtool statistics are displayed for all regular ethernet queues and the
  * fcoe L2 queue if not disabled
@@ -2992,7 +2993,7 @@ static int bnx2x_get_sset_count(struct net_device *dev, int stringset)
                                      BNX2X_NUM_Q_STATS;
                } else
                        num_strings = 0;
-               if (IS_MF_MODE_STAT(bp)) {
+               if (HIDE_PORT_STAT(bp)) {
                        for (i = 0; i < BNX2X_NUM_STATS; i++)
                                if (IS_FUNC_STAT(i))
                                        num_strings++;
@@ -3047,7 +3048,7 @@ static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
                }
 
                for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
-                       if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
+                       if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i))
                                continue;
                        strcpy(buf + (k + j)*ETH_GSTRING_LEN,
                                   bnx2x_stats_arr[i].string);
@@ -3105,7 +3106,7 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
 
        hw_stats = (u32 *)&bp->eth_stats;
        for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) {
-               if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i))
+               if (HIDE_PORT_STAT(bp) && IS_PORT_STAT(i))
                        continue;
                if (bnx2x_stats_arr[i].size == 0) {
                        /* skip this counter */
index 84aecdf06f7a7cc807993952eedd01d483e739f7..95dc365435483ed9298389b88f965130d48eb7d0 100644 (file)
@@ -87,7 +87,6 @@
        (IRO[156].base + ((vfId) * IRO[156].m1))
 #define CSTORM_VF_TO_PF_OFFSET(funcId) \
        (IRO[150].base + ((funcId) * IRO[150].m1))
-#define TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET (IRO[204].base)
 #define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \
        (IRO[203].base + ((pfId) * IRO[203].m1))
 #define TSTORM_ASSERT_LIST_INDEX_OFFSET        (IRO[102].base)
index cf1df8b62e2c2785c0560b77ac5ed4b5fc8ae8b3..5ba8af50c84f2bb3ebf9300c9ad8765d25a06a8d 100644 (file)
@@ -2003,6 +2003,23 @@ struct shmem_lfa {
        #define SHMEM_LFA_DONT_CLEAR_STAT               (1<<24)
 };
 
+/* Used to support NSCI get OS driver version
+ * on driver load the version value will be set
+ * on driver unload driver value of 0x0 will be set.
+ */
+struct os_drv_ver {
+#define DRV_VER_NOT_LOADED                     0
+
+       /* personalties order is important */
+#define DRV_PERS_ETHERNET                      0
+#define DRV_PERS_ISCSI                         1
+#define DRV_PERS_FCOE                          2
+
+       /* shmem2 struct is constant can't add more personalties here */
+#define MAX_DRV_PERS                           3
+       u32 versions[MAX_DRV_PERS];
+};
+
 struct ncsi_oem_fcoe_features {
        u32 fcoe_features1;
        #define FCOE_FEATURES1_IOS_PER_CONNECTION_MASK          0x0000FFFF
@@ -2217,6 +2234,18 @@ struct shmem2_region {
        u32 reserved4;                          /* Offset 0x150 */
        u32 link_attr_sync[PORT_MAX];           /* Offset 0x154 */
        #define LINK_ATTR_SYNC_KR2_ENABLE       (1<<0)
+
+       u32 reserved5[2];
+       u32 reserved6[PORT_MAX];
+
+       /* driver version for each personality */
+       struct os_drv_ver func_os_drv_ver[E2_FUNC_MAX]; /* Offset 0x16c */
+
+       /* Flag to the driver that PF's drv_info_host_addr buffer was read  */
+       u32 mfw_drv_indication;
+
+       /* We use indication for each PF (0..3) */
+#define MFW_DRV_IND_READ_DONE_OFFSET(_pf_) (1 << (_pf_))
 };
 
 
@@ -2848,7 +2877,7 @@ struct afex_stats {
 
 #define BCM_5710_FW_MAJOR_VERSION                      7
 #define BCM_5710_FW_MINOR_VERSION                      8
-#define BCM_5710_FW_REVISION_VERSION           17
+#define BCM_5710_FW_REVISION_VERSION           19
 #define BCM_5710_FW_ENGINEERING_VERSION                0
 #define BCM_5710_FW_COMPILE_FLAGS                      1
 
index c9c445e7b4a5ab0d756880926fc529ed538a70a6..a78edaccceee92d8f2439ac40f3b3ba887ec0000 100644 (file)
@@ -95,32 +95,33 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1H);
 MODULE_FIRMWARE(FW_FILE_NAME_E2);
 
 int bnx2x_num_queues;
-module_param_named(num_queues, bnx2x_num_queues, int, 0);
+module_param_named(num_queues, bnx2x_num_queues, int, S_IRUGO);
 MODULE_PARM_DESC(num_queues,
                 " Set number of queues (default is as a number of CPUs)");
 
 static int disable_tpa;
-module_param(disable_tpa, int, 0);
+module_param(disable_tpa, int, S_IRUGO);
 MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");
 
 static int int_mode;
-module_param(int_mode, int, 0);
+module_param(int_mode, int, S_IRUGO);
 MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
                                "(1 INT#x; 2 MSI)");
 
 static int dropless_fc;
-module_param(dropless_fc, int, 0);
+module_param(dropless_fc, int, S_IRUGO);
 MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");
 
 static int mrrs = -1;
-module_param(mrrs, int, 0);
+module_param(mrrs, int, S_IRUGO);
 MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");
 
 static int debug;
-module_param(debug, int, 0);
+module_param(debug, int, S_IRUGO);
 MODULE_PARM_DESC(debug, " Default debug msglevel");
 
-struct workqueue_struct *bnx2x_wq;
+static struct workqueue_struct *bnx2x_wq;
+struct workqueue_struct *bnx2x_iov_wq;
 
 struct bnx2x_mac_vals {
        u32 xmac_addr;
@@ -918,7 +919,7 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
        u16 start = 0, end = 0;
        u8 cos;
 #endif
-       if (disable_int)
+       if (IS_PF(bp) && disable_int)
                bnx2x_int_disable(bp);
 
        bp->stats_state = STATS_STATE_DISABLED;
@@ -929,33 +930,41 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
 
        /* Indices */
        /* Common */
-       BNX2X_ERR("def_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)  spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
-                 bp->def_idx, bp->def_att_idx, bp->attn_state,
-                 bp->spq_prod_idx, bp->stats_counter);
-       BNX2X_ERR("DSB: attn bits(0x%x)  ack(0x%x)  id(0x%x)  idx(0x%x)\n",
-                 bp->def_status_blk->atten_status_block.attn_bits,
-                 bp->def_status_blk->atten_status_block.attn_bits_ack,
-                 bp->def_status_blk->atten_status_block.status_block_id,
-                 bp->def_status_blk->atten_status_block.attn_bits_index);
-       BNX2X_ERR("     def (");
-       for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
-               pr_cont("0x%x%s",
-                       bp->def_status_blk->sp_sb.index_values[i],
-                       (i == HC_SP_SB_MAX_INDICES - 1) ? ")  " : " ");
-
-       for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++)
-               *((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM +
-                       CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) +
-                       i*sizeof(u32));
-
-       pr_cont("igu_sb_id(0x%x)  igu_seg_id(0x%x) pf_id(0x%x)  vnic_id(0x%x)  vf_id(0x%x)  vf_valid (0x%x) state(0x%x)\n",
-              sp_sb_data.igu_sb_id,
-              sp_sb_data.igu_seg_id,
-              sp_sb_data.p_func.pf_id,
-              sp_sb_data.p_func.vnic_id,
-              sp_sb_data.p_func.vf_id,
-              sp_sb_data.p_func.vf_valid,
-              sp_sb_data.state);
+       if (IS_PF(bp)) {
+               struct host_sp_status_block *def_sb = bp->def_status_blk;
+               int data_size, cstorm_offset;
+
+               BNX2X_ERR("def_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)  spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
+                         bp->def_idx, bp->def_att_idx, bp->attn_state,
+                         bp->spq_prod_idx, bp->stats_counter);
+               BNX2X_ERR("DSB: attn bits(0x%x)  ack(0x%x)  id(0x%x)  idx(0x%x)\n",
+                         def_sb->atten_status_block.attn_bits,
+                         def_sb->atten_status_block.attn_bits_ack,
+                         def_sb->atten_status_block.status_block_id,
+                         def_sb->atten_status_block.attn_bits_index);
+               BNX2X_ERR("     def (");
+               for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
+                       pr_cont("0x%x%s",
+                               def_sb->sp_sb.index_values[i],
+                               (i == HC_SP_SB_MAX_INDICES - 1) ? ")  " : " ");
+
+               data_size = sizeof(struct hc_sp_status_block_data) /
+                           sizeof(u32);
+               cstorm_offset = CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func);
+               for (i = 0; i < data_size; i++)
+                       *((u32 *)&sp_sb_data + i) =
+                               REG_RD(bp, BAR_CSTRORM_INTMEM + cstorm_offset +
+                                          i * sizeof(u32));
+
+               pr_cont("igu_sb_id(0x%x)  igu_seg_id(0x%x) pf_id(0x%x)  vnic_id(0x%x)  vf_id(0x%x)  vf_valid (0x%x) state(0x%x)\n",
+                       sp_sb_data.igu_sb_id,
+                       sp_sb_data.igu_seg_id,
+                       sp_sb_data.p_func.pf_id,
+                       sp_sb_data.p_func.vnic_id,
+                       sp_sb_data.p_func.vf_id,
+                       sp_sb_data.p_func.vf_valid,
+                       sp_sb_data.state);
+       }
 
        for_each_eth_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
@@ -1013,6 +1022,11 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
                        pr_cont("0x%x%s",
                               fp->sb_index_values[j],
                               (j == loop - 1) ? ")" : " ");
+
+               /* VF cannot access FW refelection for status block */
+               if (IS_VF(bp))
+                       continue;
+
                /* fw sb data */
                data_size = CHIP_IS_E1x(bp) ?
                        sizeof(struct hc_status_block_data_e1x) :
@@ -1064,16 +1078,18 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
        }
 
 #ifdef BNX2X_STOP_ON_ERROR
-
-       /* event queue */
-       BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
-       for (i = 0; i < NUM_EQ_DESC; i++) {
-               u32 *data = (u32 *)&bp->eq_ring[i].message.data;
-
-               BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
-                         i, bp->eq_ring[i].message.opcode,
-                         bp->eq_ring[i].message.error);
-               BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]);
+       if (IS_PF(bp)) {
+               /* event queue */
+               BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
+               for (i = 0; i < NUM_EQ_DESC; i++) {
+                       u32 *data = (u32 *)&bp->eq_ring[i].message.data;
+
+                       BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
+                                 i, bp->eq_ring[i].message.opcode,
+                                 bp->eq_ring[i].message.error);
+                       BNX2X_ERR("data: %x %x %x\n",
+                                 data[0], data[1], data[2]);
+               }
        }
 
        /* Rings */
@@ -1140,8 +1156,10 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
                }
        }
 #endif
-       bnx2x_fw_dump(bp);
-       bnx2x_mc_assert(bp);
+       if (IS_PF(bp)) {
+               bnx2x_fw_dump(bp);
+               bnx2x_mc_assert(bp);
+       }
        BNX2X_ERR("end crash dump -----------------\n");
 }
 
@@ -1814,6 +1832,11 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
                drv_cmd = BNX2X_Q_CMD_EMPTY;
                break;
 
+       case (RAMROD_CMD_ID_ETH_TPA_UPDATE):
+               DP(BNX2X_MSG_SP, "got tpa update ramrod CID=%d\n", cid);
+               drv_cmd = BNX2X_Q_CMD_UPDATE_TPA;
+               break;
+
        default:
                BNX2X_ERR("unexpected MC reply (%d) on fp[%d]\n",
                          command, fp->index);
@@ -1834,8 +1857,6 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
 #else
                return;
 #endif
-       /* SRIOV: reschedule any 'in_progress' operations */
-       bnx2x_iov_sp_event(bp, cid, true);
 
        smp_mb__before_atomic_inc();
        atomic_inc(&bp->cq_spq_left);
@@ -3460,10 +3481,15 @@ static void bnx2x_handle_eee_event(struct bnx2x *bp)
        bnx2x_fw_command(bp, DRV_MSG_CODE_EEE_RESULTS_ACK, 0);
 }
 
+#define BNX2X_UPDATE_DRV_INFO_IND_LENGTH       (20)
+#define BNX2X_UPDATE_DRV_INFO_IND_COUNT                (25)
+
 static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
 {
        enum drv_info_opcode op_code;
        u32 drv_info_ctl = SHMEM2_RD(bp, drv_info_control);
+       bool release = false;
+       int wait;
 
        /* if drv_info version supported by MFW doesn't match - send NACK */
        if ((drv_info_ctl & DRV_INFO_CONTROL_VER_MASK) != DRV_INFO_CUR_VER) {
@@ -3474,6 +3500,9 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
        op_code = (drv_info_ctl & DRV_INFO_CONTROL_OP_CODE_MASK) >>
                  DRV_INFO_CONTROL_OP_CODE_SHIFT;
 
+       /* Must prevent other flows from accessing drv_info_to_mcp */
+       mutex_lock(&bp->drv_info_mutex);
+
        memset(&bp->slowpath->drv_info_to_mcp, 0,
               sizeof(union drv_info_to_mcp));
 
@@ -3490,7 +3519,7 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
        default:
                /* if op code isn't supported - send NACK */
                bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_NACK, 0);
-               return;
+               goto out;
        }
 
        /* if we got drv_info attn from MFW then these fields are defined in
@@ -3502,6 +3531,106 @@ static void bnx2x_handle_drv_info_req(struct bnx2x *bp)
                U64_HI(bnx2x_sp_mapping(bp, drv_info_to_mcp)));
 
        bnx2x_fw_command(bp, DRV_MSG_CODE_DRV_INFO_ACK, 0);
+
+       /* Since possible management wants both this and get_driver_version
+        * need to wait until management notifies us it finished utilizing
+        * the buffer.
+        */
+       if (!SHMEM2_HAS(bp, mfw_drv_indication)) {
+               DP(BNX2X_MSG_MCP, "Management does not support indication\n");
+       } else if (!bp->drv_info_mng_owner) {
+               u32 bit = MFW_DRV_IND_READ_DONE_OFFSET((BP_ABS_FUNC(bp) >> 1));
+
+               for (wait = 0; wait < BNX2X_UPDATE_DRV_INFO_IND_COUNT; wait++) {
+                       u32 indication = SHMEM2_RD(bp, mfw_drv_indication);
+
+                       /* Management is done; need to clear indication */
+                       if (indication & bit) {
+                               SHMEM2_WR(bp, mfw_drv_indication,
+                                         indication & ~bit);
+                               release = true;
+                               break;
+                       }
+
+                       msleep(BNX2X_UPDATE_DRV_INFO_IND_LENGTH);
+               }
+       }
+       if (!release) {
+               DP(BNX2X_MSG_MCP, "Management did not release indication\n");
+               bp->drv_info_mng_owner = true;
+       }
+
+out:
+       mutex_unlock(&bp->drv_info_mutex);
+}
+
+static u32 bnx2x_update_mng_version_utility(u8 *version, bool bnx2x_format)
+{
+       u8 vals[4];
+       int i = 0;
+
+       if (bnx2x_format) {
+               i = sscanf(version, "1.%c%hhd.%hhd.%hhd",
+                          &vals[0], &vals[1], &vals[2], &vals[3]);
+               if (i > 0)
+                       vals[0] -= '0';
+       } else {
+               i = sscanf(version, "%hhd.%hhd.%hhd.%hhd",
+                          &vals[0], &vals[1], &vals[2], &vals[3]);
+       }
+
+       while (i < 4)
+               vals[i++] = 0;
+
+       return (vals[0] << 24) | (vals[1] << 16) | (vals[2] << 8) | vals[3];
+}
+
+void bnx2x_update_mng_version(struct bnx2x *bp)
+{
+       u32 iscsiver = DRV_VER_NOT_LOADED;
+       u32 fcoever = DRV_VER_NOT_LOADED;
+       u32 ethver = DRV_VER_NOT_LOADED;
+       int idx = BP_FW_MB_IDX(bp);
+       u8 *version;
+
+       if (!SHMEM2_HAS(bp, func_os_drv_ver))
+               return;
+
+       mutex_lock(&bp->drv_info_mutex);
+       /* Must not proceed when `bnx2x_handle_drv_info_req' is feasible */
+       if (bp->drv_info_mng_owner)
+               goto out;
+
+       if (bp->state != BNX2X_STATE_OPEN)
+               goto out;
+
+       /* Parse ethernet driver version */
+       ethver = bnx2x_update_mng_version_utility(DRV_MODULE_VERSION, true);
+       if (!CNIC_LOADED(bp))
+               goto out;
+
+       /* Try getting storage driver version via cnic */
+       memset(&bp->slowpath->drv_info_to_mcp, 0,
+              sizeof(union drv_info_to_mcp));
+       bnx2x_drv_info_iscsi_stat(bp);
+       version = bp->slowpath->drv_info_to_mcp.iscsi_stat.version;
+       iscsiver = bnx2x_update_mng_version_utility(version, false);
+
+       memset(&bp->slowpath->drv_info_to_mcp, 0,
+              sizeof(union drv_info_to_mcp));
+       bnx2x_drv_info_fcoe_stat(bp);
+       version = bp->slowpath->drv_info_to_mcp.fcoe_stat.version;
+       fcoever = bnx2x_update_mng_version_utility(version, false);
+
+out:
+       SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_ETHERNET], ethver);
+       SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_ISCSI], iscsiver);
+       SHMEM2_WR(bp, func_os_drv_ver[idx].versions[DRV_PERS_FCOE], fcoever);
+
+       mutex_unlock(&bp->drv_info_mutex);
+
+       DP(BNX2X_MSG_MCP, "Setting driver version: ETH [%08x] iSCSI [%08x] FCoE [%08x]\n",
+          ethver, iscsiver, fcoever);
 }
 
 static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
@@ -3644,10 +3773,18 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
                        cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) |
                                    HW_CID(bp, cid));
 
-       type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) & SPE_HDR_CONN_TYPE;
-
-       type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) &
-                SPE_HDR_FUNCTION_ID);
+       /* In some cases, type may already contain the func-id
+        * mainly in SRIOV related use cases, so we add it here only
+        * if it's not already set.
+        */
+       if (!(cmd_type & SPE_HDR_FUNCTION_ID)) {
+               type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) &
+                       SPE_HDR_CONN_TYPE;
+               type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) &
+                        SPE_HDR_FUNCTION_ID);
+       } else {
+               type = cmd_type;
+       }
 
        spe->hdr.type = cpu_to_le16(type);
 
@@ -3878,10 +4015,7 @@ static void bnx2x_fan_failure(struct bnx2x *bp)
         * This is due to some boards consuming sufficient power when driver is
         * up to overheat if fan fails.
         */
-       smp_mb__before_clear_bit();
-       set_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state);
-       smp_mb__after_clear_bit();
-       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_FAN_FAILURE, 0);
 }
 
 static void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn)
@@ -4025,7 +4159,8 @@ static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
                                bnx2x_handle_drv_info_req(bp);
 
                        if (val & DRV_STATUS_VF_DISABLED)
-                               bnx2x_vf_handle_flr_event(bp);
+                               bnx2x_schedule_iov_task(bp,
+                                                       BNX2X_IOV_HANDLE_FLR);
 
                        if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
                                bnx2x_pmf_update(bp);
@@ -5216,14 +5351,14 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                /* handle eq element */
                switch (opcode) {
                case EVENT_RING_OPCODE_VF_PF_CHANNEL:
-                       DP(BNX2X_MSG_IOV, "vf pf channel element on eq\n");
-                       bnx2x_vf_mbx(bp, &elem->message.data.vf_pf_event);
+                       bnx2x_vf_mbx_schedule(bp,
+                                             &elem->message.data.vf_pf_event);
                        continue;
 
                case EVENT_RING_OPCODE_STAT_QUERY:
-                       DP(BNX2X_MSG_SP | BNX2X_MSG_STATS,
-                          "got statistics comp event %d\n",
-                          bp->stats_comp++);
+                       DP_AND((BNX2X_MSG_SP | BNX2X_MSG_STATS),
+                              "got statistics comp event %d\n",
+                              bp->stats_comp++);
                        /* nothing to do with stats comp */
                        goto next_spqe;
 
@@ -5273,6 +5408,8 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                                        break;
 
                        } else {
+                               int cmd = BNX2X_SP_RTNL_AFEX_F_UPDATE;
+
                                DP(BNX2X_MSG_SP | BNX2X_MSG_MCP,
                                   "AFEX: ramrod completed FUNCTION_UPDATE\n");
                                f_obj->complete_cmd(bp, f_obj,
@@ -5282,12 +5419,7 @@ static void bnx2x_eq_int(struct bnx2x *bp)
                                 * sp_rtnl task as all Queue SP operations
                                 * should run under rtnl_lock.
                                 */
-                               smp_mb__before_clear_bit();
-                               set_bit(BNX2X_SP_RTNL_AFEX_F_UPDATE,
-                                       &bp->sp_rtnl_state);
-                               smp_mb__after_clear_bit();
-
-                               schedule_delayed_work(&bp->sp_rtnl_task, 0);
+                               bnx2x_schedule_sp_rtnl(bp, cmd, 0);
                        }
 
                        goto next_spqe;
@@ -5435,13 +5567,6 @@ static void bnx2x_sp_task(struct work_struct *work)
                             le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1);
        }
 
-       /* must be called after the EQ processing (since eq leads to sriov
-        * ramrod completion flows).
-        * This flow may have been scheduled by the arrival of a ramrod
-        * completion, or by the sriov code rescheduling itself.
-        */
-       bnx2x_iov_sp_task(bp);
-
        /* afex - poll to check if VIFSET_ACK should be sent to MFW */
        if (test_and_clear_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK,
                               &bp->sp_state)) {
@@ -6005,18 +6130,6 @@ static void bnx2x_init_internal_common(struct bnx2x *bp)
 {
        int i;
 
-       if (IS_MF_SI(bp))
-               /*
-                * In switch independent mode, the TSTORM needs to accept
-                * packets that failed classification, since approximate match
-                * mac addresses aren't written to NIG LLH
-                */
-               REG_WR8(bp, BAR_TSTRORM_INTMEM +
-                           TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 2);
-       else if (!CHIP_IS_E1(bp)) /* 57710 doesn't support MF */
-               REG_WR8(bp, BAR_TSTRORM_INTMEM +
-                           TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 0);
-
        /* Zero this manually as its initialization is
           currently missing in the initTool */
        for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++)
@@ -7989,19 +8102,25 @@ void bnx2x_free_mem(struct bnx2x *bp)
 
 int bnx2x_alloc_mem_cnic(struct bnx2x *bp)
 {
-       if (!CHIP_IS_E1x(bp))
+       if (!CHIP_IS_E1x(bp)) {
                /* size = the status block + ramrod buffers */
-               BNX2X_PCI_ALLOC(bp->cnic_sb.e2_sb, &bp->cnic_sb_mapping,
-                               sizeof(struct host_hc_status_block_e2));
-       else
-               BNX2X_PCI_ALLOC(bp->cnic_sb.e1x_sb,
-                               &bp->cnic_sb_mapping,
-                               sizeof(struct
-                                      host_hc_status_block_e1x));
+               bp->cnic_sb.e2_sb = BNX2X_PCI_ALLOC(&bp->cnic_sb_mapping,
+                                                   sizeof(struct host_hc_status_block_e2));
+               if (!bp->cnic_sb.e2_sb)
+                       goto alloc_mem_err;
+       } else {
+               bp->cnic_sb.e1x_sb = BNX2X_PCI_ALLOC(&bp->cnic_sb_mapping,
+                                                    sizeof(struct host_hc_status_block_e1x));
+               if (!bp->cnic_sb.e1x_sb)
+                       goto alloc_mem_err;
+       }
 
-       if (CONFIGURE_NIC_MODE(bp) && !bp->t2)
+       if (CONFIGURE_NIC_MODE(bp) && !bp->t2) {
                /* allocate searcher T2 table, as it wasn't allocated before */
-               BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
+               bp->t2 = BNX2X_PCI_ALLOC(&bp->t2_mapping, SRC_T2_SZ);
+               if (!bp->t2)
+                       goto alloc_mem_err;
+       }
 
        /* write address to which L5 should insert its values */
        bp->cnic_eth_dev.addr_drv_info_to_mcp =
@@ -8022,15 +8141,22 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
 {
        int i, allocated, context_size;
 
-       if (!CONFIGURE_NIC_MODE(bp) && !bp->t2)
+       if (!CONFIGURE_NIC_MODE(bp) && !bp->t2) {
                /* allocate searcher T2 table */
-               BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ);
+               bp->t2 = BNX2X_PCI_ALLOC(&bp->t2_mapping, SRC_T2_SZ);
+               if (!bp->t2)
+                       goto alloc_mem_err;
+       }
 
-       BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping,
-                       sizeof(struct host_sp_status_block));
+       bp->def_status_blk = BNX2X_PCI_ALLOC(&bp->def_status_blk_mapping,
+                                            sizeof(struct host_sp_status_block));
+       if (!bp->def_status_blk)
+               goto alloc_mem_err;
 
-       BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
-                       sizeof(struct bnx2x_slowpath));
+       bp->slowpath = BNX2X_PCI_ALLOC(&bp->slowpath_mapping,
+                                      sizeof(struct bnx2x_slowpath));
+       if (!bp->slowpath)
+               goto alloc_mem_err;
 
        /* Allocate memory for CDU context:
         * This memory is allocated separately and not in the generic ILT
@@ -8050,12 +8176,16 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
        for (i = 0, allocated = 0; allocated < context_size; i++) {
                bp->context[i].size = min(CDU_ILT_PAGE_SZ,
                                          (context_size - allocated));
-               BNX2X_PCI_ALLOC(bp->context[i].vcxt,
-                               &bp->context[i].cxt_mapping,
-                               bp->context[i].size);
+               bp->context[i].vcxt = BNX2X_PCI_ALLOC(&bp->context[i].cxt_mapping,
+                                                     bp->context[i].size);
+               if (!bp->context[i].vcxt)
+                       goto alloc_mem_err;
                allocated += bp->context[i].size;
        }
-       BNX2X_ALLOC(bp->ilt->lines, sizeof(struct ilt_line) * ILT_MAX_LINES);
+       bp->ilt->lines = kcalloc(ILT_MAX_LINES, sizeof(struct ilt_line),
+                                GFP_KERNEL);
+       if (!bp->ilt->lines)
+               goto alloc_mem_err;
 
        if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC))
                goto alloc_mem_err;
@@ -8064,11 +8194,15 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
                goto alloc_mem_err;
 
        /* Slow path ring */
-       BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE);
+       bp->spq = BNX2X_PCI_ALLOC(&bp->spq_mapping, BCM_PAGE_SIZE);
+       if (!bp->spq)
+               goto alloc_mem_err;
 
        /* EQ */
-       BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping,
-                       BCM_PAGE_SIZE * NUM_EQ_PAGES);
+       bp->eq_ring = BNX2X_PCI_ALLOC(&bp->eq_mapping,
+                                     BCM_PAGE_SIZE * NUM_EQ_PAGES);
+       if (!bp->eq_ring)
+               goto alloc_mem_err;
 
        return 0;
 
@@ -8849,6 +8983,7 @@ static int bnx2x_func_wait_started(struct bnx2x *bp)
                synchronize_irq(bp->pdev->irq);
 
        flush_workqueue(bnx2x_wq);
+       flush_workqueue(bnx2x_iov_wq);
 
        while (bnx2x_func_get_state(bp, &bp->func_obj) !=
                                BNX2X_F_STATE_STARTED && tout--)
@@ -9774,6 +9909,10 @@ sp_rtnl_not_reset:
                bnx2x_dcbx_resume_hw_tx(bp);
        }
 
+       if (test_and_clear_bit(BNX2X_SP_RTNL_GET_DRV_VERSION,
+                              &bp->sp_rtnl_state))
+               bnx2x_update_mng_version(bp);
+
        /* work which needs rtnl lock not-taken (as it takes the lock itself and
         * can be called from other contexts as well)
         */
@@ -11724,12 +11863,15 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
+       mutex_init(&bp->drv_info_mutex);
+       bp->drv_info_mng_owner = false;
        spin_lock_init(&bp->stats_lock);
        sema_init(&bp->stats_sema, 1);
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
        INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
+       INIT_DELAYED_WORK(&bp->iov_task, bnx2x_iov_task);
        if (IS_PF(bp)) {
                rc = bnx2x_get_hwinfo(bp);
                if (rc)
@@ -11771,6 +11913,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
 
        bp->disable_tpa = disable_tpa;
        bp->disable_tpa |= IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp);
+       /* Reduce memory usage in kdump environment by disabling TPA */
+       bp->disable_tpa |= reset_devices;
 
        /* Set TPA flags */
        if (bp->disable_tpa) {
@@ -11942,7 +12086,7 @@ static int bnx2x_init_mcast_macs_list(struct bnx2x *bp,
 {
        int mc_count = netdev_mc_count(bp->dev);
        struct bnx2x_mcast_list_elem *mc_mac =
-               kzalloc(sizeof(*mc_mac) * mc_count, GFP_ATOMIC);
+               kcalloc(mc_count, sizeof(*mc_mac), GFP_ATOMIC);
        struct netdev_hw_addr *ha;
 
        if (!mc_mac)
@@ -12064,11 +12208,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
                return;
        } else {
                /* Schedule an SP task to handle rest of change */
-               DP(NETIF_MSG_IFUP, "Scheduling an Rx mode change\n");
-               smp_mb__before_clear_bit();
-               set_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state);
-               smp_mb__after_clear_bit();
-               schedule_delayed_work(&bp->sp_rtnl_task, 0);
+               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_RX_MODE,
+                                      NETIF_MSG_IFUP);
        }
 }
 
@@ -12101,11 +12242,8 @@ void bnx2x_set_rx_mode_inner(struct bnx2x *bp)
                        /* configuring mcast to a vf involves sleeping (when we
                         * wait for the pf's response).
                         */
-                       smp_mb__before_clear_bit();
-                       set_bit(BNX2X_SP_RTNL_VFPF_MCAST,
-                               &bp->sp_rtnl_state);
-                       smp_mb__after_clear_bit();
-                       schedule_delayed_work(&bp->sp_rtnl_task, 0);
+                       bnx2x_schedule_sp_rtnl(bp,
+                                              BNX2X_SP_RTNL_VFPF_MCAST, 0);
                }
        }
 
@@ -13356,11 +13494,18 @@ static int __init bnx2x_init(void)
                pr_err("Cannot create workqueue\n");
                return -ENOMEM;
        }
+       bnx2x_iov_wq = create_singlethread_workqueue("bnx2x_iov");
+       if (!bnx2x_iov_wq) {
+               pr_err("Cannot create iov workqueue\n");
+               destroy_workqueue(bnx2x_wq);
+               return -ENOMEM;
+       }
 
        ret = pci_register_driver(&bnx2x_pci_driver);
        if (ret) {
                pr_err("Cannot register driver\n");
                destroy_workqueue(bnx2x_wq);
+               destroy_workqueue(bnx2x_iov_wq);
        }
        return ret;
 }
@@ -13372,6 +13517,7 @@ static void __exit bnx2x_cleanup(void)
        pci_unregister_driver(&bnx2x_pci_driver);
 
        destroy_workqueue(bnx2x_wq);
+       destroy_workqueue(bnx2x_iov_wq);
 
        /* Free globally allocated resources */
        list_for_each_safe(pos, q, &bnx2x_prev_list) {
@@ -13765,6 +13911,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
                                REG_WR(bp, scratch_offset + i,
                                       *(host_addr + i/4));
                }
+               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
                break;
        }
 
@@ -13782,6 +13929,7 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
                                cap &= ~DRV_FLAGS_CAPABILITIES_LOADED_FCOE;
                        SHMEM2_WR(bp, drv_capabilities_flag[idx], cap);
                }
+               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
                break;
        }
 
@@ -13887,6 +14035,9 @@ static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
 
        rcu_assign_pointer(bp->cnic_ops, ops);
 
+       /* Schedule driver to read CNIC driver versions */
+       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0);
+
        return 0;
 }
 
index 0fb6ff2ac8e3738372bcb95f4278ef600c2bd76b..31297266b743e27fa527da4636bc893b1c64cc56 100644 (file)
@@ -2277,11 +2277,11 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp,
                         data->header.rule_cnt, p->rx_accept_flags,
                         p->tx_accept_flags);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
 
        /* Send a ramrod */
@@ -2982,11 +2982,11 @@ static int bnx2x_mcast_setup_e2(struct bnx2x *bp,
                raw->clear_pending(raw);
                return 0;
        } else {
-               /* No need for an explicit memory barrier here as long we would
-                * need to ensure the ordering of writing to the SPQ element
+               /* No need for an explicit memory barrier here as long as we
+                * ensure the ordering of writing to the SPQ element
                 * and updating of the SPQ producer which involves a memory
-                * read and we will have to put a full memory barrier there
-                * (inside bnx2x_sp_post()).
+                * read. If the memory read is removed we will have to put a
+                * full memory barrier there (inside bnx2x_sp_post()).
                 */
 
                /* Send a ramrod */
@@ -3466,11 +3466,11 @@ static int bnx2x_mcast_setup_e1(struct bnx2x *bp,
                raw->clear_pending(raw);
                return 0;
        } else {
-               /* No need for an explicit memory barrier here as long we would
-                * need to ensure the ordering of writing to the SPQ element
+               /* No need for an explicit memory barrier here as long as we
+                * ensure the ordering of writing to the SPQ element
                 * and updating of the SPQ producer which involves a memory
-                * read and we will have to put a full memory barrier there
-                * (inside bnx2x_sp_post()).
+                * read. If the memory read is removed we will have to put a
+                * full memory barrier there (inside bnx2x_sp_post()).
                 */
 
                /* Send a ramrod */
@@ -4091,11 +4091,11 @@ static int bnx2x_setup_rss(struct bnx2x *bp,
                data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY;
        }
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
 
        /* Send a ramrod */
@@ -4158,16 +4158,6 @@ void bnx2x_init_rss_config_obj(struct bnx2x *bp,
        rss_obj->config_rss = bnx2x_setup_rss;
 }
 
-int validate_vlan_mac(struct bnx2x *bp,
-                     struct bnx2x_vlan_mac_obj *vlan_mac)
-{
-       if (!vlan_mac->get_n_elements) {
-               BNX2X_ERR("vlan mac object was not intialized\n");
-               return -EINVAL;
-       }
-       return 0;
-}
-
 /********************** Queue state object ***********************************/
 
 /**
@@ -4587,13 +4577,12 @@ static inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp,
        /* Fill the ramrod data */
        bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4615,13 +4604,12 @@ static inline int bnx2x_q_send_setup_e2(struct bnx2x *bp,
        bnx2x_q_fill_setup_data_cmn(bp, params, rdata);
        bnx2x_q_fill_setup_data_e2(bp, params, rdata);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX],
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4659,13 +4647,12 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp,
                         o->cids[cid_index], rdata->general.client_id,
                         rdata->general.sp_client_id, rdata->general.cos);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, ramrod, o->cids[cid_index],
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4760,13 +4747,12 @@ static inline int bnx2x_q_send_update(struct bnx2x *bp,
        /* Fill the ramrod data */
        bnx2x_q_fill_update_data(bp, o, update_params, rdata);
 
-       /* No need for an explicit memory barrier here as long we would
-        * need to ensure the ordering of writing to the SPQ element
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
         * and updating of the SPQ producer which involves a memory
-        * read and we will have to put a full memory barrier there
-        * (inside bnx2x_sp_post()).
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
-
        return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE,
                             o->cids[cid_index], U64_HI(data_mapping),
                             U64_LO(data_mapping), ETH_CONNECTION_TYPE);
@@ -4813,11 +4799,62 @@ static inline int bnx2x_q_send_activate(struct bnx2x *bp,
        return bnx2x_q_send_update(bp, params);
 }
 
+static void bnx2x_q_fill_update_tpa_data(struct bnx2x *bp,
+                               struct bnx2x_queue_sp_obj *obj,
+                               struct bnx2x_queue_update_tpa_params *params,
+                               struct tpa_update_ramrod_data *data)
+{
+       data->client_id = obj->cl_id;
+       data->complete_on_both_clients = params->complete_on_both_clients;
+       data->dont_verify_rings_pause_thr_flg =
+               params->dont_verify_thr;
+       data->max_agg_size = cpu_to_le16(params->max_agg_sz);
+       data->max_sges_for_packet = params->max_sges_pkt;
+       data->max_tpa_queues = params->max_tpa_queues;
+       data->sge_buff_size = cpu_to_le16(params->sge_buff_sz);
+       data->sge_page_base_hi = cpu_to_le32(U64_HI(params->sge_map));
+       data->sge_page_base_lo = cpu_to_le32(U64_LO(params->sge_map));
+       data->sge_pause_thr_high = cpu_to_le16(params->sge_pause_thr_high);
+       data->sge_pause_thr_low = cpu_to_le16(params->sge_pause_thr_low);
+       data->tpa_mode = params->tpa_mode;
+       data->update_ipv4 = params->update_ipv4;
+       data->update_ipv6 = params->update_ipv6;
+}
+
 static inline int bnx2x_q_send_update_tpa(struct bnx2x *bp,
                                        struct bnx2x_queue_state_params *params)
 {
-       /* TODO: Not implemented yet. */
-       return -1;
+       struct bnx2x_queue_sp_obj *o = params->q_obj;
+       struct tpa_update_ramrod_data *rdata =
+               (struct tpa_update_ramrod_data *)o->rdata;
+       dma_addr_t data_mapping = o->rdata_mapping;
+       struct bnx2x_queue_update_tpa_params *update_tpa_params =
+               &params->params.update_tpa;
+       u16 type;
+
+       /* Clear the ramrod data */
+       memset(rdata, 0, sizeof(*rdata));
+
+       /* Fill the ramrod data */
+       bnx2x_q_fill_update_tpa_data(bp, o, update_tpa_params, rdata);
+
+       /* Add the function id inside the type, so that sp post function
+        * doesn't automatically add the PF func-id, this is required
+        * for operations done by PFs on behalf of their VFs
+        */
+       type = ETH_CONNECTION_TYPE |
+               ((o->func_id) << SPE_HDR_FUNCTION_ID_SHIFT);
+
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
+        */
+       return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TPA_UPDATE,
+                            o->cids[BNX2X_PRIMARY_CID_INDEX],
+                            U64_HI(data_mapping),
+                            U64_LO(data_mapping), type);
 }
 
 static inline int bnx2x_q_send_halt(struct bnx2x *bp,
@@ -5647,6 +5684,12 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp,
        rdata->tx_switch_suspend = switch_update_params->suspend;
        rdata->echo = SWITCH_UPDATE;
 
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
+        */
        return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0,
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), NONE_CONNECTION_TYPE);
@@ -5674,11 +5717,11 @@ static inline int bnx2x_func_send_afex_update(struct bnx2x *bp,
        rdata->allowed_priorities = afex_update_params->allowed_priorities;
        rdata->echo = AFEX_UPDATE;
 
-       /*  No need for an explicit memory barrier here as long we would
-        *  need to ensure the ordering of writing to the SPQ element
-        *  and updating of the SPQ producer which involves a memory
-        *  read and we will have to put a full memory barrier there
-        *  (inside bnx2x_sp_post()).
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
         */
        DP(BNX2X_MSG_SP,
           "afex: sending func_update vif_id 0x%x dvlan 0x%x prio 0x%x\n",
@@ -5763,6 +5806,12 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp,
                rdata->traffic_type_to_priority_cos[i] =
                        tx_start_params->traffic_type_to_priority_cos[i];
 
+       /* No need for an explicit memory barrier here as long as we
+        * ensure the ordering of writing to the SPQ element
+        * and updating of the SPQ producer which involves a memory
+        * read. If the memory read is removed we will have to put a
+        * full memory barrier there (inside bnx2x_sp_post()).
+        */
        return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0,
                             U64_HI(data_mapping),
                             U64_LO(data_mapping), NONE_CONNECTION_TYPE);
index 00d7f214a40a2caf2619fac0343ad3798b4bdaed..80f6c790ed88097ed17b3c3f259179e86451eff2 100644 (file)
@@ -893,6 +893,24 @@ struct bnx2x_queue_update_params {
        u8              cid_index;
 };
 
+struct bnx2x_queue_update_tpa_params {
+       dma_addr_t sge_map;
+       u8 update_ipv4;
+       u8 update_ipv6;
+       u8 max_tpa_queues;
+       u8 max_sges_pkt;
+       u8 complete_on_both_clients;
+       u8 dont_verify_thr;
+       u8 tpa_mode;
+       u8 _pad;
+
+       u16 sge_buff_sz;
+       u16 max_agg_sz;
+
+       u16 sge_pause_thr_low;
+       u16 sge_pause_thr_high;
+};
+
 struct rxq_pause_params {
        u16             bd_th_lo;
        u16             bd_th_hi;
@@ -987,6 +1005,7 @@ struct bnx2x_queue_state_params {
        /* Params according to the current command */
        union {
                struct bnx2x_queue_update_params        update;
+               struct bnx2x_queue_update_tpa_params    update_tpa;
                struct bnx2x_queue_setup_params         setup;
                struct bnx2x_queue_init_params          init;
                struct bnx2x_queue_setup_tx_only_params tx_only;
@@ -1403,6 +1422,4 @@ int bnx2x_config_rss(struct bnx2x *bp,
 void bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj,
                             u8 *ind_table);
 
-int validate_vlan_mac(struct bnx2x *bp,
-                     struct bnx2x_vlan_mac_obj *vlan_mac);
 #endif /* BNX2X_SP_VERBS */
index aec5ef2ed7ce26329ff2638b48bda29979c360ee..5c523b32db70126720dbf0b2914dcbb1a3391a2b 100644 (file)
@@ -102,82 +102,22 @@ static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf,
        mmiowb();
        barrier();
 }
-/* VFOP - VF slow-path operation support */
 
-#define BNX2X_VFOP_FILTER_ADD_CNT_MAX          0x10000
+static bool bnx2x_validate_vf_sp_objs(struct bnx2x *bp,
+                                      struct bnx2x_virtf *vf,
+                                      bool print_err)
+{
+       if (!bnx2x_leading_vfq(vf, sp_initialized)) {
+               if (print_err)
+                       BNX2X_ERR("Slowpath objects not yet initialized!\n");
+               else
+                       DP(BNX2X_MSG_IOV, "Slowpath objects not yet initialized!\n");
+               return false;
+       }
+       return true;
+}
 
 /* VFOP operations states */
-enum bnx2x_vfop_qctor_state {
-          BNX2X_VFOP_QCTOR_INIT,
-          BNX2X_VFOP_QCTOR_SETUP,
-          BNX2X_VFOP_QCTOR_INT_EN
-};
-
-enum bnx2x_vfop_qdtor_state {
-          BNX2X_VFOP_QDTOR_HALT,
-          BNX2X_VFOP_QDTOR_TERMINATE,
-          BNX2X_VFOP_QDTOR_CFCDEL,
-          BNX2X_VFOP_QDTOR_DONE
-};
-
-enum bnx2x_vfop_vlan_mac_state {
-          BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
-          BNX2X_VFOP_VLAN_MAC_CLEAR,
-          BNX2X_VFOP_VLAN_MAC_CHK_DONE,
-          BNX2X_VFOP_MAC_CONFIG_LIST,
-          BNX2X_VFOP_VLAN_CONFIG_LIST,
-          BNX2X_VFOP_VLAN_CONFIG_LIST_0
-};
-
-enum bnx2x_vfop_qsetup_state {
-          BNX2X_VFOP_QSETUP_CTOR,
-          BNX2X_VFOP_QSETUP_VLAN0,
-          BNX2X_VFOP_QSETUP_DONE
-};
-
-enum bnx2x_vfop_mcast_state {
-          BNX2X_VFOP_MCAST_DEL,
-          BNX2X_VFOP_MCAST_ADD,
-          BNX2X_VFOP_MCAST_CHK_DONE
-};
-enum bnx2x_vfop_qflr_state {
-          BNX2X_VFOP_QFLR_CLR_VLAN,
-          BNX2X_VFOP_QFLR_CLR_MAC,
-          BNX2X_VFOP_QFLR_TERMINATE,
-          BNX2X_VFOP_QFLR_DONE
-};
-
-enum bnx2x_vfop_flr_state {
-          BNX2X_VFOP_FLR_QUEUES,
-          BNX2X_VFOP_FLR_HW
-};
-
-enum bnx2x_vfop_close_state {
-          BNX2X_VFOP_CLOSE_QUEUES,
-          BNX2X_VFOP_CLOSE_HW
-};
-
-enum bnx2x_vfop_rxmode_state {
-          BNX2X_VFOP_RXMODE_CONFIG,
-          BNX2X_VFOP_RXMODE_DONE
-};
-
-enum bnx2x_vfop_qteardown_state {
-          BNX2X_VFOP_QTEARDOWN_RXMODE,
-          BNX2X_VFOP_QTEARDOWN_CLR_VLAN,
-          BNX2X_VFOP_QTEARDOWN_CLR_MAC,
-          BNX2X_VFOP_QTEARDOWN_CLR_MCAST,
-          BNX2X_VFOP_QTEARDOWN_QDTOR,
-          BNX2X_VFOP_QTEARDOWN_DONE
-};
-
-enum bnx2x_vfop_rss_state {
-          BNX2X_VFOP_RSS_CONFIG,
-          BNX2X_VFOP_RSS_DONE
-};
-
-#define bnx2x_vfop_reset_wq(vf)        atomic_set(&vf->op_in_progress, 0)
-
 void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
                              struct bnx2x_queue_init_params *init_params,
                              struct bnx2x_queue_setup_params *setup_params,
@@ -221,7 +161,7 @@ void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
 void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
                           struct bnx2x_virtf *vf,
                           struct bnx2x_vf_queue *q,
-                          struct bnx2x_vfop_qctor_params *p,
+                          struct bnx2x_vf_queue_construct_params *p,
                           unsigned long q_type)
 {
        struct bnx2x_queue_init_params *init_p = &p->qstate.params.init;
@@ -290,191 +230,85 @@ void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
        }
 }
 
-/* VFOP queue construction */
-static void bnx2x_vfop_qctor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static int bnx2x_vf_queue_create(struct bnx2x *bp,
+                                struct bnx2x_virtf *vf, int qid,
+                                struct bnx2x_vf_queue_construct_params *qctor)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_vfop_args_qctor *args = &vfop->args.qctor;
-       struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
-       enum bnx2x_vfop_qctor_state state = vfop->state;
-
-       bnx2x_vfop_reset_wq(vf);
-
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       switch (state) {
-       case BNX2X_VFOP_QCTOR_INIT:
-
-               /* has this queue already been opened? */
-               if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
-                   BNX2X_Q_LOGICAL_STATE_ACTIVE) {
-                       DP(BNX2X_MSG_IOV,
-                          "Entered qctor but queue was already up. Aborting gracefully\n");
-                       goto op_done;
-               }
-
-               /* next state */
-               vfop->state = BNX2X_VFOP_QCTOR_SETUP;
-
-               q_params->cmd = BNX2X_Q_CMD_INIT;
-               vfop->rc = bnx2x_queue_state_change(bp, q_params);
-
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
-       case BNX2X_VFOP_QCTOR_SETUP:
-               /* next state */
-               vfop->state = BNX2X_VFOP_QCTOR_INT_EN;
-
-               /* copy pre-prepared setup params to the queue-state params */
-               vfop->op_p->qctor.qstate.params.setup =
-                       vfop->op_p->qctor.prep_qsetup;
-
-               q_params->cmd = BNX2X_Q_CMD_SETUP;
-               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+       struct bnx2x_queue_state_params *q_params;
+       int rc = 0;
 
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+       DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
 
-       case BNX2X_VFOP_QCTOR_INT_EN:
+       /* Prepare ramrod information */
+       q_params = &qctor->qstate;
+       q_params->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+       set_bit(RAMROD_COMP_WAIT, &q_params->ramrod_flags);
 
-               /* enable interrupts */
-               bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, args->sb_idx),
-                                   USTORM_ID, 0, IGU_INT_ENABLE, 0);
-               goto op_done;
-       default:
-               bnx2x_vfop_default(state);
+       if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
+           BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+               DP(BNX2X_MSG_IOV, "queue was already up. Aborting gracefully\n");
+               goto out;
        }
-op_err:
-       BNX2X_ERR("QCTOR[%d:%d] error: cmd %d, rc %d\n",
-                 vf->abs_vfid, args->qid, q_params->cmd, vfop->rc);
-op_done:
-       bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
-       return;
-}
 
-static int bnx2x_vfop_qctor_cmd(struct bnx2x *bp,
-                               struct bnx2x_virtf *vf,
-                               struct bnx2x_vfop_cmd *cmd,
-                               int qid)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
-       if (vfop) {
-               vf->op_params.qctor.qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+       /* Run Queue 'construction' ramrods */
+       q_params->cmd = BNX2X_Q_CMD_INIT;
+       rc = bnx2x_queue_state_change(bp, q_params);
+       if (rc)
+               goto out;
 
-               vfop->args.qctor.qid = qid;
-               vfop->args.qctor.sb_idx = bnx2x_vfq(vf, qid, sb_idx);
+       memcpy(&q_params->params.setup, &qctor->prep_qsetup,
+              sizeof(struct bnx2x_queue_setup_params));
+       q_params->cmd = BNX2X_Q_CMD_SETUP;
+       rc = bnx2x_queue_state_change(bp, q_params);
+       if (rc)
+               goto out;
 
-               bnx2x_vfop_opset(BNX2X_VFOP_QCTOR_INIT,
-                                bnx2x_vfop_qctor, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qctor,
-                                            cmd->block);
-       }
-       return -ENOMEM;
+       /* enable interrupts */
+       bnx2x_vf_igu_ack_sb(bp, vf, vf_igu_sb(vf, bnx2x_vfq(vf, qid, sb_idx)),
+                           USTORM_ID, 0, IGU_INT_ENABLE, 0);
+out:
+       return rc;
 }
 
-/* VFOP queue destruction */
-static void bnx2x_vfop_qdtor(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static int bnx2x_vf_queue_destroy(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                 int qid)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_vfop_args_qdtor *qdtor = &vfop->args.qdtor;
-       struct bnx2x_queue_state_params *q_params = &vfop->op_p->qctor.qstate;
-       enum bnx2x_vfop_qdtor_state state = vfop->state;
-
-       bnx2x_vfop_reset_wq(vf);
-
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       switch (state) {
-       case BNX2X_VFOP_QDTOR_HALT:
-
-               /* has this queue already been stopped? */
-               if (bnx2x_get_q_logical_state(bp, q_params->q_obj) ==
-                   BNX2X_Q_LOGICAL_STATE_STOPPED) {
-                       DP(BNX2X_MSG_IOV,
-                          "Entered qdtor but queue was already stopped. Aborting gracefully\n");
-
-                       /* next state */
-                       vfop->state = BNX2X_VFOP_QDTOR_DONE;
-
-                       bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-               }
-
-               /* next state */
-               vfop->state = BNX2X_VFOP_QDTOR_TERMINATE;
-
-               q_params->cmd = BNX2X_Q_CMD_HALT;
-               vfop->rc = bnx2x_queue_state_change(bp, q_params);
-
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
-       case BNX2X_VFOP_QDTOR_TERMINATE:
-               /* next state */
-               vfop->state = BNX2X_VFOP_QDTOR_CFCDEL;
-
-               q_params->cmd = BNX2X_Q_CMD_TERMINATE;
-               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+       enum bnx2x_queue_cmd cmds[] = {BNX2X_Q_CMD_HALT,
+                                      BNX2X_Q_CMD_TERMINATE,
+                                      BNX2X_Q_CMD_CFC_DEL};
+       struct bnx2x_queue_state_params q_params;
+       int rc, i;
 
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
 
-       case BNX2X_VFOP_QDTOR_CFCDEL:
-               /* next state */
-               vfop->state = BNX2X_VFOP_QDTOR_DONE;
+       /* Prepare ramrod information */
+       memset(&q_params, 0, sizeof(struct bnx2x_queue_state_params));
+       q_params.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+       set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags);
 
-               q_params->cmd = BNX2X_Q_CMD_CFC_DEL;
-               vfop->rc = bnx2x_queue_state_change(bp, q_params);
+       if (bnx2x_get_q_logical_state(bp, q_params.q_obj) ==
+           BNX2X_Q_LOGICAL_STATE_STOPPED) {
+               DP(BNX2X_MSG_IOV, "queue was already stopped. Aborting gracefully\n");
+               goto out;
+       }
 
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-op_err:
-       BNX2X_ERR("QDTOR[%d:%d] error: cmd %d, rc %d\n",
-                 vf->abs_vfid, qdtor->qid, q_params->cmd, vfop->rc);
-op_done:
-       case BNX2X_VFOP_QDTOR_DONE:
-               /* invalidate the context */
-               if (qdtor->cxt) {
-                       qdtor->cxt->ustorm_ag_context.cdu_usage = 0;
-                       qdtor->cxt->xstorm_ag_context.cdu_reserved = 0;
+       /* Run Queue 'destruction' ramrods */
+       for (i = 0; i < ARRAY_SIZE(cmds); i++) {
+               q_params.cmd = cmds[i];
+               rc = bnx2x_queue_state_change(bp, &q_params);
+               if (rc) {
+                       BNX2X_ERR("Failed to run Queue command %d\n", cmds[i]);
+                       return rc;
                }
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-       default:
-               bnx2x_vfop_default(state);
        }
-op_pending:
-       return;
-}
-
-static int bnx2x_vfop_qdtor_cmd(struct bnx2x *bp,
-                               struct bnx2x_virtf *vf,
-                               struct bnx2x_vfop_cmd *cmd,
-                               int qid)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
-       if (vfop) {
-               struct bnx2x_queue_state_params *qstate =
-                       &vf->op_params.qctor.qstate;
-
-               memset(qstate, 0, sizeof(*qstate));
-               qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
-
-               vfop->args.qdtor.qid = qid;
-               vfop->args.qdtor.cxt = bnx2x_vfq(vf, qid, cxt);
-
-               bnx2x_vfop_opset(BNX2X_VFOP_QDTOR_HALT,
-                                bnx2x_vfop_qdtor, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdtor,
-                                            cmd->block);
-       } else {
-               BNX2X_ERR("VF[%d] failed to add a vfop\n", vf->abs_vfid);
-               return -ENOMEM;
+out:
+       /* Clean Context */
+       if (bnx2x_vfq(vf, qid, cxt)) {
+               bnx2x_vfq(vf, qid, cxt)->ustorm_ag_context.cdu_usage = 0;
+               bnx2x_vfq(vf, qid, cxt)->xstorm_ag_context.cdu_reserved = 0;
        }
+
+       return 0;
 }
 
 static void
@@ -496,751 +330,293 @@ bnx2x_vf_set_igu_info(struct bnx2x *bp, u8 igu_sb_id, u8 abs_vfid)
        BP_VFDB(bp)->vf_sbs_pool++;
 }
 
-/* VFOP MAC/VLAN helpers */
-static inline void bnx2x_vfop_credit(struct bnx2x *bp,
-                                    struct bnx2x_vfop *vfop,
-                                    struct bnx2x_vlan_mac_obj *obj)
+static inline void bnx2x_vf_vlan_credit(struct bnx2x *bp,
+                                       struct bnx2x_vlan_mac_obj *obj,
+                                       atomic_t *counter)
 {
-       struct bnx2x_vfop_args_filters *args = &vfop->args.filters;
-
-       /* update credit only if there is no error
-        * and a valid credit counter
-        */
-       if (!vfop->rc && args->credit) {
-               struct list_head *pos;
-               int read_lock;
-               int cnt = 0;
-
-               read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj);
-               if (read_lock)
-                       DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n");
+       struct list_head *pos;
+       int read_lock;
+       int cnt = 0;
 
-               list_for_each(pos, &obj->head)
-                       cnt++;
+       read_lock = bnx2x_vlan_mac_h_read_lock(bp, obj);
+       if (read_lock)
+               DP(BNX2X_MSG_SP, "Failed to take vlan mac read head; continuing anyway\n");
 
-               if (!read_lock)
-                       bnx2x_vlan_mac_h_read_unlock(bp, obj);
+       list_for_each(pos, &obj->head)
+               cnt++;
 
-               atomic_set(args->credit, cnt);
-       }
-}
-
-static int bnx2x_vfop_set_user_req(struct bnx2x *bp,
-                                   struct bnx2x_vfop_filter *pos,
-                                   struct bnx2x_vlan_mac_data *user_req)
-{
-       user_req->cmd = pos->add ? BNX2X_VLAN_MAC_ADD :
-               BNX2X_VLAN_MAC_DEL;
+       if (!read_lock)
+               bnx2x_vlan_mac_h_read_unlock(bp, obj);
 
-       switch (pos->type) {
-       case BNX2X_VFOP_FILTER_MAC:
-               memcpy(user_req->u.mac.mac, pos->mac, ETH_ALEN);
-               break;
-       case BNX2X_VFOP_FILTER_VLAN:
-               user_req->u.vlan.vlan = pos->vid;
-               break;
-       default:
-               BNX2X_ERR("Invalid filter type, skipping\n");
-               return 1;
-       }
-       return 0;
+       atomic_set(counter, cnt);
 }
 
-static int bnx2x_vfop_config_list(struct bnx2x *bp,
-                                 struct bnx2x_vfop_filters *filters,
-                                 struct bnx2x_vlan_mac_ramrod_params *vlan_mac)
+static int bnx2x_vf_vlan_mac_clear(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                  int qid, bool drv_only, bool mac)
 {
-       struct bnx2x_vfop_filter *pos, *tmp;
-       struct list_head rollback_list, *filters_list = &filters->head;
-       struct bnx2x_vlan_mac_data *user_req = &vlan_mac->user_req;
-       int rc = 0, cnt = 0;
-
-       INIT_LIST_HEAD(&rollback_list);
-
-       list_for_each_entry_safe(pos, tmp, filters_list, link) {
-               if (bnx2x_vfop_set_user_req(bp, pos, user_req))
-                       continue;
+       struct bnx2x_vlan_mac_ramrod_params ramrod;
+       int rc;
 
-               rc = bnx2x_config_vlan_mac(bp, vlan_mac);
-               if (rc >= 0) {
-                       cnt += pos->add ? 1 : -1;
-                       list_move(&pos->link, &rollback_list);
-                       rc = 0;
-               } else if (rc == -EEXIST) {
-                       rc = 0;
-               } else {
-                       BNX2X_ERR("Failed to add a new vlan_mac command\n");
-                       break;
-               }
-       }
+       DP(BNX2X_MSG_IOV, "vf[%d] - deleting all %s\n", vf->abs_vfid,
+          mac ? "MACs" : "VLANs");
 
-       /* rollback if error or too many rules added */
-       if (rc || cnt > filters->add_cnt) {
-               BNX2X_ERR("error or too many rules added. Performing rollback\n");
-               list_for_each_entry_safe(pos, tmp, &rollback_list, link) {
-                       pos->add = !pos->add;   /* reverse op */
-                       bnx2x_vfop_set_user_req(bp, pos, user_req);
-                       bnx2x_config_vlan_mac(bp, vlan_mac);
-                       list_del(&pos->link);
-               }
-               cnt = 0;
-               if (!rc)
-                       rc = -EINVAL;
+       /* Prepare ramrod params */
+       memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params));
+       if (mac) {
+               set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
+               ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+       } else {
+               set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
+                       &ramrod.user_req.vlan_mac_flags);
+               ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
        }
-       filters->add_cnt = cnt;
-       return rc;
-}
-
-/* VFOP set VLAN/MAC */
-static void bnx2x_vfop_vlan_mac(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_vlan_mac_ramrod_params *vlan_mac = &vfop->op_p->vlan_mac;
-       struct bnx2x_vlan_mac_obj *obj = vlan_mac->vlan_mac_obj;
-       struct bnx2x_vfop_filters *filters = vfop->args.filters.multi_filter;
-
-       enum bnx2x_vfop_vlan_mac_state state = vfop->state;
-
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       bnx2x_vfop_reset_wq(vf);
-
-       switch (state) {
-       case BNX2X_VFOP_VLAN_MAC_CLEAR:
-               /* next state */
-               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
-               /* do delete */
-               vfop->rc = obj->delete_all(bp, obj,
-                                          &vlan_mac->user_req.vlan_mac_flags,
-                                          &vlan_mac->ramrod_flags);
-
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
-       case BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE:
-               /* next state */
-               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
-               /* do config */
-               vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
-               if (vfop->rc == -EEXIST)
-                       vfop->rc = 0;
+       ramrod.user_req.cmd = BNX2X_VLAN_MAC_DEL;
 
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
-       case BNX2X_VFOP_VLAN_MAC_CHK_DONE:
-               vfop->rc = !!obj->raw.check_pending(&obj->raw);
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-
-       case BNX2X_VFOP_MAC_CONFIG_LIST:
-               /* next state */
-               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
-               /* do list config */
-               vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
-               if (vfop->rc)
-                       goto op_err;
-
-               set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
-               vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
-       case BNX2X_VFOP_VLAN_CONFIG_LIST:
-               /* next state */
-               vfop->state = BNX2X_VFOP_VLAN_MAC_CHK_DONE;
-
-               /* do list config */
-               vfop->rc = bnx2x_vfop_config_list(bp, filters, vlan_mac);
-               if (!vfop->rc) {
-                       set_bit(RAMROD_CONT, &vlan_mac->ramrod_flags);
-                       vfop->rc = bnx2x_config_vlan_mac(bp, vlan_mac);
-               }
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+       set_bit(RAMROD_EXEC, &ramrod.ramrod_flags);
+       if (drv_only)
+               set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags);
+       else
+               set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
 
-       default:
-               bnx2x_vfop_default(state);
+       /* Start deleting */
+       rc = ramrod.vlan_mac_obj->delete_all(bp,
+                                            ramrod.vlan_mac_obj,
+                                            &ramrod.user_req.vlan_mac_flags,
+                                            &ramrod.ramrod_flags);
+       if (rc) {
+               BNX2X_ERR("Failed to delete all %s\n",
+                         mac ? "MACs" : "VLANs");
+               return rc;
        }
-op_err:
-       BNX2X_ERR("VLAN-MAC error: rc %d\n", vfop->rc);
-op_done:
-       kfree(filters);
-       bnx2x_vfop_credit(bp, vfop, obj);
-       bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
-       return;
-}
-
-struct bnx2x_vfop_vlan_mac_flags {
-       bool drv_only;
-       bool dont_consume;
-       bool single_cmd;
-       bool add;
-};
-
-static void
-bnx2x_vfop_vlan_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
-                               struct bnx2x_vfop_vlan_mac_flags *flags)
-{
-       struct bnx2x_vlan_mac_data *ureq = &ramrod->user_req;
-
-       memset(ramrod, 0, sizeof(*ramrod));
 
-       /* ramrod flags */
-       if (flags->drv_only)
-               set_bit(RAMROD_DRV_CLR_ONLY, &ramrod->ramrod_flags);
-       if (flags->single_cmd)
-               set_bit(RAMROD_EXEC, &ramrod->ramrod_flags);
+       /* Clear the vlan counters */
+       if (!mac)
+               atomic_set(&bnx2x_vfq(vf, qid, vlan_count), 0);
 
-       /* mac_vlan flags */
-       if (flags->dont_consume)
-               set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, &ureq->vlan_mac_flags);
-
-       /* cmd */
-       ureq->cmd = flags->add ? BNX2X_VLAN_MAC_ADD : BNX2X_VLAN_MAC_DEL;
-}
-
-static inline void
-bnx2x_vfop_mac_prep_ramrod(struct bnx2x_vlan_mac_ramrod_params *ramrod,
-                          struct bnx2x_vfop_vlan_mac_flags *flags)
-{
-       bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, flags);
-       set_bit(BNX2X_ETH_MAC, &ramrod->user_req.vlan_mac_flags);
+       return 0;
 }
 
-static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp,
-                                    struct bnx2x_virtf *vf,
-                                    struct bnx2x_vfop_cmd *cmd,
-                                    int qid, bool drv_only)
+static int bnx2x_vf_mac_vlan_config(struct bnx2x *bp,
+                                   struct bnx2x_virtf *vf, int qid,
+                                   struct bnx2x_vf_mac_vlan_filter *filter,
+                                   bool drv_only)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       struct bnx2x_vlan_mac_ramrod_params ramrod;
        int rc;
 
-       if (vfop) {
-               struct bnx2x_vfop_args_filters filters = {
-                       .multi_filter = NULL,   /* single */
-                       .credit = NULL,         /* consume credit */
-               };
-               struct bnx2x_vfop_vlan_mac_flags flags = {
-                       .drv_only = drv_only,
-                       .dont_consume = (filters.credit != NULL),
-                       .single_cmd = true,
-                       .add = false /* don't care */,
-               };
-               struct bnx2x_vlan_mac_ramrod_params *ramrod =
-                       &vf->op_params.vlan_mac;
-
-               /* set ramrod params */
-               bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
-
-               /* set object */
-               rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj));
-               if (rc)
-                       return rc;
-               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
-
-               /* set extra args */
-               vfop->args.filters = filters;
-
-               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
-                                bnx2x_vfop_vlan_mac, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
-                                            cmd->block);
+       DP(BNX2X_MSG_IOV, "vf[%d] - %s a %s filter\n",
+          vf->abs_vfid, filter->add ? "Adding" : "Deleting",
+          filter->type == BNX2X_VF_FILTER_MAC ? "MAC" : "VLAN");
+
+       /* Prepare ramrod params */
+       memset(&ramrod, 0, sizeof(struct bnx2x_vlan_mac_ramrod_params));
+       if (filter->type == BNX2X_VF_FILTER_VLAN) {
+               set_bit(BNX2X_DONT_CONSUME_CAM_CREDIT,
+                       &ramrod.user_req.vlan_mac_flags);
+               ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+               ramrod.user_req.u.vlan.vlan = filter->vid;
+       } else {
+               set_bit(BNX2X_ETH_MAC, &ramrod.user_req.vlan_mac_flags);
+               ramrod.vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+               memcpy(&ramrod.user_req.u.mac.mac, filter->mac, ETH_ALEN);
+       }
+       ramrod.user_req.cmd = filter->add ? BNX2X_VLAN_MAC_ADD :
+                                           BNX2X_VLAN_MAC_DEL;
+
+       /* Verify there are available vlan credits */
+       if (filter->add && filter->type == BNX2X_VF_FILTER_VLAN &&
+           (atomic_read(&bnx2x_vfq(vf, qid, vlan_count)) >=
+            vf_vlan_rules_cnt(vf))) {
+               BNX2X_ERR("No credits for vlan\n");
+               return -ENOMEM;
        }
-       return -ENOMEM;
-}
-
-int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
-                           struct bnx2x_virtf *vf,
-                           struct bnx2x_vfop_cmd *cmd,
-                           struct bnx2x_vfop_filters *macs,
-                           int qid, bool drv_only)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       int rc;
 
-       if (vfop) {
-               struct bnx2x_vfop_args_filters filters = {
-                       .multi_filter = macs,
-                       .credit = NULL,         /* consume credit */
-               };
-               struct bnx2x_vfop_vlan_mac_flags flags = {
-                       .drv_only = drv_only,
-                       .dont_consume = (filters.credit != NULL),
-                       .single_cmd = false,
-                       .add = false, /* don't care since only the items in the
-                                      * filters list affect the sp operation,
-                                      * not the list itself
-                                      */
-               };
-               struct bnx2x_vlan_mac_ramrod_params *ramrod =
-                       &vf->op_params.vlan_mac;
-
-               /* set ramrod params */
-               bnx2x_vfop_mac_prep_ramrod(ramrod, &flags);
-
-               /* set object */
-               rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj));
-               if (rc)
-                       return rc;
-               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj);
+       set_bit(RAMROD_EXEC, &ramrod.ramrod_flags);
+       if (drv_only)
+               set_bit(RAMROD_DRV_CLR_ONLY, &ramrod.ramrod_flags);
+       else
+               set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
+
+       /* Add/Remove the filter */
+       rc = bnx2x_config_vlan_mac(bp, &ramrod);
+       if (rc && rc != -EEXIST) {
+               BNX2X_ERR("Failed to %s %s\n",
+                         filter->add ? "add" : "delete",
+                         filter->type == BNX2X_VF_FILTER_MAC ? "MAC" :
+                                                               "VLAN");
+               return rc;
+       }
 
-               /* set extra args */
-               filters.multi_filter->add_cnt = BNX2X_VFOP_FILTER_ADD_CNT_MAX;
-               vfop->args.filters = filters;
+       /* Update the vlan counters */
+       if (filter->type == BNX2X_VF_FILTER_VLAN)
+               bnx2x_vf_vlan_credit(bp, ramrod.vlan_mac_obj,
+                                    &bnx2x_vfq(vf, qid, vlan_count));
 
-               bnx2x_vfop_opset(BNX2X_VFOP_MAC_CONFIG_LIST,
-                                bnx2x_vfop_vlan_mac, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
-                                            cmd->block);
-       }
-       return -ENOMEM;
+       return 0;
 }
 
-static int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp,
-                                  struct bnx2x_virtf *vf,
-                                  struct bnx2x_vfop_cmd *cmd,
-                                  int qid, u16 vid, bool add)
+int bnx2x_vf_mac_vlan_config_list(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                 struct bnx2x_vf_mac_vlan_filters *filters,
+                                 int qid, bool drv_only)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       int rc;
+       int rc = 0, i;
 
-       if (vfop) {
-               struct bnx2x_vfop_args_filters filters = {
-                       .multi_filter = NULL, /* single command */
-                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
-               };
-               struct bnx2x_vfop_vlan_mac_flags flags = {
-                       .drv_only = false,
-                       .dont_consume = (filters.credit != NULL),
-                       .single_cmd = true,
-                       .add = add,
-               };
-               struct bnx2x_vlan_mac_ramrod_params *ramrod =
-                       &vf->op_params.vlan_mac;
-
-               /* set ramrod params */
-               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
-               ramrod->user_req.u.vlan.vlan = vid;
-
-               /* set object */
-               rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj));
-               if (rc)
-                       return rc;
-               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
 
-               /* set extra args */
-               vfop->args.filters = filters;
+       if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+               return -EINVAL;
 
-               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CONFIG_SINGLE,
-                                bnx2x_vfop_vlan_mac, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
-                                            cmd->block);
+       /* Prepare ramrod params */
+       for (i = 0; i < filters->count; i++) {
+               rc = bnx2x_vf_mac_vlan_config(bp, vf, qid,
+                                             &filters->filters[i], drv_only);
+               if (rc)
+                       break;
        }
-       return -ENOMEM;
-}
-
-static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp,
-                              struct bnx2x_virtf *vf,
-                              struct bnx2x_vfop_cmd *cmd,
-                              int qid, bool drv_only)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       int rc;
 
-       if (vfop) {
-               struct bnx2x_vfop_args_filters filters = {
-                       .multi_filter = NULL, /* single command */
-                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
-               };
-               struct bnx2x_vfop_vlan_mac_flags flags = {
-                       .drv_only = drv_only,
-                       .dont_consume = (filters.credit != NULL),
-                       .single_cmd = true,
-                       .add = false, /* don't care */
-               };
-               struct bnx2x_vlan_mac_ramrod_params *ramrod =
-                       &vf->op_params.vlan_mac;
-
-               /* set ramrod params */
-               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
-
-               /* set object */
-               rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj));
-               if (rc)
-                       return rc;
-               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
+       /* Rollback if needed */
+       if (i != filters->count) {
+               BNX2X_ERR("Managed only %d/%d filters - rolling back\n",
+                         i, filters->count + 1);
+               while (--i >= 0) {
+                       filters->filters[i].add = !filters->filters[i].add;
+                       bnx2x_vf_mac_vlan_config(bp, vf, qid,
+                                                &filters->filters[i],
+                                                drv_only);
+               }
+       }
 
-               /* set extra args */
-               vfop->args.filters = filters;
+       /* It's our responsibility to free the filters */
+       kfree(filters);
 
-               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_MAC_CLEAR,
-                                bnx2x_vfop_vlan_mac, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
-                                            cmd->block);
-       }
-       return -ENOMEM;
+       return rc;
 }
 
-int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
-                            struct bnx2x_virtf *vf,
-                            struct bnx2x_vfop_cmd *cmd,
-                            struct bnx2x_vfop_filters *vlans,
-                            int qid, bool drv_only)
+int bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid,
+                        struct bnx2x_vf_queue_construct_params *qctor)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
        int rc;
 
-       if (vfop) {
-               struct bnx2x_vfop_args_filters filters = {
-                       .multi_filter = vlans,
-                       .credit = &bnx2x_vfq(vf, qid, vlan_count),
-               };
-               struct bnx2x_vfop_vlan_mac_flags flags = {
-                       .drv_only = drv_only,
-                       .dont_consume = (filters.credit != NULL),
-                       .single_cmd = false,
-                       .add = false, /* don't care */
-               };
-               struct bnx2x_vlan_mac_ramrod_params *ramrod =
-                       &vf->op_params.vlan_mac;
-
-               /* set ramrod params */
-               bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags);
-
-               /* set object */
-               rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj));
-               if (rc)
-                       return rc;
-               ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj);
-
-               /* set extra args */
-               filters.multi_filter->add_cnt = vf_vlan_rules_cnt(vf) -
-                       atomic_read(filters.credit);
-
-               vfop->args.filters = filters;
+       DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
 
-               bnx2x_vfop_opset(BNX2X_VFOP_VLAN_CONFIG_LIST,
-                                bnx2x_vfop_vlan_mac, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_vlan_mac,
-                                            cmd->block);
-       }
-       return -ENOMEM;
-}
-
-/* VFOP queue setup (queue constructor + set vlan 0) */
-static void bnx2x_vfop_qsetup(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       int qid = vfop->args.qctor.qid;
-       enum bnx2x_vfop_qsetup_state state = vfop->state;
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vfop_qsetup,
-               .block = false,
-       };
-
-       if (vfop->rc < 0)
+       rc = bnx2x_vf_queue_create(bp, vf, qid, qctor);
+       if (rc)
                goto op_err;
 
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+       /* Configure vlan0 for leading queue */
+       if (!qid) {
+               struct bnx2x_vf_mac_vlan_filter filter;
 
-       switch (state) {
-       case BNX2X_VFOP_QSETUP_CTOR:
-               /* init the queue ctor command */
-               vfop->state = BNX2X_VFOP_QSETUP_VLAN0;
-               vfop->rc = bnx2x_vfop_qctor_cmd(bp, vf, &cmd, qid);
-               if (vfop->rc)
+               memset(&filter, 0, sizeof(struct bnx2x_vf_mac_vlan_filter));
+               filter.type = BNX2X_VF_FILTER_VLAN;
+               filter.add = true;
+               filter.vid = 0;
+               rc = bnx2x_vf_mac_vlan_config(bp, vf, qid, &filter, false);
+               if (rc)
                        goto op_err;
-               return;
-
-       case BNX2X_VFOP_QSETUP_VLAN0:
-               /* skip if non-leading or FPGA/EMU*/
-               if (qid)
-                       goto op_done;
+       }
 
-               /* init the queue set-vlan command (for vlan 0) */
-               vfop->state = BNX2X_VFOP_QSETUP_DONE;
-               vfop->rc = bnx2x_vfop_vlan_set_cmd(bp, vf, &cmd, qid, 0, true);
-               if (vfop->rc)
-                       goto op_err;
-               return;
+       /* Schedule the configuration of any pending vlan filters */
+       vf->cfg_flags |= VF_CFG_VLAN;
+       bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_HYPERVISOR_VLAN,
+                              BNX2X_MSG_IOV);
+       return 0;
 op_err:
-       BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, vfop->rc);
-op_done:
-       case BNX2X_VFOP_QSETUP_DONE:
-               vf->cfg_flags |= VF_CFG_VLAN;
-               smp_mb__before_clear_bit();
-               set_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN,
-                       &bp->sp_rtnl_state);
-               smp_mb__after_clear_bit();
-               schedule_delayed_work(&bp->sp_rtnl_task, 0);
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-       default:
-               bnx2x_vfop_default(state);
-       }
+       BNX2X_ERR("QSETUP[%d:%d] error: rc %d\n", vf->abs_vfid, qid, rc);
+       return rc;
 }
 
-int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
-                         struct bnx2x_virtf *vf,
-                         struct bnx2x_vfop_cmd *cmd,
-                         int qid)
+static int bnx2x_vf_queue_flr(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                              int qid)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       int rc;
 
-       if (vfop) {
-               vfop->args.qctor.qid = qid;
+       DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
 
-               bnx2x_vfop_opset(BNX2X_VFOP_QSETUP_CTOR,
-                                bnx2x_vfop_qsetup, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qsetup,
-                                            cmd->block);
+       /* If needed, clean the filtering data base */
+       if ((qid == LEADING_IDX) &&
+           bnx2x_validate_vf_sp_objs(bp, vf, false)) {
+               rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, false);
+               if (rc)
+                       goto op_err;
+               rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid, true, true);
+               if (rc)
+                       goto op_err;
        }
-       return -ENOMEM;
-}
-
-/* VFOP queue FLR handling (clear vlans, clear macs, queue destructor) */
-static void bnx2x_vfop_qflr(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       int qid = vfop->args.qx.qid;
-       enum bnx2x_vfop_qflr_state state = vfop->state;
-       struct bnx2x_queue_state_params *qstate;
-       struct bnx2x_vfop_cmd cmd;
-
-       bnx2x_vfop_reset_wq(vf);
-
-       if (vfop->rc < 0)
-               goto op_err;
 
-       DP(BNX2X_MSG_IOV, "VF[%d] STATE: %d\n", vf->abs_vfid, state);
+       /* Terminate queue */
+       if (bnx2x_vfq(vf, qid, sp_obj).state != BNX2X_Q_STATE_RESET) {
+               struct bnx2x_queue_state_params qstate;
 
-       cmd.done = bnx2x_vfop_qflr;
-       cmd.block = false;
-
-       switch (state) {
-       case BNX2X_VFOP_QFLR_CLR_VLAN:
-               /* vlan-clear-all: driver-only, don't consume credit */
-               vfop->state = BNX2X_VFOP_QFLR_CLR_MAC;
-
-               if (!validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj))) {
-                       /* the vlan_mac vfop will re-schedule us */
-                       vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd,
-                                                             qid, true);
-                       if (vfop->rc)
-                               goto op_err;
-                       return;
-
-               } else {
-                       /* need to reschedule ourselves */
-                       bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-               }
-
-       case BNX2X_VFOP_QFLR_CLR_MAC:
-               /* mac-clear-all: driver only consume credit */
-               vfop->state = BNX2X_VFOP_QFLR_TERMINATE;
-               if (!validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj))) {
-                       /* the vlan_mac vfop will re-schedule us */
-                       vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd,
-                                                            qid, true);
-                       if (vfop->rc)
-                               goto op_err;
-                       return;
-
-               } else {
-                       /* need to reschedule ourselves */
-                       bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-               }
-
-       case BNX2X_VFOP_QFLR_TERMINATE:
-               qstate = &vfop->op_p->qctor.qstate;
-               memset(qstate , 0, sizeof(*qstate));
-               qstate->q_obj = &bnx2x_vfq(vf, qid, sp_obj);
-               vfop->state = BNX2X_VFOP_QFLR_DONE;
-
-               DP(BNX2X_MSG_IOV, "VF[%d] qstate during flr was %d\n",
-                  vf->abs_vfid, qstate->q_obj->state);
-
-               if (qstate->q_obj->state != BNX2X_Q_STATE_RESET) {
-                       qstate->q_obj->state = BNX2X_Q_STATE_STOPPED;
-                       qstate->cmd = BNX2X_Q_CMD_TERMINATE;
-                       vfop->rc = bnx2x_queue_state_change(bp, qstate);
-                       bnx2x_vfop_finalize(vf, vfop->rc, VFOP_VERIFY_PEND);
-               } else {
-                       goto op_done;
-               }
-
-op_err:
-       BNX2X_ERR("QFLR[%d:%d] error: rc %d\n",
-                 vf->abs_vfid, qid, vfop->rc);
-op_done:
-       case BNX2X_VFOP_QFLR_DONE:
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-       default:
-               bnx2x_vfop_default(state);
+               memset(&qstate, 0, sizeof(struct bnx2x_queue_state_params));
+               qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+               qstate.q_obj->state = BNX2X_Q_STATE_STOPPED;
+               qstate.cmd = BNX2X_Q_CMD_TERMINATE;
+               set_bit(RAMROD_COMP_WAIT, &qstate.ramrod_flags);
+               rc = bnx2x_queue_state_change(bp, &qstate);
+               if (rc)
+                       goto op_err;
        }
-op_pending:
-       return;
-}
-
-static int bnx2x_vfop_qflr_cmd(struct bnx2x *bp,
-                              struct bnx2x_virtf *vf,
-                              struct bnx2x_vfop_cmd *cmd,
-                              int qid)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
 
-       if (vfop) {
-               vfop->args.qx.qid = qid;
-               bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN,
-                                bnx2x_vfop_qflr, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qflr,
-                                            cmd->block);
-       }
-       return -ENOMEM;
+       return 0;
+op_err:
+       BNX2X_ERR("vf[%d:%d] error: rc %d\n", vf->abs_vfid, qid, rc);
+       return rc;
 }
 
-/* VFOP multi-casts */
-static void bnx2x_vfop_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                  bnx2x_mac_addr_t *mcasts, int mc_num, bool drv_only)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_mcast_ramrod_params *mcast = &vfop->op_p->mcast;
-       struct bnx2x_raw_obj *raw = &mcast->mcast_obj->raw;
-       struct bnx2x_vfop_args_mcast *args = &vfop->args.mc_list;
-       enum bnx2x_vfop_mcast_state state = vfop->state;
-       int i;
-
-       bnx2x_vfop_reset_wq(vf);
-
-       if (vfop->rc < 0)
-               goto op_err;
+       struct bnx2x_mcast_list_elem *mc = NULL;
+       struct bnx2x_mcast_ramrod_params mcast;
+       int rc, i;
 
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       switch (state) {
-       case BNX2X_VFOP_MCAST_DEL:
-               /* clear existing mcasts */
-               vfop->state = (args->mc_num) ? BNX2X_VFOP_MCAST_ADD
-                                            : BNX2X_VFOP_MCAST_CHK_DONE;
-               mcast->mcast_list_len = vf->mcast_list_len;
-               vf->mcast_list_len = args->mc_num;
-               vfop->rc = bnx2x_config_mcast(bp, mcast, BNX2X_MCAST_CMD_DEL);
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
-
-       case BNX2X_VFOP_MCAST_ADD:
-               if (raw->check_pending(raw))
-                       goto op_pending;
-
-               /* update mcast list on the ramrod params */
-               INIT_LIST_HEAD(&mcast->mcast_list);
-               for (i = 0; i < args->mc_num; i++)
-                       list_add_tail(&(args->mc[i].link),
-                                     &mcast->mcast_list);
-               mcast->mcast_list_len = args->mc_num;
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
 
-               /* add new mcasts */
-               vfop->state = BNX2X_VFOP_MCAST_CHK_DONE;
-               vfop->rc = bnx2x_config_mcast(bp, mcast,
-                                             BNX2X_MCAST_CMD_ADD);
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-
-       case BNX2X_VFOP_MCAST_CHK_DONE:
-               vfop->rc = raw->check_pending(raw) ? 1 : 0;
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-       default:
-               bnx2x_vfop_default(state);
+       /* Prepare Multicast command */
+       memset(&mcast, 0, sizeof(struct bnx2x_mcast_ramrod_params));
+       mcast.mcast_obj = &vf->mcast_obj;
+       if (drv_only)
+               set_bit(RAMROD_DRV_CLR_ONLY, &mcast.ramrod_flags);
+       else
+               set_bit(RAMROD_COMP_WAIT, &mcast.ramrod_flags);
+       if (mc_num) {
+               mc = kzalloc(mc_num * sizeof(struct bnx2x_mcast_list_elem),
+                            GFP_KERNEL);
+               if (!mc) {
+                       BNX2X_ERR("Cannot Configure mulicasts due to lack of memory\n");
+                       return -ENOMEM;
+               }
        }
-op_err:
-       BNX2X_ERR("MCAST CONFIG error: rc %d\n", vfop->rc);
-op_done:
-       kfree(args->mc);
-       bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
-       return;
-}
 
-int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
-                        struct bnx2x_virtf *vf,
-                        struct bnx2x_vfop_cmd *cmd,
-                        bnx2x_mac_addr_t *mcasts,
-                        int mcast_num, bool drv_only)
-{
-       struct bnx2x_vfop *vfop = NULL;
-       size_t mc_sz = mcast_num * sizeof(struct bnx2x_mcast_list_elem);
-       struct bnx2x_mcast_list_elem *mc = mc_sz ? kzalloc(mc_sz, GFP_KERNEL) :
-                                          NULL;
-
-       if (!mc_sz || mc) {
-               vfop = bnx2x_vfop_add(bp, vf);
-               if (vfop) {
-                       int i;
-                       struct bnx2x_mcast_ramrod_params *ramrod =
-                               &vf->op_params.mcast;
-
-                       /* set ramrod params */
-                       memset(ramrod, 0, sizeof(*ramrod));
-                       ramrod->mcast_obj = &vf->mcast_obj;
-                       if (drv_only)
-                               set_bit(RAMROD_DRV_CLR_ONLY,
-                                       &ramrod->ramrod_flags);
-
-                       /* copy mcasts pointers */
-                       vfop->args.mc_list.mc_num = mcast_num;
-                       vfop->args.mc_list.mc = mc;
-                       for (i = 0; i < mcast_num; i++)
-                               mc[i].mac = mcasts[i];
-
-                       bnx2x_vfop_opset(BNX2X_VFOP_MCAST_DEL,
-                                        bnx2x_vfop_mcast, cmd->done);
-                       return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mcast,
-                                                    cmd->block);
-               } else {
+       /* clear existing mcasts */
+       mcast.mcast_list_len = vf->mcast_list_len;
+       vf->mcast_list_len = mc_num;
+       rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL);
+       if (rc) {
+               BNX2X_ERR("Failed to remove multicasts\n");
+               if (mc)
                        kfree(mc);
-               }
+               return rc;
        }
-       return -ENOMEM;
-}
-
-/* VFOP rx-mode */
-static void bnx2x_vfop_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_rx_mode_ramrod_params *ramrod = &vfop->op_p->rx_mode;
-       enum bnx2x_vfop_rxmode_state state = vfop->state;
-
-       bnx2x_vfop_reset_wq(vf);
-
-       if (vfop->rc < 0)
-               goto op_err;
 
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       switch (state) {
-       case BNX2X_VFOP_RXMODE_CONFIG:
-               /* next state */
-               vfop->state = BNX2X_VFOP_RXMODE_DONE;
+       /* update mcast list on the ramrod params */
+       if (mc_num) {
+               INIT_LIST_HEAD(&mcast.mcast_list);
+               for (i = 0; i < mc_num; i++) {
+                       mc[i].mac = mcasts[i];
+                       list_add_tail(&mc[i].link,
+                                     &mcast.mcast_list);
+               }
 
-               /* record the accept flags in vfdb so hypervisor can modify them
-                * if necessary
-                */
-               bnx2x_vfq(vf, ramrod->cl_id - vf->igu_base_id, accept_flags) =
-                       ramrod->rx_accept_flags;
-               vfop->rc = bnx2x_config_rx_mode(bp, ramrod);
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-op_err:
-               BNX2X_ERR("RXMODE error: rc %d\n", vfop->rc);
-op_done:
-       case BNX2X_VFOP_RXMODE_DONE:
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-       default:
-               bnx2x_vfop_default(state);
+               /* add new mcasts */
+               rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_ADD);
+               if (rc)
+                       BNX2X_ERR("Faled to add multicasts\n");
+               kfree(mc);
        }
-op_pending:
-       return;
+
+       return rc;
 }
 
 static void bnx2x_vf_prep_rx_mode(struct bnx2x *bp, u8 qid,
@@ -1268,118 +644,56 @@ static void bnx2x_vf_prep_rx_mode(struct bnx2x *bp, u8 qid,
        ramrod->rdata_mapping = bnx2x_vf_sp_map(bp, vf, rx_mode_rdata.e2);
 }
 
-int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
-                         struct bnx2x_virtf *vf,
-                         struct bnx2x_vfop_cmd *cmd,
-                         int qid, unsigned long accept_flags)
+int bnx2x_vf_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                   int qid, unsigned long accept_flags)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
-       if (vfop) {
-               struct bnx2x_rx_mode_ramrod_params *ramrod =
-                       &vf->op_params.rx_mode;
+       struct bnx2x_rx_mode_ramrod_params ramrod;
 
-               bnx2x_vf_prep_rx_mode(bp, qid, ramrod, vf, accept_flags);
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
 
-               bnx2x_vfop_opset(BNX2X_VFOP_RXMODE_CONFIG,
-                                bnx2x_vfop_rxmode, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rxmode,
-                                            cmd->block);
-       }
-       return -ENOMEM;
+       bnx2x_vf_prep_rx_mode(bp, qid, &ramrod, vf, accept_flags);
+       set_bit(RAMROD_COMP_WAIT, &ramrod.ramrod_flags);
+       vfq_get(vf, qid)->accept_flags = ramrod.rx_accept_flags;
+       return bnx2x_config_rx_mode(bp, &ramrod);
 }
 
-/* VFOP queue tear-down ('drop all' rx-mode, clear vlans, clear macs,
- * queue destructor)
- */
-static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_queue_teardown(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       int qid = vfop->args.qx.qid;
-       enum bnx2x_vfop_qteardown_state state = vfop->state;
-       struct bnx2x_vfop_cmd cmd;
-
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       cmd.done = bnx2x_vfop_qdown;
-       cmd.block = false;
-
-       switch (state) {
-       case BNX2X_VFOP_QTEARDOWN_RXMODE:
-               /* Drop all */
-               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN;
-               vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0);
-               if (vfop->rc)
-                       goto op_err;
-               return;
-
-       case BNX2X_VFOP_QTEARDOWN_CLR_VLAN:
-               /* vlan-clear-all: don't consume credit */
-               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MAC;
-               vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, false);
-               if (vfop->rc)
-                       goto op_err;
-               return;
-
-       case BNX2X_VFOP_QTEARDOWN_CLR_MAC:
-               /* mac-clear-all: consume credit */
-               vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_MCAST;
-               vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, false);
-               if (vfop->rc)
-                       goto op_err;
-               return;
+       int rc;
 
-       case BNX2X_VFOP_QTEARDOWN_CLR_MCAST:
-               vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR;
-               vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL, 0, false);
-               if (vfop->rc)
-                       goto op_err;
-               return;
+       DP(BNX2X_MSG_IOV, "vf[%d:%d]\n", vf->abs_vfid, qid);
 
-       case BNX2X_VFOP_QTEARDOWN_QDTOR:
-               /* run the queue destruction flow */
-               DP(BNX2X_MSG_IOV, "case: BNX2X_VFOP_QTEARDOWN_QDTOR\n");
-               vfop->state = BNX2X_VFOP_QTEARDOWN_DONE;
-               DP(BNX2X_MSG_IOV, "new state: BNX2X_VFOP_QTEARDOWN_DONE\n");
-               vfop->rc = bnx2x_vfop_qdtor_cmd(bp, vf, &cmd, qid);
-               DP(BNX2X_MSG_IOV, "returned from cmd\n");
-               if (vfop->rc)
+       /* Remove all classification configuration for leading queue */
+       if (qid == LEADING_IDX) {
+               rc = bnx2x_vf_rxmode(bp, vf, qid, 0);
+               if (rc)
                        goto op_err;
-               return;
-op_err:
-       BNX2X_ERR("QTEARDOWN[%d:%d] error: rc %d\n",
-                 vf->abs_vfid, qid, vfop->rc);
-
-       case BNX2X_VFOP_QTEARDOWN_DONE:
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-       default:
-               bnx2x_vfop_default(state);
-       }
-}
 
-int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
-                        struct bnx2x_virtf *vf,
-                        struct bnx2x_vfop_cmd *cmd,
-                        int qid)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-
-       /* for non leading queues skip directly to qdown sate */
-       if (vfop) {
-               vfop->args.qx.qid = qid;
-               bnx2x_vfop_opset(qid == LEADING_IDX ?
-                                BNX2X_VFOP_QTEARDOWN_RXMODE :
-                                BNX2X_VFOP_QTEARDOWN_QDTOR, bnx2x_vfop_qdown,
-                                cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qdown,
-                                            cmd->block);
+               /* Remove filtering if feasible */
+               if (bnx2x_validate_vf_sp_objs(bp, vf, true)) {
+                       rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
+                                                    false, false);
+                       if (rc)
+                               goto op_err;
+                       rc = bnx2x_vf_vlan_mac_clear(bp, vf, qid,
+                                                    false, true);
+                       if (rc)
+                               goto op_err;
+                       rc = bnx2x_vf_mcast(bp, vf, NULL, 0, false);
+                       if (rc)
+                               goto op_err;
+               }
        }
 
-       return -ENOMEM;
+       /* Destroy queue */
+       rc = bnx2x_vf_queue_destroy(bp, vf, qid);
+       if (rc)
+               goto op_err;
+       return rc;
+op_err:
+       BNX2X_ERR("vf[%d:%d] error: rc %d\n",
+                 vf->abs_vfid, qid, rc);
+       return rc;
 }
 
 /* VF enable primitives
@@ -1446,12 +760,12 @@ static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf)
        if (vf->cfg_flags & VF_CFG_INT_SIMD)
                val |= IGU_VF_CONF_SINGLE_ISR_EN;
        val &= ~IGU_VF_CONF_PARENT_MASK;
-       val |= BP_FUNC(bp) << IGU_VF_CONF_PARENT_SHIFT; /* parent PF */
+       val |= (BP_ABS_FUNC(bp) >> 1) << IGU_VF_CONF_PARENT_SHIFT;
        REG_WR(bp, IGU_REG_VF_CONFIGURATION, val);
 
        DP(BNX2X_MSG_IOV,
-          "value in IGU_REG_VF_CONFIGURATION of vf %d after write %x\n",
-          vf->abs_vfid, REG_RD(bp, IGU_REG_VF_CONFIGURATION));
+          "value in IGU_REG_VF_CONFIGURATION of vf %d after write is 0x%08x\n",
+          vf->abs_vfid, val);
 
        bnx2x_pretend_func(bp, BP_ABS_FUNC(bp));
 
@@ -1579,120 +893,63 @@ static void bnx2x_vf_flr_clnup_hw(struct bnx2x *bp, struct bnx2x_virtf *vf)
        bnx2x_tx_hw_flushed(bp, poll_cnt);
 }
 
-static void bnx2x_vfop_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static void bnx2x_vf_flr(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
-       enum bnx2x_vfop_flr_state state = vfop->state;
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vfop_flr,
-               .block = false,
-       };
-
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
+       int rc, i;
 
-       switch (state) {
-       case BNX2X_VFOP_FLR_QUEUES:
-               /* the cleanup operations are valid if and only if the VF
-                * was first acquired.
-                */
-               if (++(qx->qid) < vf_rxq_count(vf)) {
-                       vfop->rc = bnx2x_vfop_qflr_cmd(bp, vf, &cmd,
-                                                      qx->qid);
-                       if (vfop->rc)
-                               goto op_err;
-                       return;
-               }
-               /* remove multicasts */
-               vfop->state = BNX2X_VFOP_FLR_HW;
-               vfop->rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, NULL,
-                                               0, true);
-               if (vfop->rc)
-                       goto op_err;
-               return;
-       case BNX2X_VFOP_FLR_HW:
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
 
-               /* dispatch final cleanup and wait for HW queues to flush */
-               bnx2x_vf_flr_clnup_hw(bp, vf);
+       /* the cleanup operations are valid if and only if the VF
+        * was first acquired.
+        */
+       for (i = 0; i < vf_rxq_count(vf); i++) {
+               rc = bnx2x_vf_queue_flr(bp, vf, i);
+               if (rc)
+                       goto out;
+       }
 
-               /* release VF resources */
-               bnx2x_vf_free_resc(bp, vf);
+       /* remove multicasts */
+       bnx2x_vf_mcast(bp, vf, NULL, 0, true);
 
-               /* re-open the mailbox */
-               bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+       /* dispatch final cleanup and wait for HW queues to flush */
+       bnx2x_vf_flr_clnup_hw(bp, vf);
 
-               goto op_done;
-       default:
-               bnx2x_vfop_default(state);
-       }
-op_err:
-       BNX2X_ERR("VF[%d] FLR error: rc %d\n", vf->abs_vfid, vfop->rc);
-op_done:
-       vf->flr_clnup_stage = VF_FLR_ACK;
-       bnx2x_vfop_end(bp, vf, vfop);
-       bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
-}
+       /* release VF resources */
+       bnx2x_vf_free_resc(bp, vf);
 
-static int bnx2x_vfop_flr_cmd(struct bnx2x *bp,
-                             struct bnx2x_virtf *vf,
-                             vfop_handler_t done)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       if (vfop) {
-               vfop->args.qx.qid = -1; /* loop */
-               bnx2x_vfop_opset(BNX2X_VFOP_FLR_QUEUES,
-                                bnx2x_vfop_flr, done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_flr, false);
-       }
-       return -ENOMEM;
+       /* re-open the mailbox */
+       bnx2x_vf_enable_mbx(bp, vf->abs_vfid);
+       return;
+out:
+       BNX2X_ERR("vf[%d:%d] failed flr: rc %d\n",
+                 vf->abs_vfid, i, rc);
 }
 
-static void bnx2x_vf_flr_clnup(struct bnx2x *bp, struct bnx2x_virtf *prev_vf)
+static void bnx2x_vf_flr_clnup(struct bnx2x *bp)
 {
-       int i = prev_vf ? prev_vf->index + 1 : 0;
        struct bnx2x_virtf *vf;
+       int i;
 
-       /* find next VF to cleanup */
-next_vf_to_clean:
-       for (;
-            i < BNX2X_NR_VIRTFN(bp) &&
-            (bnx2x_vf(bp, i, state) != VF_RESET ||
-             bnx2x_vf(bp, i, flr_clnup_stage) != VF_FLR_CLN);
-            i++)
-               ;
+       for (i = 0; i < BNX2X_NR_VIRTFN(bp); i++) {
+               /* VF should be RESET & in FLR cleanup states */
+               if (bnx2x_vf(bp, i, state) != VF_RESET ||
+                   !bnx2x_vf(bp, i, flr_clnup_stage))
+                       continue;
 
-       DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n", i,
-          BNX2X_NR_VIRTFN(bp));
+               DP(BNX2X_MSG_IOV, "next vf to cleanup: %d. Num of vfs: %d\n",
+                  i, BNX2X_NR_VIRTFN(bp));
 
-       if (i < BNX2X_NR_VIRTFN(bp)) {
                vf = BP_VF(bp, i);
 
                /* lock the vf pf channel */
                bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
 
                /* invoke the VF FLR SM */
-               if (bnx2x_vfop_flr_cmd(bp, vf, bnx2x_vf_flr_clnup)) {
-                       BNX2X_ERR("VF[%d]: FLR cleanup failed -ENOMEM\n",
-                                 vf->abs_vfid);
+               bnx2x_vf_flr(bp, vf);
 
-                       /* mark the VF to be ACKED and continue */
-                       vf->flr_clnup_stage = VF_FLR_ACK;
-                       goto next_vf_to_clean;
-               }
-               return;
-       }
-
-       /* we are done, update vf records */
-       for_each_vf(bp, i) {
-               vf = BP_VF(bp, i);
-
-               if (vf->flr_clnup_stage != VF_FLR_ACK)
-                       continue;
-
-               vf->flr_clnup_stage = VF_FLR_EPILOG;
+               /* mark the VF to be ACKED and continue */
+               vf->flr_clnup_stage = false;
+               bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_FLR);
        }
 
        /* Acknowledge the handled VFs.
@@ -1742,7 +999,7 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
                if (reset) {
                        /* set as reset and ready for cleanup */
                        vf->state = VF_RESET;
-                       vf->flr_clnup_stage = VF_FLR_CLN;
+                       vf->flr_clnup_stage = true;
 
                        DP(BNX2X_MSG_IOV,
                           "Initiating Final cleanup for VF %d\n",
@@ -1751,7 +1008,7 @@ void bnx2x_vf_handle_flr_event(struct bnx2x *bp)
        }
 
        /* do the FLR cleanup for all marked VFs*/
-       bnx2x_vf_flr_clnup(bp, NULL);
+       bnx2x_vf_flr_clnup(bp);
 }
 
 /* IOV global initialization routines  */
@@ -2018,7 +1275,6 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
                bnx2x_vf(bp, i, index) = i;
                bnx2x_vf(bp, i, abs_vfid) = iov->first_vf_in_pf + i;
                bnx2x_vf(bp, i, state) = VF_FREE;
-               INIT_LIST_HEAD(&bnx2x_vf(bp, i, op_list_head));
                mutex_init(&bnx2x_vf(bp, i, op_mutex));
                bnx2x_vf(bp, i, op_current) = CHANNEL_TLV_NONE;
        }
@@ -2039,6 +1295,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
                goto failed;
        }
 
+       /* Prepare the VFs event synchronization mechanism */
+       mutex_init(&bp->vfdb->event_mutex);
+
        return 0;
 failed:
        DP(BNX2X_MSG_IOV, "Failed err=%d\n", err);
@@ -2117,7 +1376,9 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp)
                cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ);
 
                if (cxt->size) {
-                       BNX2X_PCI_ALLOC(cxt->addr, &cxt->mapping, cxt->size);
+                       cxt->addr = BNX2X_PCI_ALLOC(&cxt->mapping, cxt->size);
+                       if (!cxt->addr)
+                               goto alloc_mem_err;
                } else {
                        cxt->addr = NULL;
                        cxt->mapping = 0;
@@ -2127,20 +1388,28 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp)
 
        /* allocate vfs ramrods dma memory - client_init and set_mac */
        tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp);
-       BNX2X_PCI_ALLOC(BP_VFDB(bp)->sp_dma.addr, &BP_VFDB(bp)->sp_dma.mapping,
-                       tot_size);
+       BP_VFDB(bp)->sp_dma.addr = BNX2X_PCI_ALLOC(&BP_VFDB(bp)->sp_dma.mapping,
+                                                  tot_size);
+       if (!BP_VFDB(bp)->sp_dma.addr)
+               goto alloc_mem_err;
        BP_VFDB(bp)->sp_dma.size = tot_size;
 
        /* allocate mailboxes */
        tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE;
-       BNX2X_PCI_ALLOC(BP_VF_MBX_DMA(bp)->addr, &BP_VF_MBX_DMA(bp)->mapping,
-                       tot_size);
+       BP_VF_MBX_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_MBX_DMA(bp)->mapping,
+                                                 tot_size);
+       if (!BP_VF_MBX_DMA(bp)->addr)
+               goto alloc_mem_err;
+
        BP_VF_MBX_DMA(bp)->size = tot_size;
 
        /* allocate local bulletin boards */
        tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE;
-       BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr,
-                       &BP_VF_BULLETIN_DMA(bp)->mapping, tot_size);
+       BP_VF_BULLETIN_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_BULLETIN_DMA(bp)->mapping,
+                                                      tot_size);
+       if (!BP_VF_BULLETIN_DMA(bp)->addr)
+               goto alloc_mem_err;
+
        BP_VF_BULLETIN_DMA(bp)->size = tot_size;
 
        return 0;
@@ -2166,6 +1435,9 @@ static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
                             bnx2x_vf_sp_map(bp, vf, q_data),
                             q_type);
 
+       /* sp indication is set only when vlan/mac/etc. are initialized */
+       q->sp_initialized = false;
+
        DP(BNX2X_MSG_IOV,
           "initialized vf %d's queue object. func id set to %d. cid set to 0x%x\n",
           vf->abs_vfid, q->sp_obj.func_id, q->cid);
@@ -2269,7 +1541,7 @@ int bnx2x_iov_chip_cleanup(struct bnx2x *bp)
 
        /* release all the VFs */
        for_each_vf(bp, i)
-               bnx2x_vf_release(bp, BP_VF(bp, i), true); /* blocking */
+               bnx2x_vf_release(bp, BP_VF(bp, i));
 
        return 0;
 }
@@ -2359,6 +1631,12 @@ void bnx2x_vf_handle_filters_eqe(struct bnx2x *bp,
        smp_mb__after_clear_bit();
 }
 
+static void bnx2x_vf_handle_rss_update_eqe(struct bnx2x *bp,
+                                          struct bnx2x_virtf *vf)
+{
+       vf->rss_conf_obj.raw.clear_pending(&vf->rss_conf_obj.raw);
+}
+
 int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
 {
        struct bnx2x_virtf *vf;
@@ -2383,6 +1661,7 @@ int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem)
        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);
                DP(BNX2X_MSG_IOV, "checking filtering comp cid=%d\n", cid);
@@ -2447,13 +1726,15 @@ get_vf:
                   vf->abs_vfid, qidx);
                bnx2x_vf_handle_filters_eqe(bp, vf);
                break;
+       case EVENT_RING_OPCODE_RSS_UPDATE_RULES:
+               DP(BNX2X_MSG_IOV, "got VF [%d:%d] RSS update ramrod\n",
+                  vf->abs_vfid, qidx);
+               bnx2x_vf_handle_rss_update_eqe(bp, vf);
        case EVENT_RING_OPCODE_VF_FLR:
        case EVENT_RING_OPCODE_MALICIOUS_VF:
                /* Do nothing for now */
                return 0;
        }
-       /* SRIOV: reschedule any 'in_progress' operations */
-       bnx2x_iov_sp_event(bp, cid, false);
 
        return 0;
 }
@@ -2490,23 +1771,6 @@ void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
        }
 }
 
-void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work)
-{
-       struct bnx2x_virtf *vf;
-
-       /* check if the cid is the VF range */
-       if (!IS_SRIOV(bp) || !bnx2x_iov_is_vf_cid(bp, vf_cid))
-               return;
-
-       vf = bnx2x_vf_by_cid(bp, vf_cid);
-       if (vf) {
-               /* set in_progress flag */
-               atomic_set(&vf->op_in_progress, 1);
-               if (queue_work)
-                       queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
-       }
-}
-
 void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
 {
        int i;
@@ -2527,10 +1791,10 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
        first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX -
                (is_fcoe ? 0 : 1);
 
-       DP(BNX2X_MSG_IOV,
-          "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
-          BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
-          first_queue_query_index + num_queues_req);
+       DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
+              "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n",
+              BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index,
+              first_queue_query_index + num_queues_req);
 
        cur_data_offset = bp->fw_stats_data_mapping +
                offsetof(struct bnx2x_fw_stats_data, queue_stats) +
@@ -2544,9 +1808,9 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
                struct bnx2x_virtf *vf = BP_VF(bp, i);
 
                if (vf->state != VF_ENABLED) {
-                       DP(BNX2X_MSG_IOV,
-                          "vf %d not enabled so no stats for it\n",
-                          vf->abs_vfid);
+                       DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS),
+                              "vf %d not enabled so no stats for it\n",
+                              vf->abs_vfid);
                        continue;
                }
 
@@ -2588,32 +1852,6 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp)
        bp->fw_stats_req->hdr.cmd_num = bp->fw_stats_num + stats_count;
 }
 
-void bnx2x_iov_sp_task(struct bnx2x *bp)
-{
-       int i;
-
-       if (!IS_SRIOV(bp))
-               return;
-       /* Iterate over all VFs and invoke state transition for VFs with
-        * 'in-progress' slow-path operations
-        */
-       DP(BNX2X_MSG_IOV, "searching for pending vf operations\n");
-       for_each_vf(bp, i) {
-               struct bnx2x_virtf *vf = BP_VF(bp, i);
-
-               if (!vf) {
-                       BNX2X_ERR("VF was null! skipping...\n");
-                       continue;
-               }
-
-               if (!list_empty(&vf->op_list_head) &&
-                   atomic_read(&vf->op_in_progress)) {
-                       DP(BNX2X_MSG_IOV, "running pending op for vf %d\n", i);
-                       bnx2x_vfop_cur(bp, vf)->transition(bp, vf);
-               }
-       }
-}
-
 static inline
 struct bnx2x_virtf *__vf_from_stat_id(struct bnx2x *bp, u8 stat_id)
 {
@@ -2849,52 +2087,26 @@ static void bnx2x_set_vf_state(void *cookie)
        p->vf->state = p->state;
 }
 
-/* VFOP close (teardown the queues, delete mcasts and close HW) */
-static void bnx2x_vfop_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_vfop_args_qx *qx = &vfop->args.qx;
-       enum bnx2x_vfop_close_state state = vfop->state;
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vfop_close,
-               .block = false,
-       };
+       int rc = 0, i;
 
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       switch (state) {
-       case BNX2X_VFOP_CLOSE_QUEUES:
-
-               if (++(qx->qid) < vf_rxq_count(vf)) {
-                       vfop->rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qx->qid);
-                       if (vfop->rc)
-                               goto op_err;
-                       return;
-               }
-               vfop->state = BNX2X_VFOP_CLOSE_HW;
-               vfop->rc = 0;
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT);
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
 
-       case BNX2X_VFOP_CLOSE_HW:
-
-               /* disable the interrupts */
-               DP(BNX2X_MSG_IOV, "disabling igu\n");
-               bnx2x_vf_igu_disable(bp, vf);
+       /* Close all queues */
+       for (i = 0; i < vf_rxq_count(vf); i++) {
+               rc = bnx2x_vf_queue_teardown(bp, vf, i);
+               if (rc)
+                       goto op_err;
+       }
 
-               /* disable the VF */
-               DP(BNX2X_MSG_IOV, "clearing qtbl\n");
-               bnx2x_vf_clr_qtbl(bp, vf);
+       /* disable the interrupts */
+       DP(BNX2X_MSG_IOV, "disabling igu\n");
+       bnx2x_vf_igu_disable(bp, vf);
 
-               goto op_done;
-       default:
-               bnx2x_vfop_default(state);
-       }
-op_err:
-       BNX2X_ERR("VF[%d] CLOSE error: rc %d\n", vf->abs_vfid, vfop->rc);
-op_done:
+       /* disable the VF */
+       DP(BNX2X_MSG_IOV, "clearing qtbl\n");
+       bnx2x_vf_clr_qtbl(bp, vf);
 
        /* need to make sure there are no outstanding stats ramrods which may
         * cause the device to access the VF's stats buffer which it will free
@@ -2909,43 +2121,20 @@ op_done:
        }
 
        DP(BNX2X_MSG_IOV, "set state to acquired\n");
-       bnx2x_vfop_end(bp, vf, vfop);
-op_pending:
-       /* Not supported at the moment; Exists for macros only */
-       return;
-}
 
-int bnx2x_vfop_close_cmd(struct bnx2x *bp,
-                        struct bnx2x_virtf *vf,
-                        struct bnx2x_vfop_cmd *cmd)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       if (vfop) {
-               vfop->args.qx.qid = -1; /* loop */
-               bnx2x_vfop_opset(BNX2X_VFOP_CLOSE_QUEUES,
-                                bnx2x_vfop_close, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_close,
-                                            cmd->block);
-       }
-       return -ENOMEM;
+       return 0;
+op_err:
+       BNX2X_ERR("vf[%d] CLOSE error: rc %d\n", vf->abs_vfid, rc);
+       return rc;
 }
 
 /* VF release can be called either: 1. The VF was acquired but
  * not enabled 2. the vf was enabled or in the process of being
  * enabled
  */
-static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vfop_release,
-               .block = false,
-       };
-
-       DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
-
-       if (vfop->rc < 0)
-               goto op_err;
+       int rc;
 
        DP(BNX2X_MSG_IOV, "VF[%d] STATE: %s\n", vf->abs_vfid,
           vf->state == VF_FREE ? "Free" :
@@ -2956,116 +2145,87 @@ static void bnx2x_vfop_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
 
        switch (vf->state) {
        case VF_ENABLED:
-               vfop->rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
-               if (vfop->rc)
+               rc = bnx2x_vf_close(bp, vf);
+               if (rc)
                        goto op_err;
-               return;
-
+               /* Fallthrough to release resources */
        case VF_ACQUIRED:
                DP(BNX2X_MSG_IOV, "about to free resources\n");
                bnx2x_vf_free_resc(bp, vf);
-               DP(BNX2X_MSG_IOV, "vfop->rc %d\n", vfop->rc);
-               goto op_done;
+               break;
 
        case VF_FREE:
        case VF_RESET:
-               /* do nothing */
-               goto op_done;
        default:
-               bnx2x_vfop_default(vf->state);
+               break;
        }
+       return 0;
 op_err:
-       BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, vfop->rc);
-op_done:
-       bnx2x_vfop_end(bp, vf, vfop);
+       BNX2X_ERR("VF[%d] RELEASE error: rc %d\n", vf->abs_vfid, rc);
+       return rc;
 }
 
-static void bnx2x_vfop_rss(struct bnx2x *bp, struct bnx2x_virtf *vf)
+int bnx2x_vf_rss_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                       struct bnx2x_config_rss_params *rss)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       enum bnx2x_vfop_rss_state state;
-
-       if (!vfop) {
-               BNX2X_ERR("vfop was null\n");
-               return;
-       }
-
-       state = vfop->state;
-       bnx2x_vfop_reset_wq(vf);
-
-       if (vfop->rc < 0)
-               goto op_err;
-
-       DP(BNX2X_MSG_IOV, "vf[%d] STATE: %d\n", vf->abs_vfid, state);
-
-       switch (state) {
-       case BNX2X_VFOP_RSS_CONFIG:
-               /* next state */
-               vfop->state = BNX2X_VFOP_RSS_DONE;
-               bnx2x_config_rss(bp, &vfop->op_p->rss);
-               bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE);
-op_err:
-               BNX2X_ERR("RSS error: rc %d\n", vfop->rc);
-op_done:
-       case BNX2X_VFOP_RSS_DONE:
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-       default:
-               bnx2x_vfop_default(state);
-       }
-op_pending:
-       return;
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
+       set_bit(RAMROD_COMP_WAIT, &rss->ramrod_flags);
+       return bnx2x_config_rss(bp, rss);
 }
 
-int bnx2x_vfop_release_cmd(struct bnx2x *bp,
-                          struct bnx2x_virtf *vf,
-                          struct bnx2x_vfop_cmd *cmd)
+int bnx2x_vf_tpa_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                       struct vfpf_tpa_tlv *tlv,
+                       struct bnx2x_queue_update_tpa_params *params)
 {
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       if (vfop) {
-               bnx2x_vfop_opset(-1, /* use vf->state */
-                                bnx2x_vfop_release, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_release,
-                                            cmd->block);
-       }
-       return -ENOMEM;
-}
+       aligned_u64 *sge_addr = tlv->tpa_client_info.sge_addr;
+       struct bnx2x_queue_state_params qstate;
+       int qid, rc = 0;
 
-int bnx2x_vfop_rss_cmd(struct bnx2x *bp,
-                      struct bnx2x_virtf *vf,
-                      struct bnx2x_vfop_cmd *cmd)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
+       DP(BNX2X_MSG_IOV, "vf[%d]\n", vf->abs_vfid);
+
+       /* Set ramrod params */
+       memset(&qstate, 0, sizeof(struct bnx2x_queue_state_params));
+       memcpy(&qstate.params.update_tpa, params,
+              sizeof(struct bnx2x_queue_update_tpa_params));
+       qstate.cmd = BNX2X_Q_CMD_UPDATE_TPA;
+       set_bit(RAMROD_COMP_WAIT, &qstate.ramrod_flags);
 
-       if (vfop) {
-               bnx2x_vfop_opset(BNX2X_VFOP_RSS_CONFIG, bnx2x_vfop_rss,
-                                cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_rss,
-                                            cmd->block);
+       for (qid = 0; qid < vf_rxq_count(vf); qid++) {
+               qstate.q_obj = &bnx2x_vfq(vf, qid, sp_obj);
+               qstate.params.update_tpa.sge_map = sge_addr[qid];
+               DP(BNX2X_MSG_IOV, "sge_addr[%d:%d] %08x:%08x\n",
+                  vf->abs_vfid, qid, U64_HI(sge_addr[qid]),
+                  U64_LO(sge_addr[qid]));
+               rc = bnx2x_queue_state_change(bp, &qstate);
+               if (rc) {
+                       BNX2X_ERR("Failed to configure sge_addr %08x:%08x for [%d:%d]\n",
+                                 U64_HI(sge_addr[qid]), U64_LO(sge_addr[qid]),
+                                 vf->abs_vfid, qid);
+                       return rc;
+               }
        }
-       return -ENOMEM;
+
+       return rc;
 }
 
 /* VF release ~ VF close + VF release-resources
  * Release is the ultimate SW shutdown and is called whenever an
  * irrecoverable error is encountered.
  */
-void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block)
+int bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
-       struct bnx2x_vfop_cmd cmd = {
-               .done = NULL,
-               .block = block,
-       };
        int rc;
 
        DP(BNX2X_MSG_IOV, "PF releasing vf %d\n", vf->abs_vfid);
        bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
 
-       rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
+       rc = bnx2x_vf_free(bp, vf);
        if (rc)
                WARN(rc,
                     "VF[%d] Failed to allocate resources for release op- rc=%d\n",
                     vf->abs_vfid, rc);
+       bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
+       return rc;
 }
 
 static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
@@ -3074,16 +2234,6 @@ static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp,
        *sbdf = vf->devfn | (vf->bus << 8);
 }
 
-static inline void bnx2x_vf_get_bars(struct bnx2x *bp, struct bnx2x_virtf *vf,
-                      struct bnx2x_vf_bar_info *bar_info)
-{
-       int n;
-
-       bar_info->nr_bars = bp->vfdb->sriov.nres;
-       for (n = 0; n < bar_info->nr_bars; n++)
-               bar_info->bars[n] = vf->bars[n];
-}
-
 void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
                              enum channel_tlvs tlv)
 {
@@ -3405,13 +2555,13 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx,
        ivi->spoofchk = 1; /*always enabled */
        if (vf->state == VF_ENABLED) {
                /* mac and vlan are in vlan_mac objects */
-               if (validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj)))
+               if (bnx2x_validate_vf_sp_objs(bp, vf, false)) {
                        mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac,
                                                0, ETH_ALEN);
-               if (validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, vlan_obj)))
                        vlan_obj->get_n_elements(bp, vlan_obj, 1,
                                                 (u8 *)&ivi->vlan, 0,
                                                 VLAN_HLEN);
+               }
        } else {
                /* mac */
                if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID))
@@ -3485,17 +2635,17 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac)
            q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
                /* configure the mac in device on this vf's queue */
                unsigned long ramrod_flags = 0;
-               struct bnx2x_vlan_mac_obj *mac_obj =
-                       &bnx2x_leading_vfq(vf, mac_obj);
+               struct bnx2x_vlan_mac_obj *mac_obj;
 
-               rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj));
-               if (rc)
-                       return rc;
+               /* User should be able to see failure reason in system logs */
+               if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+                       return -EINVAL;
 
                /* must lock vfpf channel to protect against vf flows */
                bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
 
                /* remove existing eth macs */
+               mac_obj = &bnx2x_leading_vfq(vf, mac_obj);
                rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
                if (rc) {
                        BNX2X_ERR("failed to delete eth macs\n");
@@ -3569,17 +2719,16 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos)
            BNX2X_Q_LOGICAL_STATE_ACTIVE)
                return rc;
 
-       /* configure the vlan in device on this vf's queue */
-       vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
-       rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj));
-       if (rc)
-               return rc;
+       /* User should be able to see error in system logs */
+       if (!bnx2x_validate_vf_sp_objs(bp, vf, true))
+               return -EINVAL;
 
        /* must lock vfpf channel to protect against vf flows */
        bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN);
 
        /* remove existing vlans */
        __set_bit(RAMROD_COMP_WAIT, &ramrod_flags);
+       vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj);
        rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_mac_flags,
                                  &ramrod_flags);
        if (rc) {
@@ -3736,13 +2885,9 @@ void bnx2x_timer_sriov(struct bnx2x *bp)
        bnx2x_sample_bulletin(bp);
 
        /* if channel is down we need to self destruct */
-       if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN) {
-               smp_mb__before_clear_bit();
-               set_bit(BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
-                       &bp->sp_rtnl_state);
-               smp_mb__after_clear_bit();
-               schedule_delayed_work(&bp->sp_rtnl_task, 0);
-       }
+       if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN)
+               bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN,
+                                      BNX2X_MSG_IOV);
 }
 
 void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp)
@@ -3756,12 +2901,16 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
        mutex_init(&bp->vf2pf_mutex);
 
        /* allocate vf2pf mailbox for vf to pf channel */
-       BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
-                       sizeof(struct bnx2x_vf_mbx_msg));
+       bp->vf2pf_mbox = BNX2X_PCI_ALLOC(&bp->vf2pf_mbox_mapping,
+                                        sizeof(struct bnx2x_vf_mbx_msg));
+       if (!bp->vf2pf_mbox)
+               goto alloc_mem_err;
 
        /* allocate pf 2 vf bulletin board */
-       BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
-                       sizeof(union pf_vf_bulletin));
+       bp->pf2vf_bulletin = BNX2X_PCI_ALLOC(&bp->pf2vf_bulletin_mapping,
+                                            sizeof(union pf_vf_bulletin));
+       if (!bp->pf2vf_bulletin)
+               goto alloc_mem_err;
 
        return 0;
 
@@ -3792,3 +2941,28 @@ void bnx2x_iov_channel_down(struct bnx2x *bp)
                bnx2x_post_vf_bulletin(bp, vf_idx);
        }
 }
+
+void bnx2x_iov_task(struct work_struct *work)
+{
+       struct bnx2x *bp = container_of(work, struct bnx2x, iov_task.work);
+
+       if (!netif_running(bp->dev))
+               return;
+
+       if (test_and_clear_bit(BNX2X_IOV_HANDLE_FLR,
+                              &bp->iov_task_state))
+               bnx2x_vf_handle_flr_event(bp);
+
+       if (test_and_clear_bit(BNX2X_IOV_HANDLE_VF_MSG,
+                              &bp->iov_task_state))
+               bnx2x_vf_mbx(bp);
+}
+
+void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag)
+{
+       smp_mb__before_clear_bit();
+       set_bit(flag, &bp->iov_task_state);
+       smp_mb__after_clear_bit();
+       DP(BNX2X_MSG_IOV, "Scheduling iov task [Flag: %d]\n", flag);
+       queue_delayed_work(bnx2x_iov_wq, &bp->iov_task, 0);
+}
index d9fcca1b5a9db2365773c48c4d9a3ad28462d797..8bf764570eef773eafa87ffd0fca26592e4d64ef 100644 (file)
@@ -30,6 +30,8 @@ enum sample_bulletin_result {
 
 #ifdef CONFIG_BNX2X_SRIOV
 
+extern struct workqueue_struct *bnx2x_iov_wq;
+
 /* The bnx2x device structure holds vfdb structure described below.
  * The VF array is indexed by the relative vfid.
  */
@@ -83,108 +85,35 @@ struct bnx2x_vf_queue {
        u16 index;
        u16 sb_idx;
        bool is_leading;
+       bool sp_initialized;
 };
 
-/* struct bnx2x_vfop_qctor_params - prepare queue construction parameters:
- * q-init, q-setup and SB index
+/* struct bnx2x_vf_queue_construct_params - prepare queue construction
+ * parameters: q-init, q-setup and SB index
  */
-struct bnx2x_vfop_qctor_params {
+struct bnx2x_vf_queue_construct_params {
        struct bnx2x_queue_state_params         qstate;
        struct bnx2x_queue_setup_params         prep_qsetup;
 };
 
-/* VFOP parameters (one copy per VF) */
-union bnx2x_vfop_params {
-       struct bnx2x_vlan_mac_ramrod_params     vlan_mac;
-       struct bnx2x_rx_mode_ramrod_params      rx_mode;
-       struct bnx2x_mcast_ramrod_params        mcast;
-       struct bnx2x_config_rss_params          rss;
-       struct bnx2x_vfop_qctor_params          qctor;
-};
-
 /* forward */
 struct bnx2x_virtf;
 
 /* VFOP definitions */
-typedef void (*vfop_handler_t)(struct bnx2x *bp, struct bnx2x_virtf *vf);
-
-struct bnx2x_vfop_cmd {
-       vfop_handler_t done;
-       bool block;
-};
 
-/* VFOP queue filters command additional arguments */
-struct bnx2x_vfop_filter {
-       struct list_head link;
+struct bnx2x_vf_mac_vlan_filter {
        int type;
-#define BNX2X_VFOP_FILTER_MAC  1
-#define BNX2X_VFOP_FILTER_VLAN 2
+#define BNX2X_VF_FILTER_MAC    1
+#define BNX2X_VF_FILTER_VLAN   2
 
        bool add;
        u8 *mac;
        u16 vid;
 };
 
-struct bnx2x_vfop_filters {
-       int add_cnt;
-       struct list_head head;
-       struct bnx2x_vfop_filter filters[];
-};
-
-/* transient list allocated, built and saved until its
- * passed to the SP-VERBs layer.
- */
-struct bnx2x_vfop_args_mcast {
-       int mc_num;
-       struct bnx2x_mcast_list_elem *mc;
-};
-
-struct bnx2x_vfop_args_qctor {
-       int     qid;
-       u16     sb_idx;
-};
-
-struct bnx2x_vfop_args_qdtor {
-       int     qid;
-       struct eth_context *cxt;
-};
-
-struct bnx2x_vfop_args_defvlan {
-       int     qid;
-       bool    enable;
-       u16     vid;
-       u8      prio;
-};
-
-struct bnx2x_vfop_args_qx {
-       int     qid;
-       bool    en_add;
-};
-
-struct bnx2x_vfop_args_filters {
-       struct bnx2x_vfop_filters *multi_filter;
-       atomic_t *credit;       /* non NULL means 'don't consume credit' */
-};
-
-union bnx2x_vfop_args {
-       struct bnx2x_vfop_args_mcast    mc_list;
-       struct bnx2x_vfop_args_qctor    qctor;
-       struct bnx2x_vfop_args_qdtor    qdtor;
-       struct bnx2x_vfop_args_defvlan  defvlan;
-       struct bnx2x_vfop_args_qx       qx;
-       struct bnx2x_vfop_args_filters  filters;
-};
-
-struct bnx2x_vfop {
-       struct list_head link;
-       int                     rc;             /* return code */
-       int                     state;          /* next state */
-       union bnx2x_vfop_args   args;           /* extra arguments */
-       union bnx2x_vfop_params *op_p;          /* ramrod params */
-
-       /* state machine callbacks */
-       vfop_handler_t transition;
-       vfop_handler_t done;
+struct bnx2x_vf_mac_vlan_filters {
+       int count;
+       struct bnx2x_vf_mac_vlan_filter filters[];
 };
 
 /* vf context */
@@ -204,15 +133,7 @@ struct bnx2x_virtf {
 #define VF_ENABLED     2       /* VF Enabled */
 #define VF_RESET       3       /* VF FLR'd, pending cleanup */
 
-       /* non 0 during flr cleanup */
-       u8 flr_clnup_stage;
-#define VF_FLR_CLN     1       /* reclaim resources and do 'final cleanup'
-                                * sans the end-wait
-                                */
-#define VF_FLR_ACK     2       /* ACK flr notification */
-#define VF_FLR_EPILOG  3       /* wait for VF remnants to dissipate in the HW
-                                * ~ final cleanup' end wait
-                                */
+       bool flr_clnup_stage;   /* true during flr cleanup */
 
        /* dma */
        dma_addr_t fw_stat_map;         /* valid iff VF_CFG_STATS */
@@ -276,11 +197,6 @@ struct bnx2x_virtf {
        struct bnx2x_rss_config_obj     rss_conf_obj;
 
        /* slow-path operations */
-       atomic_t                        op_in_progress;
-       int                             op_rc;
-       bool                            op_wait_blocking;
-       struct list_head                op_list_head;
-       union bnx2x_vfop_params         op_params;
        struct mutex                    op_mutex; /* one vfop at a time mutex */
        enum channel_tlvs               op_current;
 };
@@ -338,11 +254,6 @@ struct bnx2x_vf_mbx {
        u32 vf_addr_hi;
 
        struct vfpf_first_tlv first_tlv;        /* saved VF request header */
-
-       u8 flags;
-#define VF_MSG_INPROCESS       0x1     /* failsafe - the FW should prevent
-                                        * more then one pending msg
-                                        */
 };
 
 struct bnx2x_vf_sp {
@@ -419,6 +330,10 @@ struct bnx2x_vfdb {
        /* the number of msix vectors belonging to this PF designated for VFs */
        u16 vf_sbs_pool;
        u16 first_vf_igu_entry;
+
+       /* sp_rtnl synchronization */
+       struct mutex                    event_mutex;
+       u64                             event_occur;
 };
 
 /* queue access */
@@ -468,13 +383,13 @@ void bnx2x_iov_init_dq(struct bnx2x *bp);
 void bnx2x_iov_init_dmae(struct bnx2x *bp);
 void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
                                struct bnx2x_queue_sp_obj **q_obj);
-void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid, bool queue_work);
 int bnx2x_iov_eq_sp_event(struct bnx2x *bp, union event_ring_elem *elem);
 void bnx2x_iov_adjust_stats_req(struct bnx2x *bp);
 void bnx2x_iov_storm_stats_update(struct bnx2x *bp);
-void bnx2x_iov_sp_task(struct bnx2x *bp);
 /* global vf mailbox routines */
-void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event);
+void bnx2x_vf_mbx(struct bnx2x *bp);
+void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
+                          struct vf_pf_event_data *vfpf_event);
 void bnx2x_vf_enable_mbx(struct bnx2x *bp, u8 abs_vfid);
 
 /* CORE VF API */
@@ -487,162 +402,6 @@ int bnx2x_vf_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
 int bnx2x_vf_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
                  dma_addr_t *sb_map);
 
-/* VFOP generic helpers */
-#define bnx2x_vfop_default(state) do {                         \
-               BNX2X_ERR("Bad state %d\n", (state));           \
-               vfop->rc = -EINVAL;                             \
-               goto op_err;                                    \
-       } while (0)
-
-enum {
-       VFOP_DONE,
-       VFOP_CONT,
-       VFOP_VERIFY_PEND,
-};
-
-#define bnx2x_vfop_finalize(vf, rc, next) do {                         \
-               if ((rc) < 0)                                           \
-                       goto op_err;                                    \
-               else if ((rc) > 0)                                      \
-                       goto op_pending;                                \
-               else if ((next) == VFOP_DONE)                           \
-                       goto op_done;                                   \
-               else if ((next) == VFOP_VERIFY_PEND)                    \
-                       BNX2X_ERR("expected pending\n");                \
-               else {                                                  \
-                       DP(BNX2X_MSG_IOV, "no ramrod. Scheduling\n");   \
-                       atomic_set(&vf->op_in_progress, 1);             \
-                       queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);  \
-                       return;                                         \
-               }                                                       \
-       } while (0)
-
-#define bnx2x_vfop_opset(first_state, trans_hndlr, done_hndlr)         \
-       do {                                                            \
-               vfop->state = first_state;                              \
-               vfop->op_p = &vf->op_params;                            \
-               vfop->transition = trans_hndlr;                         \
-               vfop->done = done_hndlr;                                \
-       } while (0)
-
-static inline struct bnx2x_vfop *bnx2x_vfop_cur(struct bnx2x *bp,
-                                               struct bnx2x_virtf *vf)
-{
-       WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
-       WARN_ON(list_empty(&vf->op_list_head));
-       return list_first_entry(&vf->op_list_head, struct bnx2x_vfop, link);
-}
-
-static inline struct bnx2x_vfop *bnx2x_vfop_add(struct bnx2x *bp,
-                                               struct bnx2x_virtf *vf)
-{
-       struct bnx2x_vfop *vfop = kzalloc(sizeof(*vfop), GFP_KERNEL);
-
-       WARN(!mutex_is_locked(&vf->op_mutex), "about to access vf op linked list but mutex was not locked!");
-       if (vfop) {
-               INIT_LIST_HEAD(&vfop->link);
-               list_add(&vfop->link, &vf->op_list_head);
-       }
-       return vfop;
-}
-
-static inline void bnx2x_vfop_end(struct bnx2x *bp, struct bnx2x_virtf *vf,
-                                 struct bnx2x_vfop *vfop)
-{
-       /* rc < 0 - error, otherwise set to 0 */
-       DP(BNX2X_MSG_IOV, "rc was %d\n", vfop->rc);
-       if (vfop->rc >= 0)
-               vfop->rc = 0;
-       DP(BNX2X_MSG_IOV, "rc is now %d\n", vfop->rc);
-
-       /* unlink the current op context and propagate error code
-        * must be done before invoking the 'done()' handler
-        */
-       WARN(!mutex_is_locked(&vf->op_mutex),
-            "about to access vf op linked list but mutex was not locked!");
-       list_del(&vfop->link);
-
-       if (list_empty(&vf->op_list_head)) {
-               DP(BNX2X_MSG_IOV, "list was empty %d\n", vfop->rc);
-               vf->op_rc = vfop->rc;
-               DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d,  vfop->rc %d\n",
-                  vf->op_rc, vfop->rc);
-       } else {
-               struct bnx2x_vfop *cur_vfop;
-
-               DP(BNX2X_MSG_IOV, "list not empty %d\n", vfop->rc);
-               cur_vfop = bnx2x_vfop_cur(bp, vf);
-               cur_vfop->rc = vfop->rc;
-               DP(BNX2X_MSG_IOV, "copying rc vf->op_rc %d, vfop->rc %d\n",
-                  vf->op_rc, vfop->rc);
-       }
-
-       /* invoke done handler */
-       if (vfop->done) {
-               DP(BNX2X_MSG_IOV, "calling done handler\n");
-               vfop->done(bp, vf);
-       } else {
-               /* there is no done handler for the operation to unlock
-                * the mutex. Must have gotten here from PF initiated VF RELEASE
-                */
-               bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_RELEASE_VF);
-       }
-
-       DP(BNX2X_MSG_IOV, "done handler complete. vf->op_rc %d, vfop->rc %d\n",
-          vf->op_rc, vfop->rc);
-
-       /* if this is the last nested op reset the wait_blocking flag
-        * to release any blocking wrappers, only after 'done()' is invoked
-        */
-       if (list_empty(&vf->op_list_head)) {
-               DP(BNX2X_MSG_IOV, "list was empty after done %d\n", vfop->rc);
-               vf->op_wait_blocking = false;
-       }
-
-       kfree(vfop);
-}
-
-static inline int bnx2x_vfop_wait_blocking(struct bnx2x *bp,
-                                          struct bnx2x_virtf *vf)
-{
-       /* can take a while if any port is running */
-       int cnt = 5000;
-
-       might_sleep();
-       while (cnt--) {
-               if (vf->op_wait_blocking == false) {
-#ifdef BNX2X_STOP_ON_ERROR
-                       DP(BNX2X_MSG_IOV, "exit  (cnt %d)\n", 5000 - cnt);
-#endif
-                       return 0;
-               }
-               usleep_range(1000, 2000);
-
-               if (bp->panic)
-                       return -EIO;
-       }
-
-       /* timeout! */
-#ifdef BNX2X_STOP_ON_ERROR
-       bnx2x_panic();
-#endif
-
-       return -EBUSY;
-}
-
-static inline int bnx2x_vfop_transition(struct bnx2x *bp,
-                                       struct bnx2x_virtf *vf,
-                                       vfop_handler_t transition,
-                                       bool block)
-{
-       if (block)
-               vf->op_wait_blocking = true;
-       transition(bp, vf);
-       if (block)
-               return bnx2x_vfop_wait_blocking(bp, vf);
-       return 0;
-}
-
 /* VFOP queue construction helpers */
 void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf,
                            struct bnx2x_queue_init_params *init_params,
@@ -657,59 +416,41 @@ void bnx2x_vfop_qctor_dump_rx(struct bnx2x *bp, struct bnx2x_virtf *vf,
 void bnx2x_vfop_qctor_prep(struct bnx2x *bp,
                           struct bnx2x_virtf *vf,
                           struct bnx2x_vf_queue *q,
-                          struct bnx2x_vfop_qctor_params *p,
+                          struct bnx2x_vf_queue_construct_params *p,
                           unsigned long q_type);
-int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp,
-                           struct bnx2x_virtf *vf,
-                           struct bnx2x_vfop_cmd *cmd,
-                           struct bnx2x_vfop_filters *macs,
-                           int qid, bool drv_only);
-
-int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp,
-                            struct bnx2x_virtf *vf,
-                            struct bnx2x_vfop_cmd *cmd,
-                            struct bnx2x_vfop_filters *vlans,
-                            int qid, bool drv_only);
-
-int bnx2x_vfop_qsetup_cmd(struct bnx2x *bp,
-                         struct bnx2x_virtf *vf,
-                         struct bnx2x_vfop_cmd *cmd,
-                         int qid);
-
-int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
-                        struct bnx2x_virtf *vf,
-                        struct bnx2x_vfop_cmd *cmd,
-                        int qid);
-
-int bnx2x_vfop_mcast_cmd(struct bnx2x *bp,
-                        struct bnx2x_virtf *vf,
-                        struct bnx2x_vfop_cmd *cmd,
-                        bnx2x_mac_addr_t *mcasts,
-                        int mcast_num, bool drv_only);
-
-int bnx2x_vfop_rxmode_cmd(struct bnx2x *bp,
-                         struct bnx2x_virtf *vf,
-                         struct bnx2x_vfop_cmd *cmd,
-                         int qid, unsigned long accept_flags);
-
-int bnx2x_vfop_close_cmd(struct bnx2x *bp,
-                        struct bnx2x_virtf *vf,
-                        struct bnx2x_vfop_cmd *cmd);
-
-int bnx2x_vfop_release_cmd(struct bnx2x *bp,
-                          struct bnx2x_virtf *vf,
-                          struct bnx2x_vfop_cmd *cmd);
 
-int bnx2x_vfop_rss_cmd(struct bnx2x *bp,
-                      struct bnx2x_virtf *vf,
-                      struct bnx2x_vfop_cmd *cmd);
+int bnx2x_vf_mac_vlan_config_list(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                 struct bnx2x_vf_mac_vlan_filters *filters,
+                                 int qid, bool drv_only);
+
+int bnx2x_vf_queue_setup(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid,
+                        struct bnx2x_vf_queue_construct_params *qctor);
+
+int bnx2x_vf_queue_teardown(struct bnx2x *bp, struct bnx2x_virtf *vf, int qid);
+
+int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                  bnx2x_mac_addr_t *mcasts, int mc_num, bool drv_only);
+
+int bnx2x_vf_rxmode(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                   int qid, unsigned long accept_flags);
+
+int bnx2x_vf_close(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+int bnx2x_vf_free(struct bnx2x *bp, struct bnx2x_virtf *vf);
+
+int bnx2x_vf_rss_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                       struct bnx2x_config_rss_params *rss);
+
+int bnx2x_vf_tpa_update(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                       struct vfpf_tpa_tlv *tlv,
+                       struct bnx2x_queue_update_tpa_params *params);
 
 /* VF release ~ VF close + VF release-resources
  *
  * Release is the ultimate SW shutdown and is called whenever an
  * irrecoverable error is encountered.
  */
-void bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf, bool block);
+int bnx2x_vf_release(struct bnx2x *bp, struct bnx2x_virtf *vf);
 int bnx2x_vf_idx_by_abs_fid(struct bnx2x *bp, u16 abs_vfid);
 u8 bnx2x_vf_max_queue_cnt(struct bnx2x *bp, struct bnx2x_virtf *vf);
 
@@ -772,18 +513,20 @@ void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp);
 int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs);
 void bnx2x_iov_channel_down(struct bnx2x *bp);
 
+void bnx2x_iov_task(struct work_struct *work);
+
+void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag);
+
 #else /* CONFIG_BNX2X_SRIOV */
 
 static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
                                struct bnx2x_queue_sp_obj **q_obj) {}
-static inline void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid,
-                                     bool queue_work) {}
 static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {}
 static inline int bnx2x_iov_eq_sp_event(struct bnx2x *bp,
                                        union event_ring_elem *elem) {return 1; }
-static inline void bnx2x_iov_sp_task(struct bnx2x *bp) {}
-static inline void bnx2x_vf_mbx(struct bnx2x *bp,
-                               struct vf_pf_event_data *vfpf_event) {}
+static inline void bnx2x_vf_mbx(struct bnx2x *bp) {}
+static inline void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
+                                        struct vf_pf_event_data *vfpf_event) {}
 static inline int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) {return line; }
 static inline void bnx2x_iov_init_dq(struct bnx2x *bp) {}
 static inline int bnx2x_iov_alloc_mem(struct bnx2x *bp) {return 0; }
@@ -830,5 +573,8 @@ static inline void bnx2x_pf_set_vfs_vlan(struct bnx2x *bp) {}
 static inline int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs) {return 0; }
 static inline void bnx2x_iov_channel_down(struct bnx2x *bp) {}
 
+static inline void bnx2x_iov_task(struct work_struct *work) {}
+static inline void bnx2x_schedule_iov_task(struct bnx2x *bp, enum bnx2x_iov_flag flag) {}
+
 #endif /* CONFIG_BNX2X_SRIOV */
 #endif /* bnx2x_sriov.h */
index 3fa6c2a2a5a9f46ba82c19103c114649af4da238..0622884596b2f478ec4a2789c17fdd0938544995 100644 (file)
@@ -548,6 +548,7 @@ static void bnx2x_leading_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf,
 
        vf->leading_rss = cl_id;
        q->is_leading = true;
+       q->sp_initialized = true;
 }
 
 /* ask the pf to open a queue for the vf */
@@ -672,6 +673,7 @@ static int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
 
 out:
        bnx2x_vfpf_finalize(bp, &req->first_tlv);
+
        return rc;
 }
 
@@ -894,29 +896,16 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
 
        DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
 
-       switch (mode) {
-       case BNX2X_RX_MODE_NONE: /* no Rx */
+       /* Ignore everything accept MODE_NONE */
+       if (mode  == BNX2X_RX_MODE_NONE) {
                req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
-               break;
-       case BNX2X_RX_MODE_NORMAL:
+       } else {
+               /* Current PF driver will not look at the specific flags,
+                * but they are required when working with older drivers on hv.
+                */
                req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
                req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
                req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
-               break;
-       case BNX2X_RX_MODE_ALLMULTI:
-               req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
-               req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
-               req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
-               break;
-       case BNX2X_RX_MODE_PROMISC:
-               req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
-               req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
-               req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
-               break;
-       default:
-               BNX2X_ERR("BAD rx mode (%d)\n", mode);
-               rc = -EINVAL;
-               goto out;
        }
 
        req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
@@ -937,7 +926,7 @@ int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
                BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
                rc = -EINVAL;
        }
-out:
+
        bnx2x_vfpf_finalize(bp, &req->first_tlv);
 
        return rc;
@@ -1047,7 +1036,8 @@ static void bnx2x_vf_mbx_resp_single_tlv(struct bnx2x *bp,
 }
 
 static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
-                                      struct bnx2x_virtf *vf)
+                                      struct bnx2x_virtf *vf,
+                                      int vf_rc)
 {
        struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf->index);
        struct pfvf_general_resp_tlv *resp = &mbx->msg->resp.general_resp;
@@ -1059,7 +1049,7 @@ static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
        DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
           mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
 
-       resp->hdr.status = bnx2x_pfvf_status_codes(vf->op_rc);
+       resp->hdr.status = bnx2x_pfvf_status_codes(vf_rc);
 
        /* send response */
        vf_addr = HILO_U64(mbx->vf_addr_hi, mbx->vf_addr_lo) +
@@ -1088,9 +1078,6 @@ static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
        storm_memset_vf_mbx_ack(bp, vf->abs_vfid);
        mmiowb();
 
-       /* initiate dmae to send the response */
-       mbx->flags &= ~VF_MSG_INPROCESS;
-
        /* copy the response header including status-done field,
         * must be last dmae, must be after FW is acked
         */
@@ -1110,14 +1097,15 @@ static void bnx2x_vf_mbx_resp_send_msg(struct bnx2x *bp,
        return;
 
 mbx_error:
-       bnx2x_vf_release(bp, vf, false); /* non blocking */
+       bnx2x_vf_release(bp, vf);
 }
 
 static void bnx2x_vf_mbx_resp(struct bnx2x *bp,
-                                      struct bnx2x_virtf *vf)
+                             struct bnx2x_virtf *vf,
+                             int rc)
 {
        bnx2x_vf_mbx_resp_single_tlv(bp, vf);
-       bnx2x_vf_mbx_resp_send_msg(bp, vf);
+       bnx2x_vf_mbx_resp_send_msg(bp, vf, rc);
 }
 
 static void bnx2x_vf_mbx_resp_phys_port(struct bnx2x *bp,
@@ -1159,7 +1147,8 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
        resp->pfdev_info.db_size = bp->db_size;
        resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2;
        resp->pfdev_info.pf_cap = (PFVF_CAP_RSS |
-                                  /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA);
+                                  PFVF_CAP_TPA |
+                                  PFVF_CAP_TPA_UPDATE);
        bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver,
                          sizeof(resp->pfdev_info.fw_ver));
 
@@ -1240,8 +1229,7 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf,
                      sizeof(struct channel_list_end_tlv));
 
        /* send the response */
-       vf->op_rc = vfop_status;
-       bnx2x_vf_mbx_resp_send_msg(bp, vf);
+       bnx2x_vf_mbx_resp_send_msg(bp, vf, vfop_status);
 }
 
 static void bnx2x_vf_mbx_acquire(struct bnx2x *bp, struct bnx2x_virtf *vf,
@@ -1273,19 +1261,20 @@ static void bnx2x_vf_mbx_init_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
                              struct bnx2x_vf_mbx *mbx)
 {
        struct vfpf_init_tlv *init = &mbx->msg->req.init;
+       int rc;
 
        /* record ghost addresses from vf message */
        vf->spq_map = init->spq_addr;
        vf->fw_stat_map = init->stats_addr;
        vf->stats_stride = init->stats_stride;
-       vf->op_rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
+       rc = bnx2x_vf_init(bp, vf, (dma_addr_t *)init->sb_addr);
 
        /* set VF multiqueue statistics collection mode */
        if (init->flags & VFPF_INIT_FLG_STATS_COALESCE)
                vf->cfg_flags |= VF_CFG_STATS_COALESCE;
 
        /* response */
-       bnx2x_vf_mbx_resp(bp, vf);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
 /* convert MBX queue-flags to standard SP queue-flags */
@@ -1320,16 +1309,14 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                 struct bnx2x_vf_mbx *mbx)
 {
        struct vfpf_setup_q_tlv *setup_q = &mbx->msg->req.setup_q;
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vf_mbx_resp,
-               .block = false,
-       };
+       struct bnx2x_vf_queue_construct_params qctor;
+       int rc = 0;
 
        /* verify vf_qid */
        if (setup_q->vf_qid >= vf_rxq_count(vf)) {
                BNX2X_ERR("vf_qid %d invalid, max queue count is %d\n",
                          setup_q->vf_qid, vf_rxq_count(vf));
-               vf->op_rc = -EINVAL;
+               rc = -EINVAL;
                goto response;
        }
 
@@ -1347,9 +1334,10 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
                        bnx2x_leading_vfq_init(bp, vf, q);
 
                /* re-init the VF operation context */
-               memset(&vf->op_params.qctor, 0 , sizeof(vf->op_params.qctor));
-               setup_p = &vf->op_params.qctor.prep_qsetup;
-               init_p =  &vf->op_params.qctor.qstate.params.init;
+               memset(&qctor, 0 ,
+                      sizeof(struct bnx2x_vf_queue_construct_params));
+               setup_p = &qctor.prep_qsetup;
+               init_p =  &qctor.qstate.params.init;
 
                /* activate immediately */
                __set_bit(BNX2X_Q_FLG_ACTIVE, &setup_p->flags);
@@ -1435,44 +1423,34 @@ static void bnx2x_vf_mbx_setup_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                                 q->index, q->sb_idx);
                }
                /* complete the preparations */
-               bnx2x_vfop_qctor_prep(bp, vf, q, &vf->op_params.qctor, q_type);
+               bnx2x_vfop_qctor_prep(bp, vf, q, &qctor, q_type);
 
-               vf->op_rc = bnx2x_vfop_qsetup_cmd(bp, vf, &cmd, q->index);
-               if (vf->op_rc)
+               rc = bnx2x_vf_queue_setup(bp, vf, q->index, &qctor);
+               if (rc)
                        goto response;
-               return;
        }
 response:
-       bnx2x_vf_mbx_resp(bp, vf);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
-enum bnx2x_vfop_filters_state {
-          BNX2X_VFOP_MBX_Q_FILTERS_MACS,
-          BNX2X_VFOP_MBX_Q_FILTERS_VLANS,
-          BNX2X_VFOP_MBX_Q_FILTERS_RXMODE,
-          BNX2X_VFOP_MBX_Q_FILTERS_MCAST,
-          BNX2X_VFOP_MBX_Q_FILTERS_DONE
-};
-
 static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
                                     struct bnx2x_virtf *vf,
                                     struct vfpf_set_q_filters_tlv *tlv,
-                                    struct bnx2x_vfop_filters **pfl,
+                                    struct bnx2x_vf_mac_vlan_filters **pfl,
                                     u32 type_flag)
 {
        int i, j;
-       struct bnx2x_vfop_filters *fl = NULL;
+       struct bnx2x_vf_mac_vlan_filters *fl = NULL;
        size_t fsz;
 
-       fsz = tlv->n_mac_vlan_filters * sizeof(struct bnx2x_vfop_filter) +
-               sizeof(struct bnx2x_vfop_filters);
+       fsz = tlv->n_mac_vlan_filters *
+             sizeof(struct bnx2x_vf_mac_vlan_filter) +
+             sizeof(struct bnx2x_vf_mac_vlan_filters);
 
        fl = kzalloc(fsz, GFP_KERNEL);
        if (!fl)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&fl->head);
-
        for (i = 0, j = 0; i < tlv->n_mac_vlan_filters; i++) {
                struct vfpf_q_mac_vlan_filter *msg_filter = &tlv->filters[i];
 
@@ -1480,17 +1458,17 @@ static int bnx2x_vf_mbx_macvlan_list(struct bnx2x *bp,
                        continue;
                if (type_flag == VFPF_Q_FILTER_DEST_MAC_VALID) {
                        fl->filters[j].mac = msg_filter->mac;
-                       fl->filters[j].type = BNX2X_VFOP_FILTER_MAC;
+                       fl->filters[j].type = BNX2X_VF_FILTER_MAC;
                } else {
                        fl->filters[j].vid = msg_filter->vlan_tag;
-                       fl->filters[j].type = BNX2X_VFOP_FILTER_VLAN;
+                       fl->filters[j].type = BNX2X_VF_FILTER_VLAN;
                }
                fl->filters[j].add =
                        (msg_filter->flags & VFPF_Q_FILTER_SET_MAC) ?
                        true : false;
-               list_add_tail(&fl->filters[j++].link, &fl->head);
+               fl->count++;
        }
-       if (list_empty(&fl->head))
+       if (!fl->count)
                kfree(fl);
        else
                *pfl = fl;
@@ -1530,180 +1508,96 @@ static void bnx2x_vf_mbx_dp_q_filters(struct bnx2x *bp, int msglvl,
 #define VFPF_MAC_FILTER                VFPF_Q_FILTER_DEST_MAC_VALID
 #define VFPF_VLAN_FILTER       VFPF_Q_FILTER_VLAN_TAG_VALID
 
-static void bnx2x_vfop_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
+static int bnx2x_vf_mbx_qfilters(struct bnx2x *bp, struct bnx2x_virtf *vf)
 {
-       int rc;
+       int rc = 0;
 
        struct vfpf_set_q_filters_tlv *msg =
                &BP_VF_MBX(bp, vf->index)->msg->req.set_q_filters;
 
-       struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf);
-       enum bnx2x_vfop_filters_state state = vfop->state;
-
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vfop_mbx_qfilters,
-               .block = false,
-       };
-
-       DP(BNX2X_MSG_IOV, "STATE: %d\n", state);
-
-       if (vfop->rc < 0)
-               goto op_err;
+       /* check for any mac/vlan changes */
+       if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
+               /* build mac list */
+               struct bnx2x_vf_mac_vlan_filters *fl = NULL;
 
-       switch (state) {
-       case BNX2X_VFOP_MBX_Q_FILTERS_MACS:
-               /* next state */
-               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_VLANS;
+               rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+                                              VFPF_MAC_FILTER);
+               if (rc)
+                       goto op_err;
 
-               /* check for any vlan/mac changes */
-               if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
-                       /* build mac list */
-                       struct bnx2x_vfop_filters *fl = NULL;
+               if (fl) {
 
-                       vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
-                                                            VFPF_MAC_FILTER);
-                       if (vfop->rc)
+                       /* set mac list */
+                       rc = bnx2x_vf_mac_vlan_config_list(bp, vf, fl,
+                                                          msg->vf_qid,
+                                                          false);
+                       if (rc)
                                goto op_err;
-
-                       if (fl) {
-                               /* set mac list */
-                               rc = bnx2x_vfop_mac_list_cmd(bp, vf, &cmd, fl,
-                                                            msg->vf_qid,
-                                                            false);
-                               if (rc) {
-                                       vfop->rc = rc;
-                                       goto op_err;
-                               }
-                               return;
-                       }
                }
-               /* fall through */
 
-       case BNX2X_VFOP_MBX_Q_FILTERS_VLANS:
-               /* next state */
-               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_RXMODE;
+               /* build vlan list */
+               fl = NULL;
 
-               /* check for any vlan/mac changes */
-               if (msg->flags & VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED) {
-                       /* build vlan list */
-                       struct bnx2x_vfop_filters *fl = NULL;
-
-                       vfop->rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
-                                                            VFPF_VLAN_FILTER);
-                       if (vfop->rc)
+               rc = bnx2x_vf_mbx_macvlan_list(bp, vf, msg, &fl,
+                                              VFPF_VLAN_FILTER);
+               if (rc)
+                       goto op_err;
+
+               if (fl) {
+                       /* set vlan list */
+                       rc = bnx2x_vf_mac_vlan_config_list(bp, vf, fl,
+                                                          msg->vf_qid,
+                                                          false);
+                       if (rc)
                                goto op_err;
-
-                       if (fl) {
-                               /* set vlan list */
-                               rc = bnx2x_vfop_vlan_list_cmd(bp, vf, &cmd, fl,
-                                                             msg->vf_qid,
-                                                             false);
-                               if (rc) {
-                                       vfop->rc = rc;
-                                       goto op_err;
-                               }
-                               return;
-                       }
                }
-               /* fall through */
-
-       case BNX2X_VFOP_MBX_Q_FILTERS_RXMODE:
-               /* next state */
-               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_MCAST;
-
-               if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
-                       unsigned long accept = 0;
-                       struct pf_vf_bulletin_content *bulletin =
-                               BP_VF_BULLETIN(bp, vf->index);
-
-                       /* covert VF-PF if mask to bnx2x accept flags */
-                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST)
-                               __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
-
-                       if (msg->rx_mask &
-                                       VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST)
-                               __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
-
-                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_UNICAST)
-                               __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept);
-
-                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_ALL_MULTICAST)
-                               __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept);
+       }
 
-                       if (msg->rx_mask & VFPF_RX_MASK_ACCEPT_BROADCAST)
-                               __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
+       if (msg->flags & VFPF_SET_Q_FILTERS_RX_MASK_CHANGED) {
+               unsigned long accept = 0;
+               struct pf_vf_bulletin_content *bulletin =
+                                       BP_VF_BULLETIN(bp, vf->index);
 
-                       /* A packet arriving the vf's mac should be accepted
-                        * with any vlan, unless a vlan has already been
-                        * configured.
-                        */
-                       if (!(bulletin->valid_bitmap & (1 << VLAN_VALID)))
-                               __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
-
-                       /* set rx-mode */
-                       rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd,
-                                                  msg->vf_qid, accept);
-                       if (rc) {
-                               vfop->rc = rc;
-                               goto op_err;
-                       }
-                       return;
+               /* Ignore VF requested mode; instead set a regular mode */
+               if (msg->rx_mask !=  VFPF_RX_MASK_ACCEPT_NONE) {
+                       __set_bit(BNX2X_ACCEPT_UNICAST, &accept);
+                       __set_bit(BNX2X_ACCEPT_MULTICAST, &accept);
+                       __set_bit(BNX2X_ACCEPT_BROADCAST, &accept);
                }
-               /* fall through */
-
-       case BNX2X_VFOP_MBX_Q_FILTERS_MCAST:
-               /* next state */
-               vfop->state = BNX2X_VFOP_MBX_Q_FILTERS_DONE;
-
-               if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
-                       /* set mcasts */
-                       rc = bnx2x_vfop_mcast_cmd(bp, vf, &cmd, msg->multicast,
-                                                 msg->n_multicast, false);
-                       if (rc) {
-                               vfop->rc = rc;
-                               goto op_err;
-                       }
-                       return;
-               }
-               /* fall through */
-op_done:
-       case BNX2X_VFOP_MBX_Q_FILTERS_DONE:
-               bnx2x_vfop_end(bp, vf, vfop);
-               return;
-op_err:
-       BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
-                 vf->abs_vfid, msg->vf_qid, vfop->rc);
-       goto op_done;
 
-       default:
-               bnx2x_vfop_default(state);
+               /* A packet arriving the vf's mac should be accepted
+                * with any vlan, unless a vlan has already been
+                * configured.
+                */
+               if (!(bulletin->valid_bitmap & (1 << VLAN_VALID)))
+                       __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept);
+
+               /* set rx-mode */
+               rc = bnx2x_vf_rxmode(bp, vf, msg->vf_qid, accept);
+               if (rc)
+                       goto op_err;
        }
-}
 
-static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp,
-                                       struct bnx2x_virtf *vf,
-                                       struct bnx2x_vfop_cmd *cmd)
-{
-       struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf);
-       if (vfop) {
-               bnx2x_vfop_opset(BNX2X_VFOP_MBX_Q_FILTERS_MACS,
-                                bnx2x_vfop_mbx_qfilters, cmd->done);
-               return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_mbx_qfilters,
-                                            cmd->block);
+       if (msg->flags & VFPF_SET_Q_FILTERS_MULTICAST_CHANGED) {
+               /* set mcasts */
+               rc = bnx2x_vf_mcast(bp, vf, msg->multicast,
+                                   msg->n_multicast, false);
+               if (rc)
+                       goto op_err;
        }
-       return -ENOMEM;
+op_err:
+       if (rc)
+               BNX2X_ERR("QFILTERS[%d:%d] error: rc %d\n",
+                         vf->abs_vfid, msg->vf_qid, rc);
+       return rc;
 }
 
-static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
-                                      struct bnx2x_virtf *vf,
-                                      struct bnx2x_vf_mbx *mbx)
+static int bnx2x_filters_validate_mac(struct bnx2x *bp,
+                                     struct bnx2x_virtf *vf,
+                                     struct vfpf_set_q_filters_tlv *filters)
 {
-       struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
        struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vf_mbx_resp,
-               .block = false,
-       };
+       int rc = 0;
 
        /* if a mac was already set for this VF via the set vf mac ndo, we only
         * accept mac configurations of that mac. Why accept them at all?
@@ -1715,7 +1609,7 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
                if (filters->n_mac_vlan_filters > 1) {
                        BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n",
                                  vf->abs_vfid);
-                       vf->op_rc = -EPERM;
+                       rc = -EPERM;
                        goto response;
                }
 
@@ -1725,10 +1619,22 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
                        BNX2X_ERR("VF[%d] requested the addition of a mac address not matching the one configured by set_vf_mac ndo\n",
                                  vf->abs_vfid);
 
-                       vf->op_rc = -EPERM;
+                       rc = -EPERM;
                        goto response;
                }
        }
+
+response:
+       return rc;
+}
+
+static int bnx2x_filters_validate_vlan(struct bnx2x *bp,
+                                      struct bnx2x_virtf *vf,
+                                      struct vfpf_set_q_filters_tlv *filters)
+{
+       struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index);
+       int rc = 0;
+
        /* if vlan was set by hypervisor we don't allow guest to config vlan */
        if (bulletin->valid_bitmap & 1 << VLAN_VALID) {
                int i;
@@ -1739,14 +1645,35 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
                            VFPF_Q_FILTER_VLAN_TAG_VALID) {
                                BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n",
                                          vf->abs_vfid);
-                               vf->op_rc = -EPERM;
+                               rc = -EPERM;
                                goto response;
                        }
                }
        }
 
        /* verify vf_qid */
-       if (filters->vf_qid > vf_rxq_count(vf))
+       if (filters->vf_qid > vf_rxq_count(vf)) {
+               rc = -EPERM;
+               goto response;
+       }
+
+response:
+       return rc;
+}
+
+static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
+                                      struct bnx2x_virtf *vf,
+                                      struct bnx2x_vf_mbx *mbx)
+{
+       struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters;
+       int rc;
+
+       rc = bnx2x_filters_validate_mac(bp, vf, filters);
+       if (rc)
+               goto response;
+
+       rc = bnx2x_filters_validate_vlan(bp, vf, filters);
+       if (rc)
                goto response;
 
        DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n",
@@ -1756,125 +1683,169 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp,
        /* print q_filter message */
        bnx2x_vf_mbx_dp_q_filters(bp, BNX2X_MSG_IOV, filters);
 
-       vf->op_rc = bnx2x_vfop_mbx_qfilters_cmd(bp, vf, &cmd);
-       if (vf->op_rc)
-               goto response;
-       return;
-
+       rc = bnx2x_vf_mbx_qfilters(bp, vf);
 response:
-       bnx2x_vf_mbx_resp(bp, vf);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
 static void bnx2x_vf_mbx_teardown_q(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                    struct bnx2x_vf_mbx *mbx)
 {
        int qid = mbx->msg->req.q_op.vf_qid;
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vf_mbx_resp,
-               .block = false,
-       };
+       int rc;
 
        DP(BNX2X_MSG_IOV, "VF[%d] Q_TEARDOWN: vf_qid=%d\n",
           vf->abs_vfid, qid);
 
-       vf->op_rc = bnx2x_vfop_qdown_cmd(bp, vf, &cmd, qid);
-       if (vf->op_rc)
-               bnx2x_vf_mbx_resp(bp, vf);
+       rc = bnx2x_vf_queue_teardown(bp, vf, qid);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
 static void bnx2x_vf_mbx_close_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                  struct bnx2x_vf_mbx *mbx)
 {
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vf_mbx_resp,
-               .block = false,
-       };
+       int rc;
 
        DP(BNX2X_MSG_IOV, "VF[%d] VF_CLOSE\n", vf->abs_vfid);
 
-       vf->op_rc = bnx2x_vfop_close_cmd(bp, vf, &cmd);
-       if (vf->op_rc)
-               bnx2x_vf_mbx_resp(bp, vf);
+       rc = bnx2x_vf_close(bp, vf);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
 static void bnx2x_vf_mbx_release_vf(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                    struct bnx2x_vf_mbx *mbx)
 {
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vf_mbx_resp,
-               .block = false,
-       };
+       int rc;
 
        DP(BNX2X_MSG_IOV, "VF[%d] VF_RELEASE\n", vf->abs_vfid);
 
-       vf->op_rc = bnx2x_vfop_release_cmd(bp, vf, &cmd);
-       if (vf->op_rc)
-               bnx2x_vf_mbx_resp(bp, vf);
+       rc = bnx2x_vf_free(bp, vf);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
 static void bnx2x_vf_mbx_update_rss(struct bnx2x *bp, struct bnx2x_virtf *vf,
                                    struct bnx2x_vf_mbx *mbx)
 {
-       struct bnx2x_vfop_cmd cmd = {
-               .done = bnx2x_vf_mbx_resp,
-               .block = false,
-       };
-       struct bnx2x_config_rss_params *vf_op_params = &vf->op_params.rss;
+       struct bnx2x_config_rss_params rss;
        struct vfpf_rss_tlv *rss_tlv = &mbx->msg->req.update_rss;
+       int rc = 0;
 
        if (rss_tlv->ind_table_size != T_ETH_INDIRECTION_TABLE_SIZE ||
            rss_tlv->rss_key_size != T_ETH_RSS_KEY) {
                BNX2X_ERR("failing rss configuration of vf %d due to size mismatch\n",
                          vf->index);
-               vf->op_rc = -EINVAL;
+               rc = -EINVAL;
                goto mbx_resp;
        }
 
+       memset(&rss, 0, sizeof(struct bnx2x_config_rss_params));
+
        /* set vfop params according to rss tlv */
-       memcpy(vf_op_params->ind_table, rss_tlv->ind_table,
+       memcpy(rss.ind_table, rss_tlv->ind_table,
               T_ETH_INDIRECTION_TABLE_SIZE);
-       memcpy(vf_op_params->rss_key, rss_tlv->rss_key,
-              sizeof(rss_tlv->rss_key));
-       vf_op_params->rss_obj = &vf->rss_conf_obj;
-       vf_op_params->rss_result_mask = rss_tlv->rss_result_mask;
+       memcpy(rss.rss_key, rss_tlv->rss_key, sizeof(rss_tlv->rss_key));
+       rss.rss_obj = &vf->rss_conf_obj;
+       rss.rss_result_mask = rss_tlv->rss_result_mask;
 
        /* flags handled individually for backward/forward compatability */
-       vf_op_params->rss_flags = 0;
-       vf_op_params->ramrod_flags = 0;
+       rss.rss_flags = 0;
+       rss.ramrod_flags = 0;
 
        if (rss_tlv->rss_flags & VFPF_RSS_MODE_DISABLED)
-               __set_bit(BNX2X_RSS_MODE_DISABLED, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_MODE_DISABLED, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_MODE_REGULAR)
-               __set_bit(BNX2X_RSS_MODE_REGULAR, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_MODE_REGULAR, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_SET_SRCH)
-               __set_bit(BNX2X_RSS_SET_SRCH, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_SET_SRCH, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_IPV4)
-               __set_bit(BNX2X_RSS_IPV4, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_IPV4, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_IPV4_TCP)
-               __set_bit(BNX2X_RSS_IPV4_TCP, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_IPV4_TCP, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_IPV4_UDP)
-               __set_bit(BNX2X_RSS_IPV4_UDP, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_IPV4_UDP, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_IPV6)
-               __set_bit(BNX2X_RSS_IPV6, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_IPV6, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_IPV6_TCP)
-               __set_bit(BNX2X_RSS_IPV6_TCP, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_IPV6_TCP, &rss.rss_flags);
        if (rss_tlv->rss_flags & VFPF_RSS_IPV6_UDP)
-               __set_bit(BNX2X_RSS_IPV6_UDP, &vf_op_params->rss_flags);
+               __set_bit(BNX2X_RSS_IPV6_UDP, &rss.rss_flags);
 
        if ((!(rss_tlv->rss_flags & VFPF_RSS_IPV4_TCP) &&
             rss_tlv->rss_flags & VFPF_RSS_IPV4_UDP) ||
            (!(rss_tlv->rss_flags & VFPF_RSS_IPV6_TCP) &&
             rss_tlv->rss_flags & VFPF_RSS_IPV6_UDP)) {
                BNX2X_ERR("about to hit a FW assert. aborting...\n");
-               vf->op_rc = -EINVAL;
+               rc = -EINVAL;
                goto mbx_resp;
        }
 
-       vf->op_rc = bnx2x_vfop_rss_cmd(bp, vf, &cmd);
+       rc = bnx2x_vf_rss_update(bp, vf, &rss);
+mbx_resp:
+       bnx2x_vf_mbx_resp(bp, vf, rc);
+}
+
+static int bnx2x_validate_tpa_params(struct bnx2x *bp,
+                                      struct vfpf_tpa_tlv *tpa_tlv)
+{
+       int rc = 0;
+
+       if (tpa_tlv->tpa_client_info.max_sges_for_packet >
+           U_ETH_MAX_SGES_FOR_PACKET) {
+               rc = -EINVAL;
+               BNX2X_ERR("TPA update: max_sges received %d, max is %d\n",
+                         tpa_tlv->tpa_client_info.max_sges_for_packet,
+                         U_ETH_MAX_SGES_FOR_PACKET);
+       }
+
+       if (tpa_tlv->tpa_client_info.max_tpa_queues > MAX_AGG_QS(bp)) {
+               rc = -EINVAL;
+               BNX2X_ERR("TPA update: max_tpa_queues received %d, max is %d\n",
+                         tpa_tlv->tpa_client_info.max_tpa_queues,
+                         MAX_AGG_QS(bp));
+       }
+
+       return rc;
+}
+
+static void bnx2x_vf_mbx_update_tpa(struct bnx2x *bp, struct bnx2x_virtf *vf,
+                                   struct bnx2x_vf_mbx *mbx)
+{
+       struct bnx2x_queue_update_tpa_params vf_op_params;
+       struct vfpf_tpa_tlv *tpa_tlv = &mbx->msg->req.update_tpa;
+       int rc = 0;
+
+       memset(&vf_op_params, 0, sizeof(vf_op_params));
+
+       if (bnx2x_validate_tpa_params(bp, tpa_tlv))
+               goto mbx_resp;
+
+       vf_op_params.complete_on_both_clients =
+               tpa_tlv->tpa_client_info.complete_on_both_clients;
+       vf_op_params.dont_verify_thr =
+               tpa_tlv->tpa_client_info.dont_verify_thr;
+       vf_op_params.max_agg_sz =
+               tpa_tlv->tpa_client_info.max_agg_size;
+       vf_op_params.max_sges_pkt =
+               tpa_tlv->tpa_client_info.max_sges_for_packet;
+       vf_op_params.max_tpa_queues =
+               tpa_tlv->tpa_client_info.max_tpa_queues;
+       vf_op_params.sge_buff_sz =
+               tpa_tlv->tpa_client_info.sge_buff_size;
+       vf_op_params.sge_pause_thr_high =
+               tpa_tlv->tpa_client_info.sge_pause_thr_high;
+       vf_op_params.sge_pause_thr_low =
+               tpa_tlv->tpa_client_info.sge_pause_thr_low;
+       vf_op_params.tpa_mode =
+               tpa_tlv->tpa_client_info.tpa_mode;
+       vf_op_params.update_ipv4 =
+               tpa_tlv->tpa_client_info.update_ipv4;
+       vf_op_params.update_ipv6 =
+               tpa_tlv->tpa_client_info.update_ipv6;
+
+       rc = bnx2x_vf_tpa_update(bp, vf, tpa_tlv, &vf_op_params);
 
 mbx_resp:
-       if (vf->op_rc)
-               bnx2x_vf_mbx_resp(bp, vf);
+       bnx2x_vf_mbx_resp(bp, vf, rc);
 }
 
 /* dispatch request */
@@ -1916,6 +1887,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
                case CHANNEL_TLV_UPDATE_RSS:
                        bnx2x_vf_mbx_update_rss(bp, vf, mbx);
                        return;
+               case CHANNEL_TLV_UPDATE_TPA:
+                       bnx2x_vf_mbx_update_tpa(bp, vf, mbx);
+                       return;
                }
 
        } else {
@@ -1935,11 +1909,8 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
 
        /* can we respond to VF (do we have an address for it?) */
        if (vf->state == VF_ACQUIRED || vf->state == VF_ENABLED) {
-               /* mbx_resp uses the op_rc of the VF */
-               vf->op_rc = PFVF_STATUS_NOT_SUPPORTED;
-
                /* notify the VF that we do not support this request */
-               bnx2x_vf_mbx_resp(bp, vf);
+               bnx2x_vf_mbx_resp(bp, vf, PFVF_STATUS_NOT_SUPPORTED);
        } else {
                /* can't send a response since this VF is unknown to us
                 * just ack the FW to release the mailbox and unlock
@@ -1952,13 +1923,10 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf,
        }
 }
 
-/* handle new vf-pf message */
-void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
+void bnx2x_vf_mbx_schedule(struct bnx2x *bp,
+                          struct vf_pf_event_data *vfpf_event)
 {
-       struct bnx2x_virtf *vf;
-       struct bnx2x_vf_mbx *mbx;
        u8 vf_idx;
-       int rc;
 
        DP(BNX2X_MSG_IOV,
           "vf pf event received: vfid %d, address_hi %x, address lo %x",
@@ -1970,50 +1938,73 @@ void bnx2x_vf_mbx(struct bnx2x *bp, struct vf_pf_event_data *vfpf_event)
            BNX2X_NR_VIRTFN(bp)) {
                BNX2X_ERR("Illegal vf_id %d max allowed: %d\n",
                          vfpf_event->vf_id, BNX2X_NR_VIRTFN(bp));
-               goto mbx_done;
+               return;
        }
+
        vf_idx = bnx2x_vf_idx_by_abs_fid(bp, vfpf_event->vf_id);
-       mbx = BP_VF_MBX(bp, vf_idx);
 
-       /* verify an event is not currently being processed -
-        * debug failsafe only
-        */
-       if (mbx->flags & VF_MSG_INPROCESS) {
-               BNX2X_ERR("Previous message is still being processed, vf_id %d\n",
-                         vfpf_event->vf_id);
-               goto mbx_done;
-       }
-       vf = BP_VF(bp, vf_idx);
+       /* 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_VFDB(bp)->event_occur |= (1ULL << vf_idx);
+       mutex_unlock(&BP_VFDB(bp)->event_mutex);
 
-       /* save the VF message address */
-       mbx->vf_addr_hi = vfpf_event->msg_addr_hi;
-       mbx->vf_addr_lo = vfpf_event->msg_addr_lo;
-       DP(BNX2X_MSG_IOV, "mailbox vf address hi 0x%x, lo 0x%x, offset 0x%x\n",
-          mbx->vf_addr_hi, mbx->vf_addr_lo, mbx->first_tlv.resp_msg_offset);
+       bnx2x_schedule_iov_task(bp, BNX2X_IOV_HANDLE_VF_MSG);
+}
 
-       /* dmae to get the VF request */
-       rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping, vf->abs_vfid,
-                                 mbx->vf_addr_hi, mbx->vf_addr_lo,
-                                 sizeof(union vfpf_tlvs)/4);
-       if (rc) {
-               BNX2X_ERR("Failed to copy request VF %d\n", vf->abs_vfid);
-               goto mbx_error;
-       }
+/* handle new vf-pf messages */
+void bnx2x_vf_mbx(struct bnx2x *bp)
+{
+       struct bnx2x_vfdb *vfdb = BP_VFDB(bp);
+       u64 events;
+       u8 vf_idx;
+       int rc;
 
-       /* process the VF message header */
-       mbx->first_tlv = mbx->msg->req.first_tlv;
+       if (!vfdb)
+               return;
 
-       /* Clean response buffer to refrain from falsely seeing chains */
-       memset(&mbx->msg->resp, 0, sizeof(union pfvf_tlvs));
+       mutex_lock(&vfdb->event_mutex);
+       events = vfdb->event_occur;
+       vfdb->event_occur = 0;
+       mutex_unlock(&vfdb->event_mutex);
 
-       /* dispatch the request (will prepare the response) */
-       bnx2x_vf_mbx_request(bp, vf, mbx);
-       goto mbx_done;
+       for_each_vf(bp, vf_idx) {
+               struct bnx2x_vf_mbx *mbx = BP_VF_MBX(bp, vf_idx);
+               struct bnx2x_virtf *vf = BP_VF(bp, vf_idx);
 
-mbx_error:
-       bnx2x_vf_release(bp, vf, false); /* non blocking */
-mbx_done:
-       return;
+               /* Handle VFs which have pending events */
+               if (!(events & (1ULL << vf_idx)))
+                       continue;
+
+               DP(BNX2X_MSG_IOV,
+                  "Handling vf pf event vfid %d, address: [%x:%x], resp_offset 0x%x\n",
+                  vf_idx, mbx->vf_addr_hi, mbx->vf_addr_lo,
+                  mbx->first_tlv.resp_msg_offset);
+
+               /* dmae to get the VF request */
+               rc = bnx2x_copy32_vf_dmae(bp, true, mbx->msg_mapping,
+                                         vf->abs_vfid, mbx->vf_addr_hi,
+                                         mbx->vf_addr_lo,
+                                         sizeof(union vfpf_tlvs)/4);
+               if (rc) {
+                       BNX2X_ERR("Failed to copy request VF %d\n",
+                                 vf->abs_vfid);
+                       bnx2x_vf_release(bp, vf);
+                       return;
+               }
+
+               /* process the VF message header */
+               mbx->first_tlv = mbx->msg->req.first_tlv;
+
+               /* Clean response buffer to refrain from falsely
+                * seeing chains.
+                */
+               memset(&mbx->msg->resp, 0, sizeof(union pfvf_tlvs));
+
+               /* dispatch the request (will prepare the response) */
+               bnx2x_vf_mbx_request(bp, vf, mbx);
+       }
 }
 
 /* propagate local bulletin board to vf */
index 208568bc7a71d72d8e19aea70f02485e17c0e8ee..c922b81170e5bc20c4ff69d34d16d40f853c9d8a 100644 (file)
@@ -162,6 +162,7 @@ struct pfvf_acquire_resp_tlv {
 #define PFVF_CAP_RSS           0x00000001
 #define PFVF_CAP_DHC           0x00000002
 #define PFVF_CAP_TPA           0x00000004
+#define PFVF_CAP_TPA_UPDATE    0x00000008
                char fw_ver[32];
                u16 db_size;
                u8  indices_per_sb;
@@ -303,6 +304,25 @@ struct vfpf_set_q_filters_tlv {
        u32 rx_mask;    /* see mask constants at the top of the file */
 };
 
+struct vfpf_tpa_tlv {
+       struct vfpf_first_tlv   first_tlv;
+
+       struct vf_pf_tpa_client_info {
+               aligned_u64 sge_addr[PFVF_MAX_QUEUES_PER_VF];
+               u8 update_ipv4;
+               u8 update_ipv6;
+               u8 max_tpa_queues;
+               u8 max_sges_for_packet;
+               u8 complete_on_both_clients;
+               u8 dont_verify_thr;
+               u8 tpa_mode;
+               u16 sge_buff_size;
+               u16 max_agg_size;
+               u16 sge_pause_thr_low;
+               u16 sge_pause_thr_high;
+       } tpa_client_info;
+};
+
 /* close VF (disable VF) */
 struct vfpf_close_tlv {
        struct vfpf_first_tlv   first_tlv;
@@ -331,6 +351,7 @@ union vfpf_tlvs {
        struct vfpf_set_q_filters_tlv   set_q_filters;
        struct vfpf_release_tlv         release;
        struct vfpf_rss_tlv             update_rss;
+       struct vfpf_tpa_tlv             update_tpa;
        struct channel_list_end_tlv     list_end;
        struct tlv_buffer_size          tlv_buf_size;
 };
@@ -405,6 +426,7 @@ enum channel_tlvs {
        CHANNEL_TLV_PF_SET_VLAN,
        CHANNEL_TLV_UPDATE_RSS,
        CHANNEL_TLV_PHYS_PORT_ID,
+       CHANNEL_TLV_UPDATE_TPA,
        CHANNEL_TLV_MAX
 };
 
index fcf9105a5476123c0e5d4e7a4095f05d6c95774e..09f3fefcbf9ce405839e6f5893174a79dc91c5b8 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom 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
@@ -342,7 +342,7 @@ static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
        while (retry < 3) {
                rc = 0;
                rcu_read_lock();
-               ulp_ops = rcu_dereference(cnic_ulp_tbl[CNIC_ULP_ISCSI]);
+               ulp_ops = rcu_dereference(cp->ulp_ops[CNIC_ULP_ISCSI]);
                if (ulp_ops)
                        rc = ulp_ops->iscsi_nl_send_msg(
                                cp->ulp_handle[CNIC_ULP_ISCSI],
@@ -726,7 +726,7 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma)
 
        for (i = 0; i < dma->num_pages; i++) {
                if (dma->pg_arr[i]) {
-                       dma_free_coherent(&dev->pcidev->dev, BNX2_PAGE_SIZE,
+                       dma_free_coherent(&dev->pcidev->dev, CNIC_PAGE_SIZE,
                                          dma->pg_arr[i], dma->pg_map_arr[i]);
                        dma->pg_arr[i] = NULL;
                }
@@ -785,7 +785,7 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
 
        for (i = 0; i < pages; i++) {
                dma->pg_arr[i] = dma_alloc_coherent(&dev->pcidev->dev,
-                                                   BNX2_PAGE_SIZE,
+                                                   CNIC_PAGE_SIZE,
                                                    &dma->pg_map_arr[i],
                                                    GFP_ATOMIC);
                if (dma->pg_arr[i] == NULL)
@@ -794,8 +794,8 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
        if (!use_pg_tbl)
                return 0;
 
-       dma->pgtbl_size = ((pages * 8) + BNX2_PAGE_SIZE - 1) &
-                         ~(BNX2_PAGE_SIZE - 1);
+       dma->pgtbl_size = ((pages * 8) + CNIC_PAGE_SIZE - 1) &
+                         ~(CNIC_PAGE_SIZE - 1);
        dma->pgtbl = dma_alloc_coherent(&dev->pcidev->dev, dma->pgtbl_size,
                                        &dma->pgtbl_map, GFP_ATOMIC);
        if (dma->pgtbl == NULL)
@@ -900,8 +900,8 @@ static int cnic_alloc_context(struct cnic_dev *dev)
        if (BNX2_CHIP(cp) == BNX2_CHIP_5709) {
                int i, k, arr_size;
 
-               cp->ctx_blk_size = BNX2_PAGE_SIZE;
-               cp->cids_per_blk = BNX2_PAGE_SIZE / 128;
+               cp->ctx_blk_size = CNIC_PAGE_SIZE;
+               cp->cids_per_blk = CNIC_PAGE_SIZE / 128;
                arr_size = BNX2_MAX_CID / cp->cids_per_blk *
                           sizeof(struct cnic_ctx);
                cp->ctx_arr = kzalloc(arr_size, GFP_KERNEL);
@@ -933,7 +933,7 @@ static int cnic_alloc_context(struct cnic_dev *dev)
                for (i = 0; i < cp->ctx_blks; i++) {
                        cp->ctx_arr[i].ctx =
                                dma_alloc_coherent(&dev->pcidev->dev,
-                                                  BNX2_PAGE_SIZE,
+                                                  CNIC_PAGE_SIZE,
                                                   &cp->ctx_arr[i].mapping,
                                                   GFP_KERNEL);
                        if (cp->ctx_arr[i].ctx == NULL)
@@ -1013,7 +1013,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
        if (udev->l2_ring)
                return 0;
 
-       udev->l2_ring_size = pages * BNX2_PAGE_SIZE;
+       udev->l2_ring_size = pages * CNIC_PAGE_SIZE;
        udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
                                           &udev->l2_ring_map,
                                           GFP_KERNEL | __GFP_COMP);
@@ -1021,7 +1021,7 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
                return -ENOMEM;
 
        udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
-       udev->l2_buf_size = PAGE_ALIGN(udev->l2_buf_size);
+       udev->l2_buf_size = CNIC_PAGE_ALIGN(udev->l2_buf_size);
        udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
                                          &udev->l2_buf_map,
                                          GFP_KERNEL | __GFP_COMP);
@@ -1102,7 +1102,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
                uinfo->mem[0].size = MB_GET_CID_ADDR(TX_TSS_CID +
                                                     TX_MAX_TSS_RINGS + 1);
                uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
-                                       PAGE_MASK;
+                                       CNIC_PAGE_MASK;
                if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
                        uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
                else
@@ -1113,7 +1113,7 @@ static int cnic_init_uio(struct cnic_dev *dev)
                uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0);
 
                uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
-                       PAGE_MASK;
+                       CNIC_PAGE_MASK;
                uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
 
                uinfo->name = "bnx2x_cnic";
@@ -1267,14 +1267,14 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
        for (i = MAX_ISCSI_TBL_SZ; i < cp->max_cid_space; i++)
                cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_FCOE;
 
-       pages = PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
-               PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->max_cid_space * CNIC_KWQ16_DATA_SIZE) /
+               CNIC_PAGE_SIZE;
 
        ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
        if (ret)
                return -ENOMEM;
 
-       n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
+       n = CNIC_PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
        for (i = 0, j = 0; i < cp->max_cid_space; i++) {
                long off = CNIC_KWQ16_DATA_SIZE * (i % n);
 
@@ -1296,7 +1296,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
                        goto error;
        }
 
-       pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / CNIC_PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
        if (ret)
                goto error;
@@ -1466,8 +1466,8 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
        cp->r2tq_size = cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS *
                        BNX2X_ISCSI_R2TQE_SIZE;
        cp->hq_size = cp->num_ccells * BNX2X_ISCSI_HQ_BD_SIZE;
-       pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
-       hq_bds = pages * (PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
+       pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
+       hq_bds = pages * (CNIC_PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
        cp->num_cqs = req1->num_cqs;
 
        if (!dev->max_iscsi_conn)
@@ -1477,9 +1477,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
        CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(pfid),
                  req1->rq_num_wqes);
        CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
-                TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
                  TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1489,9 +1489,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
                  USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfid),
                  req1->rq_buffer_size);
        CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_USTRORM_INTMEM +
-                USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_USTRORM_INTMEM +
                  USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1504,9 +1504,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
 
        /* init Xstorm RAM */
        CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
-                XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
                  XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1519,9 +1519,9 @@ static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
 
        /* init Cstorm RAM */
        CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfid),
-                 PAGE_SIZE);
+                 CNIC_PAGE_SIZE);
        CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
-                CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), PAGE_SHIFT);
+                CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfid), CNIC_PAGE_BITS);
        CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
                  CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfid),
                  req1->num_tasks_per_conn);
@@ -1623,18 +1623,18 @@ static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
        }
 
        ctx->cid = cid;
-       pages = PAGE_ALIGN(cp->task_array_size) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->task_array_size) / CNIC_PAGE_SIZE;
 
        ret = cnic_alloc_dma(dev, &iscsi->task_array_info, pages, 1);
        if (ret)
                goto error;
 
-       pages = PAGE_ALIGN(cp->r2tq_size) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->r2tq_size) / CNIC_PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &iscsi->r2tq_info, pages, 1);
        if (ret)
                goto error;
 
-       pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+       pages = CNIC_PAGE_ALIGN(cp->hq_size) / CNIC_PAGE_SIZE;
        ret = cnic_alloc_dma(dev, &iscsi->hq_info, pages, 1);
        if (ret)
                goto error;
@@ -1760,7 +1760,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
        ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
        /* TSTORM requires the base address of RQ DB & not PTE */
        ictx->tstorm_st_context.iscsi.rq_db_phy_addr.lo =
-               req2->rq_page_table_addr_lo & PAGE_MASK;
+               req2->rq_page_table_addr_lo & CNIC_PAGE_MASK;
        ictx->tstorm_st_context.iscsi.rq_db_phy_addr.hi =
                req2->rq_page_table_addr_hi;
        ictx->tstorm_st_context.iscsi.iscsi_conn_id = req1->iscsi_conn_id;
@@ -1842,7 +1842,7 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
        /* CSTORM and USTORM initialization is different, CSTORM requires
         * CQ DB base & not PTE addr */
        ictx->cstorm_st_context.cq_db_base.lo =
-               req1->cq_page_table_addr_lo & PAGE_MASK;
+               req1->cq_page_table_addr_lo & CNIC_PAGE_MASK;
        ictx->cstorm_st_context.cq_db_base.hi = req1->cq_page_table_addr_hi;
        ictx->cstorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
        ictx->cstorm_st_context.cq_proc_en_bit_map = (1 << cp->num_cqs) - 1;
@@ -2911,7 +2911,7 @@ static int cnic_l2_completion(struct cnic_local *cp)
        u16 hw_cons, sw_cons;
        struct cnic_uio_dev *udev = cp->udev;
        union eth_rx_cqe *cqe, *cqe_ring = (union eth_rx_cqe *)
-                                       (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+                                       (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
        u32 cmd;
        int comp = 0;
 
@@ -3244,7 +3244,8 @@ static int cnic_copy_ulp_stats(struct cnic_dev *dev, int ulp_type)
        int rc;
 
        mutex_lock(&cnic_lock);
-       ulp_ops = cnic_ulp_tbl_prot(ulp_type);
+       ulp_ops = rcu_dereference_protected(cp->ulp_ops[ulp_type],
+                                           lockdep_is_held(&cnic_lock));
        if (ulp_ops && ulp_ops->cnic_get_stats)
                rc = ulp_ops->cnic_get_stats(cp->ulp_handle[ulp_type]);
        else
@@ -4384,7 +4385,7 @@ static int cnic_setup_5709_context(struct cnic_dev *dev, int valid)
                u32 idx = cp->ctx_arr[i].cid / cp->cids_per_blk;
                u32 val;
 
-               memset(cp->ctx_arr[i].ctx, 0, BNX2_PAGE_SIZE);
+               memset(cp->ctx_arr[i].ctx, 0, CNIC_PAGE_SIZE);
 
                CNIC_WR(dev, BNX2_CTX_HOST_PAGE_TBL_DATA0,
                        (cp->ctx_arr[i].mapping & 0xffffffff) | valid_bit);
@@ -4628,7 +4629,7 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
                val = BNX2_L2CTX_L2_STATUSB_NUM(sb_id);
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_HOST_BDIDX, val);
 
-       rxbd = udev->l2_ring + BNX2_PAGE_SIZE;
+       rxbd = udev->l2_ring + CNIC_PAGE_SIZE;
        for (i = 0; i < BNX2_MAX_RX_DESC_CNT; i++, rxbd++) {
                dma_addr_t buf_map;
                int n = (i % cp->l2_rx_ring_size) + 1;
@@ -4639,11 +4640,11 @@ static void cnic_init_bnx2_rx_ring(struct cnic_dev *dev)
                rxbd->rx_bd_haddr_hi = (u64) buf_map >> 32;
                rxbd->rx_bd_haddr_lo = (u64) buf_map & 0xffffffff;
        }
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val);
        rxbd->rx_bd_haddr_hi = val;
 
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
        cnic_ctx_wr(dev, cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val);
        rxbd->rx_bd_haddr_lo = val;
 
@@ -4709,10 +4710,10 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        val = CNIC_RD(dev, BNX2_MQ_CONFIG);
        val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
-       if (BNX2_PAGE_BITS > 12)
+       if (CNIC_PAGE_BITS > 12)
                val |= (12 - 8)  << 4;
        else
-               val |= (BNX2_PAGE_BITS - 8)  << 4;
+               val |= (CNIC_PAGE_BITS - 8)  << 4;
 
        CNIC_WR(dev, BNX2_MQ_CONFIG, val);
 
@@ -4742,13 +4743,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        /* Initialize the kernel work queue context. */
        val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
-             (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+             (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
        cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_TYPE, val);
 
-       val = (BNX2_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
+       val = (CNIC_PAGE_SIZE / sizeof(struct kwqe) - 1) << 16;
        cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
 
-       val = ((BNX2_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
+       val = ((CNIC_PAGE_SIZE / sizeof(struct kwqe)) << 16) | KWQ_PAGE_CNT;
        cnic_ctx_wr(dev, kwq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
 
        val = (u32) ((u64) cp->kwq_info.pgtbl_map >> 32);
@@ -4768,13 +4769,13 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
 
        /* Initialize the kernel complete queue context. */
        val = KRNLQ_TYPE_TYPE_KRNLQ | KRNLQ_SIZE_TYPE_SIZE |
-             (BNX2_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
+             (CNIC_PAGE_BITS - 8) | KRNLQ_FLAGS_QE_SELF_SEQ;
        cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_TYPE, val);
 
-       val = (BNX2_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
+       val = (CNIC_PAGE_SIZE / sizeof(struct kcqe) - 1) << 16;
        cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_QE_SELF_SEQ_MAX, val);
 
-       val = ((BNX2_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
+       val = ((CNIC_PAGE_SIZE / sizeof(struct kcqe)) << 16) | KCQ_PAGE_CNT;
        cnic_ctx_wr(dev, kcq_cid_addr, L5_KRNLQ_PGTBL_NPAGES, val);
 
        val = (u32) ((u64) cp->kcq1.dma.pgtbl_map >> 32);
@@ -4918,7 +4919,7 @@ static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev,
        u32 cli = cp->ethdev->iscsi_l2_client_id;
        u32 val;
 
-       memset(txbd, 0, BNX2_PAGE_SIZE);
+       memset(txbd, 0, CNIC_PAGE_SIZE);
 
        buf_map = udev->l2_buf_map;
        for (i = 0; i < BNX2_MAX_TX_DESC_CNT; i += 3, txbd += 3) {
@@ -4978,9 +4979,9 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
        struct bnx2x *bp = netdev_priv(dev->netdev);
        struct cnic_uio_dev *udev = cp->udev;
        struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (udev->l2_ring +
-                               BNX2_PAGE_SIZE);
+                               CNIC_PAGE_SIZE);
        struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *)
-                               (udev->l2_ring + (2 * BNX2_PAGE_SIZE));
+                               (udev->l2_ring + (2 * CNIC_PAGE_SIZE));
        struct host_sp_status_block *sb = cp->bnx2x_def_status_blk;
        int i;
        u32 cli = cp->ethdev->iscsi_l2_client_id;
@@ -5004,20 +5005,20 @@ static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev,
                rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
        }
 
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) >> 32;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) >> 32;
        rxbd->addr_hi = cpu_to_le32(val);
        data->rx.bd_page_base.hi = cpu_to_le32(val);
 
-       val = (u64) (ring_map + BNX2_PAGE_SIZE) & 0xffffffff;
+       val = (u64) (ring_map + CNIC_PAGE_SIZE) & 0xffffffff;
        rxbd->addr_lo = cpu_to_le32(val);
        data->rx.bd_page_base.lo = cpu_to_le32(val);
 
        rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
-       val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) >> 32;
+       val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) >> 32;
        rxcqe->addr_hi = cpu_to_le32(val);
        data->rx.cqe_page_base.hi = cpu_to_le32(val);
 
-       val = (u64) (ring_map + (2 * BNX2_PAGE_SIZE)) & 0xffffffff;
+       val = (u64) (ring_map + (2 * CNIC_PAGE_SIZE)) & 0xffffffff;
        rxcqe->addr_lo = cpu_to_le32(val);
        data->rx.cqe_page_base.lo = cpu_to_le32(val);
 
@@ -5265,8 +5266,8 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
                msleep(10);
        }
        clear_bit(CNIC_LCL_FL_RINGS_INITED, &cp->cnic_local_flags);
-       rx_ring = udev->l2_ring + BNX2_PAGE_SIZE;
-       memset(rx_ring, 0, BNX2_PAGE_SIZE);
+       rx_ring = udev->l2_ring + CNIC_PAGE_SIZE;
+       memset(rx_ring, 0, CNIC_PAGE_SIZE);
 }
 
 static int cnic_register_netdev(struct cnic_dev *dev)
index 0d6b13f854d959ab0cdaf101192dfe2c4930c372..d535ae4228b4ccb12d9df6e24f7fed6911e9a6da 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic.h: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom 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
index 95a8e4b11c9fcce45a0f24acea5bd1b86fa53ab9..dcbca6997e8fbcb9d4f38f12acbf8718846bdfbd 100644 (file)
@@ -1,7 +1,7 @@
 
 /* cnic.c: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom 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
index 8cf6b1926069d2c541b8b6888eced6463b887aa4..5f4d5573a73dbb8252d34ec6419750c3ec06eee1 100644 (file)
@@ -1,6 +1,6 @@
 /* cnic_if.h: Broadcom CNIC core network driver.
  *
- * Copyright (c) 2006-2013 Broadcom Corporation
+ * Copyright (c) 2006-2014 Broadcom 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
@@ -14,8 +14,8 @@
 
 #include "bnx2x/bnx2x_mfw_req.h"
 
-#define CNIC_MODULE_VERSION    "2.5.19"
-#define CNIC_MODULE_RELDATE    "December 19, 2013"
+#define CNIC_MODULE_VERSION    "2.5.20"
+#define CNIC_MODULE_RELDATE    "March 14, 2014"
 
 #define CNIC_ULP_RDMA          0
 #define CNIC_ULP_ISCSI         1
 #define MAX_CNIC_ULP_TYPE_EXT  3
 #define MAX_CNIC_ULP_TYPE      4
 
+/* Use CPU native page size up to 16K for cnic ring sizes.  */
+#if (PAGE_SHIFT > 14)
+#define CNIC_PAGE_BITS 14
+#else
+#define CNIC_PAGE_BITS PAGE_SHIFT
+#endif
+#define CNIC_PAGE_SIZE (1 << (CNIC_PAGE_BITS))
+#define CNIC_PAGE_ALIGN(addr) ALIGN(addr, CNIC_PAGE_SIZE)
+#define CNIC_PAGE_MASK (~((CNIC_PAGE_SIZE) - 1))
+
 struct kwqe {
        u32 kwqe_op_flag;
 
diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile
new file mode 100644 (file)
index 0000000..31f55a9
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_BCMGENET) += genet.o
+genet-objs := bcmgenet.o bcmmii.o
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
new file mode 100644 (file)
index 0000000..adf8acb
--- /dev/null
@@ -0,0 +1,2584 @@
+/*
+ * Broadcom GENET (Gigabit Ethernet) controller driver
+ *
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt)                            "bcmgenet: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+#include <linux/clk.h>
+#include <linux/version.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <net/arp.h>
+
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/phy.h>
+
+#include <asm/unaligned.h>
+
+#include "bcmgenet.h"
+
+/* Maximum number of hardware queues, downsized if needed */
+#define GENET_MAX_MQ_CNT       4
+
+/* Default highest priority queue for multi queue support */
+#define GENET_Q0_PRIORITY      0
+
+#define GENET_DEFAULT_BD_CNT   \
+       (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->bds_cnt)
+
+#define RX_BUF_LENGTH          2048
+#define SKB_ALIGNMENT          32
+
+/* Tx/Rx DMA register offset, skip 256 descriptors */
+#define WORDS_PER_BD(p)                (p->hw_params->words_per_bd)
+#define DMA_DESC_SIZE          (WORDS_PER_BD(priv) * sizeof(u32))
+
+#define GENET_TDMA_REG_OFF     (priv->hw_params->tdma_offset + \
+                               TOTAL_DESC * DMA_DESC_SIZE)
+
+#define GENET_RDMA_REG_OFF     (priv->hw_params->rdma_offset + \
+                               TOTAL_DESC * DMA_DESC_SIZE)
+
+static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv,
+                                               void __iomem *d, u32 value)
+{
+       __raw_writel(value, d + DMA_DESC_LENGTH_STATUS);
+}
+
+static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv,
+                                               void __iomem *d)
+{
+       return __raw_readl(d + DMA_DESC_LENGTH_STATUS);
+}
+
+static inline void dmadesc_set_addr(struct bcmgenet_priv *priv,
+                                   void __iomem *d,
+                                   dma_addr_t addr)
+{
+       __raw_writel(lower_32_bits(addr), d + DMA_DESC_ADDRESS_LO);
+
+       /* Register writes to GISB bus can take couple hundred nanoseconds
+        * and are done for each packet, save these expensive writes unless
+        * the platform is explicitely configured for 64-bits/LPAE.
+        */
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       if (priv->hw_params->flags & GENET_HAS_40BITS)
+               __raw_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI);
+#endif
+}
+
+/* Combined address + length/status setter */
+static inline void dmadesc_set(struct bcmgenet_priv *priv,
+                               void __iomem *d, dma_addr_t addr, u32 val)
+{
+       dmadesc_set_length_status(priv, d, val);
+       dmadesc_set_addr(priv, d, addr);
+}
+
+static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv,
+                                         void __iomem *d)
+{
+       dma_addr_t addr;
+
+       addr = __raw_readl(d + DMA_DESC_ADDRESS_LO);
+
+       /* Register writes to GISB bus can take couple hundred nanoseconds
+        * and are done for each packet, save these expensive writes unless
+        * the platform is explicitely configured for 64-bits/LPAE.
+        */
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       if (priv->hw_params->flags & GENET_HAS_40BITS)
+               addr |= (u64)__raw_readl(d + DMA_DESC_ADDRESS_HI) << 32;
+#endif
+       return addr;
+}
+
+#define GENET_VER_FMT  "%1d.%1d EPHY: 0x%04x"
+
+#define GENET_MSG_DEFAULT      (NETIF_MSG_DRV | NETIF_MSG_PROBE | \
+                               NETIF_MSG_LINK)
+
+static inline u32 bcmgenet_rbuf_ctrl_get(struct bcmgenet_priv *priv)
+{
+       if (GENET_IS_V1(priv))
+               return bcmgenet_rbuf_readl(priv, RBUF_FLUSH_CTRL_V1);
+       else
+               return bcmgenet_sys_readl(priv, SYS_RBUF_FLUSH_CTRL);
+}
+
+static inline void bcmgenet_rbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val)
+{
+       if (GENET_IS_V1(priv))
+               bcmgenet_rbuf_writel(priv, val, RBUF_FLUSH_CTRL_V1);
+       else
+               bcmgenet_sys_writel(priv, val, SYS_RBUF_FLUSH_CTRL);
+}
+
+/* These macros are defined to deal with register map change
+ * between GENET1.1 and GENET2. Only those currently being used
+ * by driver are defined.
+ */
+static inline u32 bcmgenet_tbuf_ctrl_get(struct bcmgenet_priv *priv)
+{
+       if (GENET_IS_V1(priv))
+               return bcmgenet_rbuf_readl(priv, TBUF_CTRL_V1);
+       else
+               return __raw_readl(priv->base +
+                               priv->hw_params->tbuf_offset + TBUF_CTRL);
+}
+
+static inline void bcmgenet_tbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val)
+{
+       if (GENET_IS_V1(priv))
+               bcmgenet_rbuf_writel(priv, val, TBUF_CTRL_V1);
+       else
+               __raw_writel(val, priv->base +
+                               priv->hw_params->tbuf_offset + TBUF_CTRL);
+}
+
+static inline u32 bcmgenet_bp_mc_get(struct bcmgenet_priv *priv)
+{
+       if (GENET_IS_V1(priv))
+               return bcmgenet_rbuf_readl(priv, TBUF_BP_MC_V1);
+       else
+               return __raw_readl(priv->base +
+                               priv->hw_params->tbuf_offset + TBUF_BP_MC);
+}
+
+static inline void bcmgenet_bp_mc_set(struct bcmgenet_priv *priv, u32 val)
+{
+       if (GENET_IS_V1(priv))
+               bcmgenet_rbuf_writel(priv, val, TBUF_BP_MC_V1);
+       else
+               __raw_writel(val, priv->base +
+                               priv->hw_params->tbuf_offset + TBUF_BP_MC);
+}
+
+/* RX/TX DMA register accessors */
+enum dma_reg {
+       DMA_RING_CFG = 0,
+       DMA_CTRL,
+       DMA_STATUS,
+       DMA_SCB_BURST_SIZE,
+       DMA_ARB_CTRL,
+       DMA_PRIORITY,
+       DMA_RING_PRIORITY,
+};
+
+static const u8 bcmgenet_dma_regs_v3plus[] = {
+       [DMA_RING_CFG]          = 0x00,
+       [DMA_CTRL]              = 0x04,
+       [DMA_STATUS]            = 0x08,
+       [DMA_SCB_BURST_SIZE]    = 0x0C,
+       [DMA_ARB_CTRL]          = 0x2C,
+       [DMA_PRIORITY]          = 0x30,
+       [DMA_RING_PRIORITY]     = 0x38,
+};
+
+static const u8 bcmgenet_dma_regs_v2[] = {
+       [DMA_RING_CFG]          = 0x00,
+       [DMA_CTRL]              = 0x04,
+       [DMA_STATUS]            = 0x08,
+       [DMA_SCB_BURST_SIZE]    = 0x0C,
+       [DMA_ARB_CTRL]          = 0x30,
+       [DMA_PRIORITY]          = 0x34,
+       [DMA_RING_PRIORITY]     = 0x3C,
+};
+
+static const u8 bcmgenet_dma_regs_v1[] = {
+       [DMA_CTRL]              = 0x00,
+       [DMA_STATUS]            = 0x04,
+       [DMA_SCB_BURST_SIZE]    = 0x0C,
+       [DMA_ARB_CTRL]          = 0x30,
+       [DMA_PRIORITY]          = 0x34,
+       [DMA_RING_PRIORITY]     = 0x3C,
+};
+
+/* Set at runtime once bcmgenet version is known */
+static const u8 *bcmgenet_dma_regs;
+
+static inline struct bcmgenet_priv *dev_to_priv(struct device *dev)
+{
+       return netdev_priv(dev_get_drvdata(dev));
+}
+
+static inline u32 bcmgenet_tdma_readl(struct bcmgenet_priv *priv,
+                                       enum dma_reg r)
+{
+       return __raw_readl(priv->base + GENET_TDMA_REG_OFF +
+                       DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+static inline void bcmgenet_tdma_writel(struct bcmgenet_priv *priv,
+                                       u32 val, enum dma_reg r)
+{
+       __raw_writel(val, priv->base + GENET_TDMA_REG_OFF +
+                       DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+static inline u32 bcmgenet_rdma_readl(struct bcmgenet_priv *priv,
+                                       enum dma_reg r)
+{
+       return __raw_readl(priv->base + GENET_RDMA_REG_OFF +
+                       DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+static inline void bcmgenet_rdma_writel(struct bcmgenet_priv *priv,
+                                       u32 val, enum dma_reg r)
+{
+       __raw_writel(val, priv->base + GENET_RDMA_REG_OFF +
+                       DMA_RINGS_SIZE + bcmgenet_dma_regs[r]);
+}
+
+/* RDMA/TDMA ring registers and accessors
+ * we merge the common fields and just prefix with T/D the registers
+ * having different meaning depending on the direction
+ */
+enum dma_ring_reg {
+       TDMA_READ_PTR = 0,
+       RDMA_WRITE_PTR = TDMA_READ_PTR,
+       TDMA_READ_PTR_HI,
+       RDMA_WRITE_PTR_HI = TDMA_READ_PTR_HI,
+       TDMA_CONS_INDEX,
+       RDMA_PROD_INDEX = TDMA_CONS_INDEX,
+       TDMA_PROD_INDEX,
+       RDMA_CONS_INDEX = TDMA_PROD_INDEX,
+       DMA_RING_BUF_SIZE,
+       DMA_START_ADDR,
+       DMA_START_ADDR_HI,
+       DMA_END_ADDR,
+       DMA_END_ADDR_HI,
+       DMA_MBUF_DONE_THRESH,
+       TDMA_FLOW_PERIOD,
+       RDMA_XON_XOFF_THRESH = TDMA_FLOW_PERIOD,
+       TDMA_WRITE_PTR,
+       RDMA_READ_PTR = TDMA_WRITE_PTR,
+       TDMA_WRITE_PTR_HI,
+       RDMA_READ_PTR_HI = TDMA_WRITE_PTR_HI
+};
+
+/* GENET v4 supports 40-bits pointer addressing
+ * for obvious reasons the LO and HI word parts
+ * are contiguous, but this offsets the other
+ * registers.
+ */
+static const u8 genet_dma_ring_regs_v4[] = {
+       [TDMA_READ_PTR]                 = 0x00,
+       [TDMA_READ_PTR_HI]              = 0x04,
+       [TDMA_CONS_INDEX]               = 0x08,
+       [TDMA_PROD_INDEX]               = 0x0C,
+       [DMA_RING_BUF_SIZE]             = 0x10,
+       [DMA_START_ADDR]                = 0x14,
+       [DMA_START_ADDR_HI]             = 0x18,
+       [DMA_END_ADDR]                  = 0x1C,
+       [DMA_END_ADDR_HI]               = 0x20,
+       [DMA_MBUF_DONE_THRESH]          = 0x24,
+       [TDMA_FLOW_PERIOD]              = 0x28,
+       [TDMA_WRITE_PTR]                = 0x2C,
+       [TDMA_WRITE_PTR_HI]             = 0x30,
+};
+
+static const u8 genet_dma_ring_regs_v123[] = {
+       [TDMA_READ_PTR]                 = 0x00,
+       [TDMA_CONS_INDEX]               = 0x04,
+       [TDMA_PROD_INDEX]               = 0x08,
+       [DMA_RING_BUF_SIZE]             = 0x0C,
+       [DMA_START_ADDR]                = 0x10,
+       [DMA_END_ADDR]                  = 0x14,
+       [DMA_MBUF_DONE_THRESH]          = 0x18,
+       [TDMA_FLOW_PERIOD]              = 0x1C,
+       [TDMA_WRITE_PTR]                = 0x20,
+};
+
+/* Set at runtime once GENET version is known */
+static const u8 *genet_dma_ring_regs;
+
+static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv,
+                                               unsigned int ring,
+                                               enum dma_ring_reg r)
+{
+       return __raw_readl(priv->base + GENET_TDMA_REG_OFF +
+                       (DMA_RING_SIZE * ring) +
+                       genet_dma_ring_regs[r]);
+}
+
+static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv,
+                                               unsigned int ring,
+                                               u32 val,
+                                               enum dma_ring_reg r)
+{
+       __raw_writel(val, priv->base + GENET_TDMA_REG_OFF +
+                       (DMA_RING_SIZE * ring) +
+                       genet_dma_ring_regs[r]);
+}
+
+static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv,
+                                               unsigned int ring,
+                                               enum dma_ring_reg r)
+{
+       return __raw_readl(priv->base + GENET_RDMA_REG_OFF +
+                       (DMA_RING_SIZE * ring) +
+                       genet_dma_ring_regs[r]);
+}
+
+static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv,
+                                               unsigned int ring,
+                                               u32 val,
+                                               enum dma_ring_reg r)
+{
+       __raw_writel(val, priv->base + GENET_RDMA_REG_OFF +
+                       (DMA_RING_SIZE * ring) +
+                       genet_dma_ring_regs[r]);
+}
+
+static int bcmgenet_get_settings(struct net_device *dev,
+               struct ethtool_cmd *cmd)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int bcmgenet_set_settings(struct net_device *dev,
+               struct ethtool_cmd *cmd)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       if (!priv->phydev)
+               return -ENODEV;
+
+       return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int bcmgenet_set_rx_csum(struct net_device *dev,
+                               netdev_features_t wanted)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       u32 rbuf_chk_ctrl;
+       bool rx_csum_en;
+
+       rx_csum_en = !!(wanted & NETIF_F_RXCSUM);
+
+       rbuf_chk_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL);
+
+       /* enable rx checksumming */
+       if (rx_csum_en)
+               rbuf_chk_ctrl |= RBUF_RXCHK_EN;
+       else
+               rbuf_chk_ctrl &= ~RBUF_RXCHK_EN;
+       priv->desc_rxchk_en = rx_csum_en;
+
+       /* If UniMAC forwards CRC, we need to skip over it to get
+        * a valid CHK bit to be set in the per-packet status word
+       */
+       if (rx_csum_en && priv->crc_fwd_en)
+               rbuf_chk_ctrl |= RBUF_SKIP_FCS;
+       else
+               rbuf_chk_ctrl &= ~RBUF_SKIP_FCS;
+
+       bcmgenet_rbuf_writel(priv, rbuf_chk_ctrl, RBUF_CHK_CTRL);
+
+       return 0;
+}
+
+static int bcmgenet_set_tx_csum(struct net_device *dev,
+                               netdev_features_t wanted)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       bool desc_64b_en;
+       u32 tbuf_ctrl, rbuf_ctrl;
+
+       tbuf_ctrl = bcmgenet_tbuf_ctrl_get(priv);
+       rbuf_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
+
+       desc_64b_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM));
+
+       /* enable 64 bytes descriptor in both directions (RBUF and TBUF) */
+       if (desc_64b_en) {
+               tbuf_ctrl |= RBUF_64B_EN;
+               rbuf_ctrl |= RBUF_64B_EN;
+       } else {
+               tbuf_ctrl &= ~RBUF_64B_EN;
+               rbuf_ctrl &= ~RBUF_64B_EN;
+       }
+       priv->desc_64b_en = desc_64b_en;
+
+       bcmgenet_tbuf_ctrl_set(priv, tbuf_ctrl);
+       bcmgenet_rbuf_writel(priv, rbuf_ctrl, RBUF_CTRL);
+
+       return 0;
+}
+
+static int bcmgenet_set_features(struct net_device *dev,
+               netdev_features_t features)
+{
+       netdev_features_t changed = features ^ dev->features;
+       netdev_features_t wanted = dev->wanted_features;
+       int ret = 0;
+
+       if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))
+               ret = bcmgenet_set_tx_csum(dev, wanted);
+       if (changed & (NETIF_F_RXCSUM))
+               ret = bcmgenet_set_rx_csum(dev, wanted);
+
+       return ret;
+}
+
+static u32 bcmgenet_get_msglevel(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       return priv->msg_enable;
+}
+
+static void bcmgenet_set_msglevel(struct net_device *dev, u32 level)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       priv->msg_enable = level;
+}
+
+/* standard ethtool support functions. */
+enum bcmgenet_stat_type {
+       BCMGENET_STAT_NETDEV = -1,
+       BCMGENET_STAT_MIB_RX,
+       BCMGENET_STAT_MIB_TX,
+       BCMGENET_STAT_RUNT,
+       BCMGENET_STAT_MISC,
+};
+
+struct bcmgenet_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int stat_sizeof;
+       int stat_offset;
+       enum bcmgenet_stat_type type;
+       /* reg offset from UMAC base for misc counters */
+       u16 reg_offset;
+};
+
+#define STAT_NETDEV(m) { \
+       .stat_string = __stringify(m), \
+       .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \
+       .stat_offset = offsetof(struct net_device_stats, m), \
+       .type = BCMGENET_STAT_NETDEV, \
+}
+
+#define STAT_GENET_MIB(str, m, _type) { \
+       .stat_string = str, \
+       .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->m), \
+       .stat_offset = offsetof(struct bcmgenet_priv, m), \
+       .type = _type, \
+}
+
+#define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX)
+#define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX)
+#define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT)
+
+#define STAT_GENET_MISC(str, m, offset) { \
+       .stat_string = str, \
+       .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->m), \
+       .stat_offset = offsetof(struct bcmgenet_priv, m), \
+       .type = BCMGENET_STAT_MISC, \
+       .reg_offset = offset, \
+}
+
+
+/* There is a 0xC gap between the end of RX and beginning of TX stats and then
+ * between the end of TX stats and the beginning of the RX RUNT
+ */
+#define BCMGENET_STAT_OFFSET   0xc
+
+/* Hardware counters must be kept in sync because the order/offset
+ * is important here (order in structure declaration = order in hardware)
+ */
+static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = {
+       /* general stats */
+       STAT_NETDEV(rx_packets),
+       STAT_NETDEV(tx_packets),
+       STAT_NETDEV(rx_bytes),
+       STAT_NETDEV(tx_bytes),
+       STAT_NETDEV(rx_errors),
+       STAT_NETDEV(tx_errors),
+       STAT_NETDEV(rx_dropped),
+       STAT_NETDEV(tx_dropped),
+       STAT_NETDEV(multicast),
+       /* UniMAC RSV counters */
+       STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64),
+       STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127),
+       STAT_GENET_MIB_RX("rx_128_255_oct", mib.rx.pkt_cnt.cnt_255),
+       STAT_GENET_MIB_RX("rx_256_511_oct", mib.rx.pkt_cnt.cnt_511),
+       STAT_GENET_MIB_RX("rx_512_1023_oct", mib.rx.pkt_cnt.cnt_1023),
+       STAT_GENET_MIB_RX("rx_1024_1518_oct", mib.rx.pkt_cnt.cnt_1518),
+       STAT_GENET_MIB_RX("rx_vlan_1519_1522_oct", mib.rx.pkt_cnt.cnt_mgv),
+       STAT_GENET_MIB_RX("rx_1522_2047_oct", mib.rx.pkt_cnt.cnt_2047),
+       STAT_GENET_MIB_RX("rx_2048_4095_oct", mib.rx.pkt_cnt.cnt_4095),
+       STAT_GENET_MIB_RX("rx_4096_9216_oct", mib.rx.pkt_cnt.cnt_9216),
+       STAT_GENET_MIB_RX("rx_pkts", mib.rx.pkt),
+       STAT_GENET_MIB_RX("rx_bytes", mib.rx.bytes),
+       STAT_GENET_MIB_RX("rx_multicast", mib.rx.mca),
+       STAT_GENET_MIB_RX("rx_broadcast", mib.rx.bca),
+       STAT_GENET_MIB_RX("rx_fcs", mib.rx.fcs),
+       STAT_GENET_MIB_RX("rx_control", mib.rx.cf),
+       STAT_GENET_MIB_RX("rx_pause", mib.rx.pf),
+       STAT_GENET_MIB_RX("rx_unknown", mib.rx.uo),
+       STAT_GENET_MIB_RX("rx_align", mib.rx.aln),
+       STAT_GENET_MIB_RX("rx_outrange", mib.rx.flr),
+       STAT_GENET_MIB_RX("rx_code", mib.rx.cde),
+       STAT_GENET_MIB_RX("rx_carrier", mib.rx.fcr),
+       STAT_GENET_MIB_RX("rx_oversize", mib.rx.ovr),
+       STAT_GENET_MIB_RX("rx_jabber", mib.rx.jbr),
+       STAT_GENET_MIB_RX("rx_mtu_err", mib.rx.mtue),
+       STAT_GENET_MIB_RX("rx_good_pkts", mib.rx.pok),
+       STAT_GENET_MIB_RX("rx_unicast", mib.rx.uc),
+       STAT_GENET_MIB_RX("rx_ppp", mib.rx.ppp),
+       STAT_GENET_MIB_RX("rx_crc", mib.rx.rcrc),
+       /* UniMAC TSV counters */
+       STAT_GENET_MIB_TX("tx_64_octets", mib.tx.pkt_cnt.cnt_64),
+       STAT_GENET_MIB_TX("tx_65_127_oct", mib.tx.pkt_cnt.cnt_127),
+       STAT_GENET_MIB_TX("tx_128_255_oct", mib.tx.pkt_cnt.cnt_255),
+       STAT_GENET_MIB_TX("tx_256_511_oct", mib.tx.pkt_cnt.cnt_511),
+       STAT_GENET_MIB_TX("tx_512_1023_oct", mib.tx.pkt_cnt.cnt_1023),
+       STAT_GENET_MIB_TX("tx_1024_1518_oct", mib.tx.pkt_cnt.cnt_1518),
+       STAT_GENET_MIB_TX("tx_vlan_1519_1522_oct", mib.tx.pkt_cnt.cnt_mgv),
+       STAT_GENET_MIB_TX("tx_1522_2047_oct", mib.tx.pkt_cnt.cnt_2047),
+       STAT_GENET_MIB_TX("tx_2048_4095_oct", mib.tx.pkt_cnt.cnt_4095),
+       STAT_GENET_MIB_TX("tx_4096_9216_oct", mib.tx.pkt_cnt.cnt_9216),
+       STAT_GENET_MIB_TX("tx_pkts", mib.tx.pkts),
+       STAT_GENET_MIB_TX("tx_multicast", mib.tx.mca),
+       STAT_GENET_MIB_TX("tx_broadcast", mib.tx.bca),
+       STAT_GENET_MIB_TX("tx_pause", mib.tx.pf),
+       STAT_GENET_MIB_TX("tx_control", mib.tx.cf),
+       STAT_GENET_MIB_TX("tx_fcs_err", mib.tx.fcs),
+       STAT_GENET_MIB_TX("tx_oversize", mib.tx.ovr),
+       STAT_GENET_MIB_TX("tx_defer", mib.tx.drf),
+       STAT_GENET_MIB_TX("tx_excess_defer", mib.tx.edf),
+       STAT_GENET_MIB_TX("tx_single_col", mib.tx.scl),
+       STAT_GENET_MIB_TX("tx_multi_col", mib.tx.mcl),
+       STAT_GENET_MIB_TX("tx_late_col", mib.tx.lcl),
+       STAT_GENET_MIB_TX("tx_excess_col", mib.tx.ecl),
+       STAT_GENET_MIB_TX("tx_frags", mib.tx.frg),
+       STAT_GENET_MIB_TX("tx_total_col", mib.tx.ncl),
+       STAT_GENET_MIB_TX("tx_jabber", mib.tx.jbr),
+       STAT_GENET_MIB_TX("tx_bytes", mib.tx.bytes),
+       STAT_GENET_MIB_TX("tx_good_pkts", mib.tx.pok),
+       STAT_GENET_MIB_TX("tx_unicast", mib.tx.uc),
+       /* UniMAC RUNT counters */
+       STAT_GENET_RUNT("rx_runt_pkts", mib.rx_runt_cnt),
+       STAT_GENET_RUNT("rx_runt_valid_fcs", mib.rx_runt_fcs),
+       STAT_GENET_RUNT("rx_runt_inval_fcs_align", mib.rx_runt_fcs_align),
+       STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes),
+       /* Misc UniMAC counters */
+       STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt,
+                       UMAC_RBUF_OVFL_CNT),
+       STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT),
+       STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT),
+};
+
+#define BCMGENET_STATS_LEN     ARRAY_SIZE(bcmgenet_gstrings_stats)
+
+static void bcmgenet_get_drvinfo(struct net_device *dev,
+               struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, "bcmgenet", sizeof(info->driver));
+       strlcpy(info->version, "v2.0", sizeof(info->version));
+       info->n_stats = BCMGENET_STATS_LEN;
+
+}
+
+static int bcmgenet_get_sset_count(struct net_device *dev, int string_set)
+{
+       switch (string_set) {
+       case ETH_SS_STATS:
+               return BCMGENET_STATS_LEN;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void bcmgenet_get_strings(struct net_device *dev,
+                               u32 stringset, u8 *data)
+{
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < BCMGENET_STATS_LEN; i++) {
+                       memcpy(data + i * ETH_GSTRING_LEN,
+                               bcmgenet_gstrings_stats[i].stat_string,
+                               ETH_GSTRING_LEN);
+               }
+               break;
+       }
+}
+
+static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv)
+{
+       int i, j = 0;
+
+       for (i = 0; i < BCMGENET_STATS_LEN; i++) {
+               const struct bcmgenet_stats *s;
+               u8 offset = 0;
+               u32 val = 0;
+               char *p;
+
+               s = &bcmgenet_gstrings_stats[i];
+               switch (s->type) {
+               case BCMGENET_STAT_NETDEV:
+                       continue;
+               case BCMGENET_STAT_MIB_RX:
+               case BCMGENET_STAT_MIB_TX:
+               case BCMGENET_STAT_RUNT:
+                       if (s->type != BCMGENET_STAT_MIB_RX)
+                               offset = BCMGENET_STAT_OFFSET;
+                       val = bcmgenet_umac_readl(priv, UMAC_MIB_START +
+                                                               j + offset);
+                       break;
+               case BCMGENET_STAT_MISC:
+                       val = bcmgenet_umac_readl(priv, s->reg_offset);
+                       /* clear if overflowed */
+                       if (val == ~0)
+                               bcmgenet_umac_writel(priv, 0, s->reg_offset);
+                       break;
+               }
+
+               j += s->stat_sizeof;
+               p = (char *)priv + s->stat_offset;
+               *(u32 *)p = val;
+       }
+}
+
+static void bcmgenet_get_ethtool_stats(struct net_device *dev,
+                                       struct ethtool_stats *stats,
+                                       u64 *data)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       int i;
+
+       if (netif_running(dev))
+               bcmgenet_update_mib_counters(priv);
+
+       for (i = 0; i < BCMGENET_STATS_LEN; i++) {
+               const struct bcmgenet_stats *s;
+               char *p;
+
+               s = &bcmgenet_gstrings_stats[i];
+               if (s->type == BCMGENET_STAT_NETDEV)
+                       p = (char *)&dev->stats;
+               else
+                       p = (char *)priv;
+               p += s->stat_offset;
+               data[i] = *(u32 *)p;
+       }
+}
+
+/* standard ethtool support functions. */
+static struct ethtool_ops bcmgenet_ethtool_ops = {
+       .get_strings            = bcmgenet_get_strings,
+       .get_sset_count         = bcmgenet_get_sset_count,
+       .get_ethtool_stats      = bcmgenet_get_ethtool_stats,
+       .get_settings           = bcmgenet_get_settings,
+       .set_settings           = bcmgenet_set_settings,
+       .get_drvinfo            = bcmgenet_get_drvinfo,
+       .get_link               = ethtool_op_get_link,
+       .get_msglevel           = bcmgenet_get_msglevel,
+       .set_msglevel           = bcmgenet_set_msglevel,
+};
+
+/* Power down the unimac, based on mode. */
+static void bcmgenet_power_down(struct bcmgenet_priv *priv,
+                               enum bcmgenet_power_mode mode)
+{
+       u32 reg;
+
+       switch (mode) {
+       case GENET_POWER_CABLE_SENSE:
+               phy_detach(priv->phydev);
+               break;
+
+       case GENET_POWER_PASSIVE:
+               /* Power down LED */
+               bcmgenet_mii_reset(priv->dev);
+               if (priv->hw_params->flags & GENET_HAS_EXT) {
+                       reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+                       reg |= (EXT_PWR_DOWN_PHY |
+                               EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS);
+                       bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void bcmgenet_power_up(struct bcmgenet_priv *priv,
+                               enum bcmgenet_power_mode mode)
+{
+       u32 reg;
+
+       if (!(priv->hw_params->flags & GENET_HAS_EXT))
+               return;
+
+       reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+
+       switch (mode) {
+       case GENET_POWER_PASSIVE:
+               reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_PHY |
+                               EXT_PWR_DOWN_BIAS);
+               /* fallthrough */
+       case GENET_POWER_CABLE_SENSE:
+               /* enable APD */
+               reg |= EXT_PWR_DN_EN_LD;
+               break;
+       default:
+               break;
+       }
+
+       bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+       bcmgenet_mii_reset(priv->dev);
+}
+
+/* ioctl handle special commands that are not present in ethtool. */
+static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       int val = 0;
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               if (!priv->phydev)
+                       val = -ENODEV;
+               else
+                       val = phy_mii_ioctl(priv->phydev, rq, cmd);
+               break;
+
+       default:
+               val = -EINVAL;
+               break;
+       }
+
+       return val;
+}
+
+static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv,
+                                        struct bcmgenet_tx_ring *ring)
+{
+       struct enet_cb *tx_cb_ptr;
+
+       tx_cb_ptr = ring->cbs;
+       tx_cb_ptr += ring->write_ptr - ring->cb_ptr;
+       tx_cb_ptr->bd_addr = priv->tx_bds + ring->write_ptr * DMA_DESC_SIZE;
+       /* Advancing local write pointer */
+       if (ring->write_ptr == ring->end_ptr)
+               ring->write_ptr = ring->cb_ptr;
+       else
+               ring->write_ptr++;
+
+       return tx_cb_ptr;
+}
+
+/* Simple helper to free a control block's resources */
+static void bcmgenet_free_cb(struct enet_cb *cb)
+{
+       dev_kfree_skb_any(cb->skb);
+       cb->skb = NULL;
+       dma_unmap_addr_set(cb, dma_addr, 0);
+}
+
+static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_priv *priv,
+                                                 struct bcmgenet_tx_ring *ring)
+{
+       bcmgenet_intrl2_0_writel(priv,
+                       UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
+                       INTRL2_CPU_MASK_SET);
+}
+
+static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_priv *priv,
+                                                struct bcmgenet_tx_ring *ring)
+{
+       bcmgenet_intrl2_0_writel(priv,
+                       UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE,
+                       INTRL2_CPU_MASK_CLEAR);
+}
+
+static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv,
+                                               struct bcmgenet_tx_ring *ring)
+{
+       bcmgenet_intrl2_1_writel(priv,
+                       (1 << ring->index), INTRL2_CPU_MASK_CLEAR);
+       priv->int1_mask &= ~(1 << ring->index);
+}
+
+static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv,
+                                               struct bcmgenet_tx_ring *ring)
+{
+       bcmgenet_intrl2_1_writel(priv,
+                       (1 << ring->index), INTRL2_CPU_MASK_SET);
+       priv->int1_mask |= (1 << ring->index);
+}
+
+/* Unlocked version of the reclaim routine */
+static void __bcmgenet_tx_reclaim(struct net_device *dev,
+                               struct bcmgenet_tx_ring *ring)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       int last_tx_cn, last_c_index, num_tx_bds;
+       struct enet_cb *tx_cb_ptr;
+       struct netdev_queue *txq;
+       unsigned int c_index;
+
+       /* Compute how many buffers are transmited since last xmit call */
+       c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX);
+       txq = netdev_get_tx_queue(dev, ring->queue);
+
+       last_c_index = ring->c_index;
+       num_tx_bds = ring->size;
+
+       c_index &= (num_tx_bds - 1);
+
+       if (c_index >= last_c_index)
+               last_tx_cn = c_index - last_c_index;
+       else
+               last_tx_cn = num_tx_bds - last_c_index + c_index;
+
+       netif_dbg(priv, tx_done, dev,
+                       "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n",
+                       __func__, ring->index,
+                       c_index, last_tx_cn, last_c_index);
+
+       /* Reclaim transmitted buffers */
+       while (last_tx_cn-- > 0) {
+               tx_cb_ptr = ring->cbs + last_c_index;
+               if (tx_cb_ptr->skb) {
+                       dev->stats.tx_bytes += tx_cb_ptr->skb->len;
+                       dma_unmap_single(&dev->dev,
+                                       dma_unmap_addr(tx_cb_ptr, dma_addr),
+                                       tx_cb_ptr->skb->len,
+                                       DMA_TO_DEVICE);
+                       bcmgenet_free_cb(tx_cb_ptr);
+               } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) {
+                       dev->stats.tx_bytes +=
+                               dma_unmap_len(tx_cb_ptr, dma_len);
+                       dma_unmap_page(&dev->dev,
+                                       dma_unmap_addr(tx_cb_ptr, dma_addr),
+                                       dma_unmap_len(tx_cb_ptr, dma_len),
+                                       DMA_TO_DEVICE);
+                       dma_unmap_addr_set(tx_cb_ptr, dma_addr, 0);
+               }
+               dev->stats.tx_packets++;
+               ring->free_bds += 1;
+
+               last_c_index++;
+               last_c_index &= (num_tx_bds - 1);
+       }
+
+       if (ring->free_bds > (MAX_SKB_FRAGS + 1))
+               ring->int_disable(priv, ring);
+
+       if (netif_tx_queue_stopped(txq))
+               netif_tx_wake_queue(txq);
+
+       ring->c_index = c_index;
+}
+
+static void bcmgenet_tx_reclaim(struct net_device *dev,
+               struct bcmgenet_tx_ring *ring)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&ring->lock, flags);
+       __bcmgenet_tx_reclaim(dev, ring);
+       spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void bcmgenet_tx_reclaim_all(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       int i;
+
+       if (netif_is_multiqueue(dev)) {
+               for (i = 0; i < priv->hw_params->tx_queues; i++)
+                       bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]);
+       }
+
+       bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]);
+}
+
+/* Transmits a single SKB (either head of a fragment or a single SKB)
+ * caller must hold priv->lock
+ */
+static int bcmgenet_xmit_single(struct net_device *dev,
+                               struct sk_buff *skb,
+                               u16 dma_desc_flags,
+                               struct bcmgenet_tx_ring *ring)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device *kdev = &priv->pdev->dev;
+       struct enet_cb *tx_cb_ptr;
+       unsigned int skb_len;
+       dma_addr_t mapping;
+       u32 length_status;
+       int ret;
+
+       tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
+
+       if (unlikely(!tx_cb_ptr))
+               BUG();
+
+       tx_cb_ptr->skb = skb;
+
+       skb_len = skb_headlen(skb) < ETH_ZLEN ? ETH_ZLEN : skb_headlen(skb);
+
+       mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
+       ret = dma_mapping_error(kdev, mapping);
+       if (ret) {
+               netif_err(priv, tx_err, dev, "Tx DMA map failed\n");
+               dev_kfree_skb(skb);
+               return ret;
+       }
+
+       dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
+       dma_unmap_len_set(tx_cb_ptr, dma_len, skb->len);
+       length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
+                       (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) |
+                       DMA_TX_APPEND_CRC;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               length_status |= DMA_TX_DO_CSUM;
+
+       dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, length_status);
+
+       /* Decrement total BD count and advance our write pointer */
+       ring->free_bds -= 1;
+       ring->prod_index += 1;
+       ring->prod_index &= DMA_P_INDEX_MASK;
+
+       return 0;
+}
+
+/* Transmit a SKB fragement */
+static int bcmgenet_xmit_frag(struct net_device *dev,
+                               skb_frag_t *frag,
+                               u16 dma_desc_flags,
+                               struct bcmgenet_tx_ring *ring)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct device *kdev = &priv->pdev->dev;
+       struct enet_cb *tx_cb_ptr;
+       dma_addr_t mapping;
+       int ret;
+
+       tx_cb_ptr = bcmgenet_get_txcb(priv, ring);
+
+       if (unlikely(!tx_cb_ptr))
+               BUG();
+       tx_cb_ptr->skb = NULL;
+
+       mapping = skb_frag_dma_map(kdev, frag, 0,
+               skb_frag_size(frag), DMA_TO_DEVICE);
+       ret = dma_mapping_error(kdev, mapping);
+       if (ret) {
+               netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n",
+                               __func__);
+               return ret;
+       }
+
+       dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping);
+       dma_unmap_len_set(tx_cb_ptr, dma_len, frag->size);
+
+       dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping,
+                       (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags |
+                       (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT));
+
+
+       ring->free_bds -= 1;
+       ring->prod_index += 1;
+       ring->prod_index &= DMA_P_INDEX_MASK;
+
+       return 0;
+}
+
+/* Reallocate the SKB to put enough headroom in front of it and insert
+ * the transmit checksum offsets in the descriptors
+ */
+static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb)
+{
+       struct status_64 *status = NULL;
+       struct sk_buff *new_skb;
+       u16 offset;
+       u8 ip_proto;
+       u16 ip_ver;
+       u32 tx_csum_info;
+
+       if (unlikely(skb_headroom(skb) < sizeof(*status))) {
+               /* If 64 byte status block enabled, must make sure skb has
+                * enough headroom for us to insert 64B status block.
+                */
+               new_skb = skb_realloc_headroom(skb, sizeof(*status));
+               dev_kfree_skb(skb);
+               if (!new_skb) {
+                       dev->stats.tx_errors++;
+                       dev->stats.tx_dropped++;
+                       return -ENOMEM;
+               }
+               skb = new_skb;
+       }
+
+       skb_push(skb, sizeof(*status));
+       status = (struct status_64 *)skb->data;
+
+       if (skb->ip_summed  == CHECKSUM_PARTIAL) {
+               ip_ver = htons(skb->protocol);
+               switch (ip_ver) {
+               case ETH_P_IP:
+                       ip_proto = ip_hdr(skb)->protocol;
+                       break;
+               case ETH_P_IPV6:
+                       ip_proto = ipv6_hdr(skb)->nexthdr;
+                       break;
+               default:
+                       return 0;
+               }
+
+               offset = skb_checksum_start_offset(skb) - sizeof(*status);
+               tx_csum_info = (offset << STATUS_TX_CSUM_START_SHIFT) |
+                               (offset + skb->csum_offset);
+
+               /* Set the length valid bit for TCP and UDP and just set
+                * the special UDP flag for IPv4, else just set to 0.
+                */
+               if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) {
+                       tx_csum_info |= STATUS_TX_CSUM_LV;
+                       if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP)
+                               tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP;
+               } else
+                       tx_csum_info = 0;
+
+               status->tx_csum_info = tx_csum_info;
+       }
+
+       return 0;
+}
+
+static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct bcmgenet_tx_ring *ring = NULL;
+       struct netdev_queue *txq;
+       unsigned long flags = 0;
+       int nr_frags, index;
+       u16 dma_desc_flags;
+       int ret;
+       int i;
+
+       index = skb_get_queue_mapping(skb);
+       /* Mapping strategy:
+        * queue_mapping = 0, unclassified, packet xmited through ring16
+        * queue_mapping = 1, goes to ring 0. (highest priority queue
+        * queue_mapping = 2, goes to ring 1.
+        * queue_mapping = 3, goes to ring 2.
+        * queue_mapping = 4, goes to ring 3.
+        */
+       if (index == 0)
+               index = DESC_INDEX;
+       else
+               index -= 1;
+
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       ring = &priv->tx_rings[index];
+       txq = netdev_get_tx_queue(dev, ring->queue);
+
+       spin_lock_irqsave(&ring->lock, flags);
+       if (ring->free_bds <= nr_frags + 1) {
+               netif_tx_stop_queue(txq);
+               netdev_err(dev, "%s: tx ring %d full when queue %d awake\n",
+                               __func__, index, ring->queue);
+               ret = NETDEV_TX_BUSY;
+               goto out;
+       }
+
+       /* set the SKB transmit checksum */
+       if (priv->desc_64b_en) {
+               ret = bcmgenet_put_tx_csum(dev, skb);
+               if (ret) {
+                       ret = NETDEV_TX_OK;
+                       goto out;
+               }
+       }
+
+       dma_desc_flags = DMA_SOP;
+       if (nr_frags == 0)
+               dma_desc_flags |= DMA_EOP;
+
+       /* Transmit single SKB or head of fragment list */
+       ret = bcmgenet_xmit_single(dev, skb, dma_desc_flags, ring);
+       if (ret) {
+               ret = NETDEV_TX_OK;
+               goto out;
+       }
+
+       /* xmit fragment */
+       for (i = 0; i < nr_frags; i++) {
+               ret = bcmgenet_xmit_frag(dev,
+                               &skb_shinfo(skb)->frags[i],
+                               (i == nr_frags - 1) ? DMA_EOP : 0, ring);
+               if (ret) {
+                       ret = NETDEV_TX_OK;
+                       goto out;
+               }
+       }
+
+       skb_tx_timestamp(skb);
+
+       /* we kept a software copy of how much we should advance the TDMA
+        * producer index, now write it down to the hardware
+        */
+       bcmgenet_tdma_ring_writel(priv, ring->index,
+                       ring->prod_index, TDMA_PROD_INDEX);
+
+       if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) {
+               netif_tx_stop_queue(txq);
+               ring->int_enable(priv, ring);
+       }
+
+out:
+       spin_unlock_irqrestore(&ring->lock, flags);
+
+       return ret;
+}
+
+
+static int bcmgenet_rx_refill(struct bcmgenet_priv *priv,
+                               struct enet_cb *cb)
+{
+       struct device *kdev = &priv->pdev->dev;
+       struct sk_buff *skb;
+       dma_addr_t mapping;
+       int ret;
+
+       skb = netdev_alloc_skb(priv->dev,
+                               priv->rx_buf_len + SKB_ALIGNMENT);
+       if (!skb)
+               return -ENOMEM;
+
+       /* a caller did not release this control block */
+       WARN_ON(cb->skb != NULL);
+       cb->skb = skb;
+       mapping = dma_map_single(kdev, skb->data,
+                       priv->rx_buf_len, DMA_FROM_DEVICE);
+       ret = dma_mapping_error(kdev, mapping);
+       if (ret) {
+               bcmgenet_free_cb(cb);
+               netif_err(priv, rx_err, priv->dev,
+                               "%s DMA map failed\n", __func__);
+               return ret;
+       }
+
+       dma_unmap_addr_set(cb, dma_addr, mapping);
+       /* assign packet, prepare descriptor, and advance pointer */
+
+       dmadesc_set_addr(priv, priv->rx_bd_assign_ptr, mapping);
+
+       /* turn on the newly assigned BD for DMA to use */
+       priv->rx_bd_assign_index++;
+       priv->rx_bd_assign_index &= (priv->num_rx_bds - 1);
+
+       priv->rx_bd_assign_ptr = priv->rx_bds +
+               (priv->rx_bd_assign_index * DMA_DESC_SIZE);
+
+       return 0;
+}
+
+/* bcmgenet_desc_rx - descriptor based rx process.
+ * this could be called from bottom half, or from NAPI polling method.
+ */
+static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv,
+                                    unsigned int budget)
+{
+       struct net_device *dev = priv->dev;
+       struct enet_cb *cb;
+       struct sk_buff *skb;
+       u32 dma_length_status;
+       unsigned long dma_flag;
+       int len, err;
+       unsigned int rxpktprocessed = 0, rxpkttoprocess;
+       unsigned int p_index;
+       unsigned int chksum_ok = 0;
+
+       p_index = bcmgenet_rdma_ring_readl(priv,
+                       DESC_INDEX, RDMA_PROD_INDEX);
+       p_index &= DMA_P_INDEX_MASK;
+
+       if (p_index < priv->rx_c_index)
+               rxpkttoprocess = (DMA_C_INDEX_MASK + 1) -
+                       priv->rx_c_index + p_index;
+       else
+               rxpkttoprocess = p_index - priv->rx_c_index;
+
+       netif_dbg(priv, rx_status, dev,
+               "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess);
+
+       while ((rxpktprocessed < rxpkttoprocess) &&
+                       (rxpktprocessed < budget)) {
+
+               /* Unmap the packet contents such that we can use the
+                * RSV from the 64 bytes descriptor when enabled and save
+                * a 32-bits register read
+                */
+               cb = &priv->rx_cbs[priv->rx_read_ptr];
+               skb = cb->skb;
+               dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr),
+                               priv->rx_buf_len, DMA_FROM_DEVICE);
+
+               if (!priv->desc_64b_en) {
+                       dma_length_status = dmadesc_get_length_status(priv,
+                                                       priv->rx_bds +
+                                                       (priv->rx_read_ptr *
+                                                        DMA_DESC_SIZE));
+               } else {
+                       struct status_64 *status;
+                       status = (struct status_64 *)skb->data;
+                       dma_length_status = status->length_status;
+               }
+
+               /* DMA flags and length are still valid no matter how
+                * we got the Receive Status Vector (64B RSB or register)
+                */
+               dma_flag = dma_length_status & 0xffff;
+               len = dma_length_status >> DMA_BUFLENGTH_SHIFT;
+
+               netif_dbg(priv, rx_status, dev,
+                       "%s: p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n",
+                       __func__, p_index, priv->rx_c_index, priv->rx_read_ptr,
+                       dma_length_status);
+
+               rxpktprocessed++;
+
+               priv->rx_read_ptr++;
+               priv->rx_read_ptr &= (priv->num_rx_bds - 1);
+
+               /* out of memory, just drop packets at the hardware level */
+               if (unlikely(!skb)) {
+                       dev->stats.rx_dropped++;
+                       dev->stats.rx_errors++;
+                       goto refill;
+               }
+
+               if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) {
+                       netif_err(priv, rx_status, dev,
+                                       "Droping fragmented packet!\n");
+                       dev->stats.rx_dropped++;
+                       dev->stats.rx_errors++;
+                       dev_kfree_skb_any(cb->skb);
+                       cb->skb = NULL;
+                       goto refill;
+               }
+               /* report errors */
+               if (unlikely(dma_flag & (DMA_RX_CRC_ERROR |
+                                               DMA_RX_OV |
+                                               DMA_RX_NO |
+                                               DMA_RX_LG |
+                                               DMA_RX_RXER))) {
+                       netif_err(priv, rx_status, dev, "dma_flag=0x%x\n",
+                                               (unsigned int)dma_flag);
+                       if (dma_flag & DMA_RX_CRC_ERROR)
+                               dev->stats.rx_crc_errors++;
+                       if (dma_flag & DMA_RX_OV)
+                               dev->stats.rx_over_errors++;
+                       if (dma_flag & DMA_RX_NO)
+                               dev->stats.rx_frame_errors++;
+                       if (dma_flag & DMA_RX_LG)
+                               dev->stats.rx_length_errors++;
+                       dev->stats.rx_dropped++;
+                       dev->stats.rx_errors++;
+
+                       /* discard the packet and advance consumer index.*/
+                       dev_kfree_skb_any(cb->skb);
+                       cb->skb = NULL;
+                       goto refill;
+               } /* error packet */
+
+               chksum_ok = (dma_flag & priv->dma_rx_chk_bit) &&
+                               priv->desc_rxchk_en;
+
+               skb_put(skb, len);
+               if (priv->desc_64b_en) {
+                       skb_pull(skb, 64);
+                       len -= 64;
+               }
+
+               if (likely(chksum_ok))
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+               /* remove hardware 2bytes added for IP alignment */
+               skb_pull(skb, 2);
+               len -= 2;
+
+               if (priv->crc_fwd_en) {
+                       skb_trim(skb, len - ETH_FCS_LEN);
+                       len -= ETH_FCS_LEN;
+               }
+
+               /*Finish setting up the received SKB and send it to the kernel*/
+               skb->protocol = eth_type_trans(skb, priv->dev);
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += len;
+               if (dma_flag & DMA_RX_MULT)
+                       dev->stats.multicast++;
+
+               /* Notify kernel */
+               napi_gro_receive(&priv->napi, skb);
+               cb->skb = NULL;
+               netif_dbg(priv, rx_status, dev, "pushed up to kernel\n");
+
+               /* refill RX path on the current control block */
+refill:
+               err = bcmgenet_rx_refill(priv, cb);
+               if (err)
+                       netif_err(priv, rx_err, dev, "Rx refill failed\n");
+       }
+
+       return rxpktprocessed;
+}
+
+/* Assign skb to RX DMA descriptor. */
+static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv)
+{
+       struct enet_cb *cb;
+       int ret = 0;
+       int i;
+
+       netif_dbg(priv, hw, priv->dev, "%s:\n", __func__);
+
+       /* loop here for each buffer needing assign */
+       for (i = 0; i < priv->num_rx_bds; i++) {
+               cb = &priv->rx_cbs[priv->rx_bd_assign_index];
+               if (cb->skb)
+                       continue;
+
+               /* set the DMA descriptor length once and for all
+                * it will only change if we support dynamically sizing
+                * priv->rx_buf_len, but we do not
+                */
+               dmadesc_set_length_status(priv, priv->rx_bd_assign_ptr,
+                               priv->rx_buf_len << DMA_BUFLENGTH_SHIFT);
+
+               ret = bcmgenet_rx_refill(priv, cb);
+               if (ret)
+                       break;
+
+       }
+
+       return ret;
+}
+
+static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv)
+{
+       struct enet_cb *cb;
+       int i;
+
+       for (i = 0; i < priv->num_rx_bds; i++) {
+               cb = &priv->rx_cbs[i];
+
+               if (dma_unmap_addr(cb, dma_addr)) {
+                       dma_unmap_single(&priv->dev->dev,
+                                       dma_unmap_addr(cb, dma_addr),
+                                       priv->rx_buf_len, DMA_FROM_DEVICE);
+                       dma_unmap_addr_set(cb, dma_addr, 0);
+               }
+
+               if (cb->skb)
+                       bcmgenet_free_cb(cb);
+       }
+}
+
+static int reset_umac(struct bcmgenet_priv *priv)
+{
+       struct device *kdev = &priv->pdev->dev;
+       unsigned int timeout = 0;
+       u32 reg;
+
+       /* 7358a0/7552a0: bad default in RBUF_FLUSH_CTRL.umac_sw_rst */
+       bcmgenet_rbuf_ctrl_set(priv, 0);
+       udelay(10);
+
+       /* disable MAC while updating its registers */
+       bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+
+       /* issue soft reset, wait for it to complete */
+       bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
+       while (timeout++ < 1000) {
+               reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+               if (!(reg & CMD_SW_RESET))
+                       return 0;
+
+               udelay(1);
+       }
+
+       if (timeout == 1000) {
+               dev_err(kdev,
+                       "timeout waiting for MAC to come out of resetn\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int init_umac(struct bcmgenet_priv *priv)
+{
+       struct device *kdev = &priv->pdev->dev;
+       int ret;
+       u32 reg, cpu_mask_clear;
+
+       dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n");
+
+       ret = reset_umac(priv);
+       if (ret)
+               return ret;
+
+       bcmgenet_umac_writel(priv, 0, UMAC_CMD);
+       /* clear tx/rx counter */
+       bcmgenet_umac_writel(priv,
+               MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, UMAC_MIB_CTRL);
+       bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL);
+
+       bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN);
+
+       /* init rx registers, enable ip header optimization */
+       reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL);
+       reg |= RBUF_ALIGN_2B;
+       bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL);
+
+       if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv))
+               bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL);
+
+       /* Mask all interrupts.*/
+       bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET);
+       bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR);
+       bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+
+       cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE;
+
+       dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__);
+
+       /* Monitor cable plug/unpluged event for internal PHY */
+       if (phy_is_internal(priv->phydev))
+               cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP);
+       else if (priv->ext_phy)
+               cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP);
+       else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
+               reg = bcmgenet_bp_mc_get(priv);
+               reg |= BIT(priv->hw_params->bp_in_en_shift);
+
+               /* bp_mask: back pressure mask */
+               if (netif_is_multiqueue(priv->dev))
+                       reg |= priv->hw_params->bp_in_mask;
+               else
+                       reg &= ~priv->hw_params->bp_in_mask;
+               bcmgenet_bp_mc_set(priv, reg);
+       }
+
+       /* Enable MDIO interrupts on GENET v3+ */
+       if (priv->hw_params->flags & GENET_HAS_MDIO_INTR)
+               cpu_mask_clear |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR;
+
+       bcmgenet_intrl2_0_writel(priv, cpu_mask_clear,
+               INTRL2_CPU_MASK_CLEAR);
+
+       /* Enable rx/tx engine.*/
+       dev_dbg(kdev, "done init umac\n");
+
+       return 0;
+}
+
+/* Initialize all house-keeping variables for a TX ring, along
+ * with corresponding hardware registers
+ */
+static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
+                                 unsigned int index, unsigned int size,
+                                 unsigned int write_ptr, unsigned int end_ptr)
+{
+       struct bcmgenet_tx_ring *ring = &priv->tx_rings[index];
+       u32 words_per_bd = WORDS_PER_BD(priv);
+       u32 flow_period_val = 0;
+       unsigned int first_bd;
+
+       spin_lock_init(&ring->lock);
+       ring->index = index;
+       if (index == DESC_INDEX) {
+               ring->queue = 0;
+               ring->int_enable = bcmgenet_tx_ring16_int_enable;
+               ring->int_disable = bcmgenet_tx_ring16_int_disable;
+       } else {
+               ring->queue = index + 1;
+               ring->int_enable = bcmgenet_tx_ring_int_enable;
+               ring->int_disable = bcmgenet_tx_ring_int_disable;
+       }
+       ring->cbs = priv->tx_cbs + write_ptr;
+       ring->size = size;
+       ring->c_index = 0;
+       ring->free_bds = size;
+       ring->write_ptr = write_ptr;
+       ring->cb_ptr = write_ptr;
+       ring->end_ptr = end_ptr - 1;
+       ring->prod_index = 0;
+
+       /* Set flow period for ring != 16 */
+       if (index != DESC_INDEX)
+               flow_period_val = ENET_MAX_MTU_SIZE << 16;
+
+       bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
+       bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
+       bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
+       /* Disable rate control for now */
+       bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
+                       TDMA_FLOW_PERIOD);
+       /* Unclassified traffic goes to ring 16 */
+       bcmgenet_tdma_ring_writel(priv, index,
+                       ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH),
+                       DMA_RING_BUF_SIZE);
+
+       first_bd = write_ptr;
+
+       /* Set start and end address, read and write pointers */
+       bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd,
+                       DMA_START_ADDR);
+       bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd,
+                       TDMA_READ_PTR);
+       bcmgenet_tdma_ring_writel(priv, index, first_bd,
+                       TDMA_WRITE_PTR);
+       bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1,
+                       DMA_END_ADDR);
+}
+
+/* Initialize a RDMA ring */
+static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv,
+                                 unsigned int index, unsigned int size)
+{
+       u32 words_per_bd = WORDS_PER_BD(priv);
+       int ret;
+
+       priv->num_rx_bds = TOTAL_DESC;
+       priv->rx_bds = priv->base + priv->hw_params->rdma_offset;
+       priv->rx_bd_assign_ptr = priv->rx_bds;
+       priv->rx_bd_assign_index = 0;
+       priv->rx_c_index = 0;
+       priv->rx_read_ptr = 0;
+       priv->rx_cbs = kzalloc(priv->num_rx_bds * sizeof(struct enet_cb),
+                               GFP_KERNEL);
+       if (!priv->rx_cbs)
+               return -ENOMEM;
+
+       ret = bcmgenet_alloc_rx_buffers(priv);
+       if (ret) {
+               kfree(priv->rx_cbs);
+               return ret;
+       }
+
+       bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_WRITE_PTR);
+       bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_PROD_INDEX);
+       bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX);
+       bcmgenet_rdma_ring_writel(priv, index,
+               ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH),
+               DMA_RING_BUF_SIZE);
+       bcmgenet_rdma_ring_writel(priv, index, 0, DMA_START_ADDR);
+       bcmgenet_rdma_ring_writel(priv, index,
+               words_per_bd * size - 1, DMA_END_ADDR);
+       bcmgenet_rdma_ring_writel(priv, index,
+                       (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) |
+                       DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH);
+       bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_READ_PTR);
+
+       return ret;
+}
+
+/* init multi xmit queues, only available for GENET2+
+ * the queue is partitioned as follows:
+ *
+ * queue 0 - 3 is priority based, each one has 32 descriptors,
+ * with queue 0 being the highest priority queue.
+ *
+ * queue 16 is the default tx queue with GENET_DEFAULT_BD_CNT
+ * descriptors: 256 - (number of tx queues * bds per queues) = 128
+ * descriptors.
+ *
+ * The transmit control block pool is then partitioned as following:
+ * - tx_cbs[0...127] are for queue 16
+ * - tx_ring_cbs[0] points to tx_cbs[128..159]
+ * - tx_ring_cbs[1] points to tx_cbs[160..191]
+ * - tx_ring_cbs[2] points to tx_cbs[192..223]
+ * - tx_ring_cbs[3] points to tx_cbs[224..255]
+ */
+static void bcmgenet_init_multiq(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       unsigned int i, dma_enable;
+       u32 reg, dma_ctrl, ring_cfg = 0, dma_priority = 0;
+
+       if (!netif_is_multiqueue(dev)) {
+               netdev_warn(dev, "called with non multi queue aware HW\n");
+               return;
+       }
+
+       dma_ctrl = bcmgenet_tdma_readl(priv, DMA_CTRL);
+       dma_enable = dma_ctrl & DMA_EN;
+       dma_ctrl &= ~DMA_EN;
+       bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL);
+
+       /* Enable strict priority arbiter mode */
+       bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL);
+
+       for (i = 0; i < priv->hw_params->tx_queues; i++) {
+               /* first 64 tx_cbs are reserved for default tx queue
+                * (ring 16)
+                */
+               bcmgenet_init_tx_ring(priv, i, priv->hw_params->bds_cnt,
+                                       i * priv->hw_params->bds_cnt,
+                                       (i + 1) * priv->hw_params->bds_cnt);
+
+               /* Configure ring as decriptor ring and setup priority */
+               ring_cfg |= 1 << i;
+               dma_priority |= ((GENET_Q0_PRIORITY + i) <<
+                               (GENET_MAX_MQ_CNT + 1) * i);
+               dma_ctrl |= 1 << (i + DMA_RING_BUF_EN_SHIFT);
+       }
+
+       /* Enable rings */
+       reg = bcmgenet_tdma_readl(priv, DMA_RING_CFG);
+       reg |= ring_cfg;
+       bcmgenet_tdma_writel(priv, reg, DMA_RING_CFG);
+
+       /* Use configured rings priority and set ring #16 priority */
+       reg = bcmgenet_tdma_readl(priv, DMA_RING_PRIORITY);
+       reg |= ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << 20);
+       reg |= dma_priority;
+       bcmgenet_tdma_writel(priv, reg, DMA_PRIORITY);
+
+       /* Configure ring as descriptor ring and re-enable DMA if enabled */
+       reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+       reg |= dma_ctrl;
+       if (dma_enable)
+               reg |= DMA_EN;
+       bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+}
+
+static void bcmgenet_fini_dma(struct bcmgenet_priv *priv)
+{
+       int i;
+
+       /* disable DMA */
+       bcmgenet_rdma_writel(priv, 0, DMA_CTRL);
+       bcmgenet_tdma_writel(priv, 0, DMA_CTRL);
+
+       for (i = 0; i < priv->num_tx_bds; i++) {
+               if (priv->tx_cbs[i].skb != NULL) {
+                       dev_kfree_skb(priv->tx_cbs[i].skb);
+                       priv->tx_cbs[i].skb = NULL;
+               }
+       }
+
+       bcmgenet_free_rx_buffers(priv);
+       kfree(priv->rx_cbs);
+       kfree(priv->tx_cbs);
+}
+
+/* init_edma: Initialize DMA control register */
+static int bcmgenet_init_dma(struct bcmgenet_priv *priv)
+{
+       int ret;
+
+       netif_dbg(priv, hw, priv->dev, "bcmgenet: init_edma\n");
+
+       /* by default, enable ring 16 (descriptor based) */
+       ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, TOTAL_DESC);
+       if (ret) {
+               netdev_err(priv->dev, "failed to initialize RX ring\n");
+               return ret;
+       }
+
+       /* init rDma */
+       bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
+
+       /* Init tDma */
+       bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE);
+
+       /* Initialize commont TX ring structures */
+       priv->tx_bds = priv->base + priv->hw_params->tdma_offset;
+       priv->num_tx_bds = TOTAL_DESC;
+       priv->tx_cbs = kzalloc(priv->num_tx_bds * sizeof(struct enet_cb),
+                               GFP_KERNEL);
+       if (!priv->tx_cbs) {
+               bcmgenet_fini_dma(priv);
+               return -ENOMEM;
+       }
+
+       /* initialize multi xmit queue */
+       bcmgenet_init_multiq(priv->dev);
+
+       /* initialize special ring 16 */
+       bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_DEFAULT_BD_CNT,
+                       priv->hw_params->tx_queues * priv->hw_params->bds_cnt,
+                       TOTAL_DESC);
+
+       return 0;
+}
+
+/* NAPI polling method*/
+static int bcmgenet_poll(struct napi_struct *napi, int budget)
+{
+       struct bcmgenet_priv *priv = container_of(napi,
+                       struct bcmgenet_priv, napi);
+       unsigned int work_done;
+
+       /* tx reclaim */
+       bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+
+       work_done = bcmgenet_desc_rx(priv, budget);
+
+       /* Advancing our consumer index*/
+       priv->rx_c_index += work_done;
+       priv->rx_c_index &= DMA_C_INDEX_MASK;
+       bcmgenet_rdma_ring_writel(priv, DESC_INDEX,
+                               priv->rx_c_index, RDMA_CONS_INDEX);
+       if (work_done < budget) {
+               napi_complete(napi);
+               bcmgenet_intrl2_0_writel(priv,
+                       UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_CLEAR);
+       }
+
+       return work_done;
+}
+
+/* Interrupt bottom half */
+static void bcmgenet_irq_task(struct work_struct *work)
+{
+       struct bcmgenet_priv *priv = container_of(
+                       work, struct bcmgenet_priv, bcmgenet_irq_work);
+
+       netif_dbg(priv, intr, priv->dev, "%s\n", __func__);
+
+       /* Link UP/DOWN event */
+       if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
+               (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) {
+               phy_mac_interrupt(priv->phydev,
+                       priv->irq0_stat & UMAC_IRQ_LINK_UP);
+               priv->irq0_stat &= ~(UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN);
+       }
+}
+
+/* bcmgenet_isr1: interrupt handler for ring buffer. */
+static irqreturn_t bcmgenet_isr1(int irq, void *dev_id)
+{
+       struct bcmgenet_priv *priv = dev_id;
+       unsigned int index;
+
+       /* Save irq status for bottom-half processing. */
+       priv->irq1_stat =
+               bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) &
+               ~priv->int1_mask;
+       /* clear inerrupts*/
+       bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR);
+
+       netif_dbg(priv, intr, priv->dev,
+               "%s: IRQ=0x%x\n", __func__, priv->irq1_stat);
+       /* Check the MBDONE interrupts.
+        * packet is done, reclaim descriptors
+        */
+       if (priv->irq1_stat & 0x0000ffff) {
+               index = 0;
+               for (index = 0; index < 16; index++) {
+                       if (priv->irq1_stat & (1 << index))
+                               bcmgenet_tx_reclaim(priv->dev,
+                                               &priv->tx_rings[index]);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+/* bcmgenet_isr0: Handle various interrupts. */
+static irqreturn_t bcmgenet_isr0(int irq, void *dev_id)
+{
+       struct bcmgenet_priv *priv = dev_id;
+
+       /* Save irq status for bottom-half processing. */
+       priv->irq0_stat =
+               bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) &
+               ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS);
+       /* clear inerrupts*/
+       bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR);
+
+       netif_dbg(priv, intr, priv->dev,
+               "IRQ=0x%x\n", priv->irq0_stat);
+
+       if (priv->irq0_stat & (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE)) {
+               /* We use NAPI(software interrupt throttling, if
+                * Rx Descriptor throttling is not used.
+                * Disable interrupt, will be enabled in the poll method.
+                */
+               if (likely(napi_schedule_prep(&priv->napi))) {
+                       bcmgenet_intrl2_0_writel(priv,
+                               UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_SET);
+                       __napi_schedule(&priv->napi);
+               }
+       }
+       if (priv->irq0_stat &
+                       (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) {
+               /* Tx reclaim */
+               bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]);
+       }
+       if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R |
+                               UMAC_IRQ_PHY_DET_F |
+                               UMAC_IRQ_LINK_UP |
+                               UMAC_IRQ_LINK_DOWN |
+                               UMAC_IRQ_HFB_SM |
+                               UMAC_IRQ_HFB_MM |
+                               UMAC_IRQ_MPD_R)) {
+               /* all other interested interrupts handled in bottom half */
+               schedule_work(&priv->bcmgenet_irq_work);
+       }
+
+       if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) &&
+               priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) {
+               priv->irq0_stat &= ~(UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR);
+               wake_up(&priv->wq);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static void bcmgenet_umac_reset(struct bcmgenet_priv *priv)
+{
+       u32 reg;
+
+       reg = bcmgenet_rbuf_ctrl_get(priv);
+       reg |= BIT(1);
+       bcmgenet_rbuf_ctrl_set(priv, reg);
+       udelay(10);
+
+       reg &= ~BIT(1);
+       bcmgenet_rbuf_ctrl_set(priv, reg);
+       udelay(10);
+}
+
+static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv,
+                                 unsigned char *addr)
+{
+       bcmgenet_umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) |
+                       (addr[2] << 8) | addr[3], UMAC_MAC0);
+       bcmgenet_umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1);
+}
+
+static int bcmgenet_wol_resume(struct bcmgenet_priv *priv)
+{
+       int ret;
+
+       /* From WOL-enabled suspend, switch to regular clock */
+       clk_disable(priv->clk_wol);
+       /* init umac registers to synchronize s/w with h/w */
+       ret = init_umac(priv);
+       if (ret)
+               return ret;
+
+       phy_init_hw(priv->phydev);
+       /* Speed settings must be restored */
+       bcmgenet_mii_config(priv->dev);
+
+       return 0;
+}
+
+/* Returns a reusable dma control register value */
+static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv)
+{
+       u32 reg;
+       u32 dma_ctrl;
+
+       /* disable DMA */
+       dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN;
+       reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+       reg &= ~dma_ctrl;
+       bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+
+       reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
+       reg &= ~dma_ctrl;
+       bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
+
+       bcmgenet_umac_writel(priv, 1, UMAC_TX_FLUSH);
+       udelay(10);
+       bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH);
+
+       return dma_ctrl;
+}
+
+static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl)
+{
+       u32 reg;
+
+       reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
+       reg |= dma_ctrl;
+       bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
+
+       reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+       reg |= dma_ctrl;
+       bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+}
+
+static int bcmgenet_open(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       unsigned long dma_ctrl;
+       u32 reg;
+       int ret;
+
+       netif_dbg(priv, ifup, dev, "bcmgenet_open\n");
+
+       /* Turn on the clock */
+       if (!IS_ERR(priv->clk))
+               clk_prepare_enable(priv->clk);
+
+       /* take MAC out of reset */
+       bcmgenet_umac_reset(priv);
+
+       ret = init_umac(priv);
+       if (ret)
+               goto err_clk_disable;
+
+       /* disable ethernet MAC while updating its registers */
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       reg &= ~(CMD_TX_EN | CMD_RX_EN);
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+       bcmgenet_set_hw_addr(priv, dev->dev_addr);
+
+       if (priv->wol_enabled) {
+               ret = bcmgenet_wol_resume(priv);
+               if (ret)
+                       return ret;
+       }
+
+       if (phy_is_internal(priv->phydev)) {
+               reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+               reg |= EXT_ENERGY_DET_MASK;
+               bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+       }
+
+       /* Disable RX/TX DMA and flush TX queues */
+       dma_ctrl = bcmgenet_dma_disable(priv);
+
+       /* Reinitialize TDMA and RDMA and SW housekeeping */
+       ret = bcmgenet_init_dma(priv);
+       if (ret) {
+               netdev_err(dev, "failed to initialize DMA\n");
+               goto err_fini_dma;
+       }
+
+       /* Always enable ring 16 - descriptor ring */
+       bcmgenet_enable_dma(priv, dma_ctrl);
+
+       ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED,
+                       dev->name, priv);
+       if (ret < 0) {
+               netdev_err(dev, "can't request IRQ %d\n", priv->irq0);
+               goto err_fini_dma;
+       }
+
+       ret = request_irq(priv->irq1, bcmgenet_isr1, IRQF_SHARED,
+                               dev->name, priv);
+       if (ret < 0) {
+               netdev_err(dev, "can't request IRQ %d\n", priv->irq1);
+               goto err_irq0;
+       }
+
+       /* Start the network engine */
+       napi_enable(&priv->napi);
+
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       reg |= (CMD_TX_EN | CMD_RX_EN);
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+       /* Make sure we reflect the value of CRC_CMD_FWD */
+       priv->crc_fwd_en = !!(reg & CMD_CRC_FWD);
+
+       device_set_wakeup_capable(&dev->dev, 1);
+
+       if (phy_is_internal(priv->phydev))
+               bcmgenet_power_up(priv, GENET_POWER_PASSIVE);
+
+       netif_tx_start_all_queues(dev);
+
+       phy_start(priv->phydev);
+
+       return 0;
+
+err_irq0:
+       free_irq(priv->irq0, dev);
+err_fini_dma:
+       bcmgenet_fini_dma(priv);
+err_clk_disable:
+       if (!IS_ERR(priv->clk))
+               clk_disable_unprepare(priv->clk);
+       return ret;
+}
+
+static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv)
+{
+       int ret = 0;
+       int timeout = 0;
+       u32 reg;
+
+       /* Disable TDMA to stop add more frames in TX DMA */
+       reg = bcmgenet_tdma_readl(priv, DMA_CTRL);
+       reg &= ~DMA_EN;
+       bcmgenet_tdma_writel(priv, reg, DMA_CTRL);
+
+       /* Check TDMA status register to confirm TDMA is disabled */
+       while (timeout++ < DMA_TIMEOUT_VAL) {
+               reg = bcmgenet_tdma_readl(priv, DMA_STATUS);
+               if (reg & DMA_DISABLED)
+                       break;
+
+               udelay(1);
+       }
+
+       if (timeout == DMA_TIMEOUT_VAL) {
+               netdev_warn(priv->dev,
+                       "Timed out while disabling TX DMA\n");
+               ret = -ETIMEDOUT;
+       }
+
+       /* Wait 10ms for packet drain in both tx and rx dma */
+       usleep_range(10000, 20000);
+
+       /* Disable RDMA */
+       reg = bcmgenet_rdma_readl(priv, DMA_CTRL);
+       reg &= ~DMA_EN;
+       bcmgenet_rdma_writel(priv, reg, DMA_CTRL);
+
+       timeout = 0;
+       /* Check RDMA status register to confirm RDMA is disabled */
+       while (timeout++ < DMA_TIMEOUT_VAL) {
+               reg = bcmgenet_rdma_readl(priv, DMA_STATUS);
+               if (reg & DMA_DISABLED)
+                       break;
+
+               udelay(1);
+       }
+
+       if (timeout == DMA_TIMEOUT_VAL) {
+               netdev_warn(priv->dev,
+                       "Timed out while disabling RX DMA\n");
+                       ret = -ETIMEDOUT;
+       }
+
+       return ret;
+}
+
+static int bcmgenet_close(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       int ret;
+       u32 reg;
+
+       netif_dbg(priv, ifdown, dev, "bcmgenet_close\n");
+
+       phy_stop(priv->phydev);
+
+       /* Disable MAC receive */
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       reg &= ~CMD_RX_EN;
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+       netif_tx_stop_all_queues(dev);
+
+       ret = bcmgenet_dma_teardown(priv);
+       if (ret)
+               return ret;
+
+       /* Disable MAC transmit. TX DMA disabled have to done before this */
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       reg &= ~CMD_TX_EN;
+       bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+       napi_disable(&priv->napi);
+
+       /* tx reclaim */
+       bcmgenet_tx_reclaim_all(dev);
+       bcmgenet_fini_dma(priv);
+
+       free_irq(priv->irq0, priv);
+       free_irq(priv->irq1, priv);
+
+       /* Wait for pending work items to complete - we are stopping
+        * the clock now. Since interrupts are disabled, no new work
+        * will be scheduled.
+        */
+       cancel_work_sync(&priv->bcmgenet_irq_work);
+
+       if (phy_is_internal(priv->phydev))
+               bcmgenet_power_down(priv, GENET_POWER_PASSIVE);
+
+       if (priv->wol_enabled)
+               clk_enable(priv->clk_wol);
+
+       if (!IS_ERR(priv->clk))
+               clk_disable_unprepare(priv->clk);
+
+       return 0;
+}
+
+static void bcmgenet_timeout(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n");
+
+       dev->trans_start = jiffies;
+
+       dev->stats.tx_errors++;
+
+       netif_tx_wake_all_queues(dev);
+}
+
+#define MAX_MC_COUNT   16
+
+static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
+                                        unsigned char *addr,
+                                        int *i,
+                                        int *mc)
+{
+       u32 reg;
+
+       bcmgenet_umac_writel(priv,
+                       addr[0] << 8 | addr[1], UMAC_MDF_ADDR + (*i * 4));
+       bcmgenet_umac_writel(priv,
+                       addr[2] << 24 | addr[3] << 16 |
+                       addr[4] << 8 | addr[5],
+                       UMAC_MDF_ADDR + ((*i + 1) * 4));
+       reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
+       reg |= (1 << (MAX_MC_COUNT - *mc));
+       bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
+       *i += 2;
+       (*mc)++;
+}
+
+static void bcmgenet_set_rx_mode(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct netdev_hw_addr *ha;
+       int i, mc;
+       u32 reg;
+
+       netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
+
+       /* Promiscous mode */
+       reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+       if (dev->flags & IFF_PROMISC) {
+               reg |= CMD_PROMISC;
+               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+               bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
+               return;
+       } else {
+               reg &= ~CMD_PROMISC;
+               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+       }
+
+       /* UniMac doesn't support ALLMULTI */
+       if (dev->flags & IFF_ALLMULTI) {
+               netdev_warn(dev, "ALLMULTI is not supported\n");
+               return;
+       }
+
+       /* update MDF filter */
+       i = 0;
+       mc = 0;
+       /* Broadcast */
+       bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc);
+       /* my own address.*/
+       bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc);
+       /* Unicast list*/
+       if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
+               return;
+
+       if (!netdev_uc_empty(dev))
+               netdev_for_each_uc_addr(ha, dev)
+                       bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+       /* Multicast */
+       if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
+               return;
+
+       netdev_for_each_mc_addr(ha, dev)
+               bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc);
+}
+
+/* Set the hardware MAC address. */
+static int bcmgenet_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct sockaddr *addr = p;
+
+       /* Setting the MAC address at the hardware level is not possible
+        * without disabling the UniMAC RX/TX enable bits.
+        */
+       if (netif_running(dev))
+               return -EBUSY;
+
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
+
+       return 0;
+}
+
+static const struct net_device_ops bcmgenet_netdev_ops = {
+       .ndo_open               = bcmgenet_open,
+       .ndo_stop               = bcmgenet_close,
+       .ndo_start_xmit         = bcmgenet_xmit,
+       .ndo_tx_timeout         = bcmgenet_timeout,
+       .ndo_set_rx_mode        = bcmgenet_set_rx_mode,
+       .ndo_set_mac_address    = bcmgenet_set_mac_addr,
+       .ndo_do_ioctl           = bcmgenet_ioctl,
+       .ndo_set_features       = bcmgenet_set_features,
+};
+
+/* Array of GENET hardware parameters/characteristics */
+static struct bcmgenet_hw_params bcmgenet_hw_params[] = {
+       [GENET_V1] = {
+               .tx_queues = 0,
+               .rx_queues = 0,
+               .bds_cnt = 0,
+               .bp_in_en_shift = 16,
+               .bp_in_mask = 0xffff,
+               .hfb_filter_cnt = 16,
+               .qtag_mask = 0x1F,
+               .hfb_offset = 0x1000,
+               .rdma_offset = 0x2000,
+               .tdma_offset = 0x3000,
+               .words_per_bd = 2,
+       },
+       [GENET_V2] = {
+               .tx_queues = 4,
+               .rx_queues = 4,
+               .bds_cnt = 32,
+               .bp_in_en_shift = 16,
+               .bp_in_mask = 0xffff,
+               .hfb_filter_cnt = 16,
+               .qtag_mask = 0x1F,
+               .tbuf_offset = 0x0600,
+               .hfb_offset = 0x1000,
+               .hfb_reg_offset = 0x2000,
+               .rdma_offset = 0x3000,
+               .tdma_offset = 0x4000,
+               .words_per_bd = 2,
+               .flags = GENET_HAS_EXT,
+       },
+       [GENET_V3] = {
+               .tx_queues = 4,
+               .rx_queues = 4,
+               .bds_cnt = 32,
+               .bp_in_en_shift = 17,
+               .bp_in_mask = 0x1ffff,
+               .hfb_filter_cnt = 48,
+               .qtag_mask = 0x3F,
+               .tbuf_offset = 0x0600,
+               .hfb_offset = 0x8000,
+               .hfb_reg_offset = 0xfc00,
+               .rdma_offset = 0x10000,
+               .tdma_offset = 0x11000,
+               .words_per_bd = 2,
+               .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR,
+       },
+       [GENET_V4] = {
+               .tx_queues = 4,
+               .rx_queues = 4,
+               .bds_cnt = 32,
+               .bp_in_en_shift = 17,
+               .bp_in_mask = 0x1ffff,
+               .hfb_filter_cnt = 48,
+               .qtag_mask = 0x3F,
+               .tbuf_offset = 0x0600,
+               .hfb_offset = 0x8000,
+               .hfb_reg_offset = 0xfc00,
+               .rdma_offset = 0x2000,
+               .tdma_offset = 0x4000,
+               .words_per_bd = 3,
+               .flags = GENET_HAS_40BITS | GENET_HAS_EXT | GENET_HAS_MDIO_INTR,
+       },
+};
+
+/* Infer hardware parameters from the detected GENET version */
+static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv)
+{
+       struct bcmgenet_hw_params *params;
+       u32 reg;
+       u8 major;
+
+       if (GENET_IS_V4(priv)) {
+               bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
+               genet_dma_ring_regs = genet_dma_ring_regs_v4;
+               priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
+               priv->version = GENET_V4;
+       } else if (GENET_IS_V3(priv)) {
+               bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus;
+               genet_dma_ring_regs = genet_dma_ring_regs_v123;
+               priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS;
+               priv->version = GENET_V3;
+       } else if (GENET_IS_V2(priv)) {
+               bcmgenet_dma_regs = bcmgenet_dma_regs_v2;
+               genet_dma_ring_regs = genet_dma_ring_regs_v123;
+               priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
+               priv->version = GENET_V2;
+       } else if (GENET_IS_V1(priv)) {
+               bcmgenet_dma_regs = bcmgenet_dma_regs_v1;
+               genet_dma_ring_regs = genet_dma_ring_regs_v123;
+               priv->dma_rx_chk_bit = DMA_RX_CHK_V12;
+               priv->version = GENET_V1;
+       }
+
+       /* enum genet_version starts at 1 */
+       priv->hw_params = &bcmgenet_hw_params[priv->version];
+       params = priv->hw_params;
+
+       /* Read GENET HW version */
+       reg = bcmgenet_sys_readl(priv, SYS_REV_CTRL);
+       major = (reg >> 24 & 0x0f);
+       if (major == 5)
+               major = 4;
+       else if (major == 0)
+               major = 1;
+       if (major != priv->version) {
+               dev_err(&priv->pdev->dev,
+                       "GENET version mismatch, got: %d, configured for: %d\n",
+                       major, priv->version);
+       }
+
+       /* Print the GENET core version */
+       dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT,
+               major, (reg >> 16) & 0x0f, reg & 0xffff);
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+       if (!(params->flags & GENET_HAS_40BITS))
+               pr_warn("GENET does not support 40-bits PA\n");
+#endif
+
+       pr_debug("Configuration for version: %d\n"
+               "TXq: %1d, RXq: %1d, BDs: %1d\n"
+               "BP << en: %2d, BP msk: 0x%05x\n"
+               "HFB count: %2d, QTAQ msk: 0x%05x\n"
+               "TBUF: 0x%04x, HFB: 0x%04x, HFBreg: 0x%04x\n"
+               "RDMA: 0x%05x, TDMA: 0x%05x\n"
+               "Words/BD: %d\n",
+               priv->version,
+               params->tx_queues, params->rx_queues, params->bds_cnt,
+               params->bp_in_en_shift, params->bp_in_mask,
+               params->hfb_filter_cnt, params->qtag_mask,
+               params->tbuf_offset, params->hfb_offset,
+               params->hfb_reg_offset,
+               params->rdma_offset, params->tdma_offset,
+               params->words_per_bd);
+}
+
+static const struct of_device_id bcmgenet_match[] = {
+       { .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 },
+       { .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 },
+       { .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 },
+       { .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 },
+       { },
+};
+
+static int bcmgenet_probe(struct platform_device *pdev)
+{
+       struct device_node *dn = pdev->dev.of_node;
+       const struct of_device_id *of_id;
+       struct bcmgenet_priv *priv;
+       struct net_device *dev;
+       const void *macaddr;
+       struct resource *r;
+       int err = -EIO;
+
+       /* Up to GENET_MAX_MQ_CNT + 1 TX queues and a single RX queue */
+       dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1, 1);
+       if (!dev) {
+               dev_err(&pdev->dev, "can't allocate net device\n");
+               return -ENOMEM;
+       }
+
+       of_id = of_match_node(bcmgenet_match, dn);
+       if (!of_id)
+               return -EINVAL;
+
+       priv = netdev_priv(dev);
+       priv->irq0 = platform_get_irq(pdev, 0);
+       priv->irq1 = platform_get_irq(pdev, 1);
+       if (!priv->irq0 || !priv->irq1) {
+               dev_err(&pdev->dev, "can't find IRQs\n");
+               err = -EINVAL;
+               goto err;
+       }
+
+       macaddr = of_get_mac_address(dn);
+       if (!macaddr) {
+               dev_err(&pdev->dev, "can't find MAC address\n");
+               err = -EINVAL;
+               goto err;
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(priv->base)) {
+               err = PTR_ERR(priv->base);
+               goto err;
+       }
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+       dev_set_drvdata(&pdev->dev, dev);
+       ether_addr_copy(dev->dev_addr, macaddr);
+       dev->watchdog_timeo = 2 * HZ;
+       SET_ETHTOOL_OPS(dev, &bcmgenet_ethtool_ops);
+       dev->netdev_ops = &bcmgenet_netdev_ops;
+       netif_napi_add(dev, &priv->napi, bcmgenet_poll, 64);
+
+       priv->msg_enable = netif_msg_init(-1, GENET_MSG_DEFAULT);
+
+       /* Set hardware features */
+       dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
+
+       /* Set the needed headroom to account for any possible
+        * features enabling/disabling at runtime
+        */
+       dev->needed_headroom += 64;
+
+       netdev_boot_setup_check(dev);
+
+       priv->dev = dev;
+       priv->pdev = pdev;
+       priv->version = (enum bcmgenet_version)of_id->data;
+
+       bcmgenet_set_hw_params(priv);
+
+       /* Mii wait queue */
+       init_waitqueue_head(&priv->wq);
+       /* Always use RX_BUF_LENGTH (2KB) buffer for all chips */
+       priv->rx_buf_len = RX_BUF_LENGTH;
+       INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task);
+
+       priv->clk = devm_clk_get(&priv->pdev->dev, "enet");
+       if (IS_ERR(priv->clk))
+               dev_warn(&priv->pdev->dev, "failed to get enet clock\n");
+
+       priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol");
+       if (IS_ERR(priv->clk_wol))
+               dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n");
+
+       if (!IS_ERR(priv->clk))
+               clk_prepare_enable(priv->clk);
+
+       err = reset_umac(priv);
+       if (err)
+               goto err_clk_disable;
+
+       err = bcmgenet_mii_init(dev);
+       if (err)
+               goto err_clk_disable;
+
+       /* setup number of real queues  + 1 (GENET_V1 has 0 hardware queues
+        * just the ring 16 descriptor based TX
+        */
+       netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1);
+       netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1);
+
+       err = register_netdev(dev);
+       if (err)
+               goto err_clk_disable;
+
+       /* Turn off the main clock, WOL clock is handled separately */
+       if (!IS_ERR(priv->clk))
+               clk_disable_unprepare(priv->clk);
+
+       return err;
+
+err_clk_disable:
+       if (!IS_ERR(priv->clk))
+               clk_disable_unprepare(priv->clk);
+err:
+       free_netdev(dev);
+       return err;
+}
+
+static int bcmgenet_remove(struct platform_device *pdev)
+{
+       struct bcmgenet_priv *priv = dev_to_priv(&pdev->dev);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+       unregister_netdev(priv->dev);
+       bcmgenet_mii_exit(priv->dev);
+       free_netdev(priv->dev);
+
+       return 0;
+}
+
+
+static struct platform_driver bcmgenet_driver = {
+       .probe  = bcmgenet_probe,
+       .remove = bcmgenet_remove,
+       .driver = {
+               .name   = "bcmgenet",
+               .owner  = THIS_MODULE,
+               .of_match_table = bcmgenet_match,
+       },
+};
+module_platform_driver(bcmgenet_driver);
+
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_DESCRIPTION("Broadcom GENET Ethernet controller driver");
+MODULE_ALIAS("platform:bcmgenet");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
new file mode 100644 (file)
index 0000000..0f11710
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+*/
+#ifndef __BCMGENET_H__
+#define __BCMGENET_H__
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/phy.h>
+
+/* total number of Buffer Descriptors, same for Rx/Tx */
+#define TOTAL_DESC                             256
+
+/* which ring is descriptor based */
+#define DESC_INDEX                             16
+
+/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528.
+ * 1536 is multiple of 256 bytes
+ */
+#define ENET_BRCM_TAG_LEN      6
+#define ENET_PAD               8
+#define ENET_MAX_MTU_SIZE      (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
+                                ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
+#define DMA_MAX_BURST_LENGTH    0x10
+
+/* misc. configuration */
+#define CLEAR_ALL_HFB                  0xFF
+#define DMA_FC_THRESH_HI               (TOTAL_DESC >> 4)
+#define DMA_FC_THRESH_LO               5
+
+/* 64B receive/transmit status block */
+struct status_64 {
+       u32     length_status;          /* length and peripheral status */
+       u32     ext_status;             /* Extended status*/
+       u32     rx_csum;                /* partial rx checksum */
+       u32     unused1[9];             /* unused */
+       u32     tx_csum_info;           /* Tx checksum info. */
+       u32     unused2[3];             /* unused */
+};
+
+/* Rx status bits */
+#define STATUS_RX_EXT_MASK             0x1FFFFF
+#define STATUS_RX_CSUM_MASK            0xFFFF
+#define STATUS_RX_CSUM_OK              0x10000
+#define STATUS_RX_CSUM_FR              0x20000
+#define STATUS_RX_PROTO_TCP            0
+#define STATUS_RX_PROTO_UDP            1
+#define STATUS_RX_PROTO_ICMP           2
+#define STATUS_RX_PROTO_OTHER          3
+#define STATUS_RX_PROTO_MASK           3
+#define STATUS_RX_PROTO_SHIFT          18
+#define STATUS_FILTER_INDEX_MASK       0xFFFF
+/* Tx status bits */
+#define STATUS_TX_CSUM_START_MASK      0X7FFF
+#define STATUS_TX_CSUM_START_SHIFT     16
+#define STATUS_TX_CSUM_PROTO_UDP       0x8000
+#define STATUS_TX_CSUM_OFFSET_MASK     0x7FFF
+#define STATUS_TX_CSUM_LV              0x80000000
+
+/* DMA Descriptor */
+#define DMA_DESC_LENGTH_STATUS 0x00    /* in bytes of data in buffer */
+#define DMA_DESC_ADDRESS_LO    0x04    /* lower bits of PA */
+#define DMA_DESC_ADDRESS_HI    0x08    /* upper 32 bits of PA, GENETv4+ */
+
+/* Rx/Tx common counter group */
+struct bcmgenet_pkt_counters {
+       u32     cnt_64;         /* RO Received/Transmited 64 bytes packet */
+       u32     cnt_127;        /* RO Rx/Tx 127 bytes packet */
+       u32     cnt_255;        /* RO Rx/Tx 65-255 bytes packet */
+       u32     cnt_511;        /* RO Rx/Tx 256-511 bytes packet */
+       u32     cnt_1023;       /* RO Rx/Tx 512-1023 bytes packet */
+       u32     cnt_1518;       /* RO Rx/Tx 1024-1518 bytes packet */
+       u32     cnt_mgv;        /* RO Rx/Tx 1519-1522 good VLAN packet */
+       u32     cnt_2047;       /* RO Rx/Tx 1522-2047 bytes packet*/
+       u32     cnt_4095;       /* RO Rx/Tx 2048-4095 bytes packet*/
+       u32     cnt_9216;       /* RO Rx/Tx 4096-9216 bytes packet*/
+};
+
+/* RSV, Receive Status Vector */
+struct bcmgenet_rx_counters {
+       struct  bcmgenet_pkt_counters pkt_cnt;
+       u32     pkt;            /* RO (0x428) Received pkt count*/
+       u32     bytes;          /* RO Received byte count */
+       u32     mca;            /* RO # of Received multicast pkt */
+       u32     bca;            /* RO # of Receive broadcast pkt */
+       u32     fcs;            /* RO # of Received FCS error  */
+       u32     cf;             /* RO # of Received control frame pkt*/
+       u32     pf;             /* RO # of Received pause frame pkt */
+       u32     uo;             /* RO # of unknown op code pkt */
+       u32     aln;            /* RO # of alignment error count */
+       u32     flr;            /* RO # of frame length out of range count */
+       u32     cde;            /* RO # of code error pkt */
+       u32     fcr;            /* RO # of carrier sense error pkt */
+       u32     ovr;            /* RO # of oversize pkt*/
+       u32     jbr;            /* RO # of jabber count */
+       u32     mtue;           /* RO # of MTU error pkt*/
+       u32     pok;            /* RO # of Received good pkt */
+       u32     uc;             /* RO # of unicast pkt */
+       u32     ppp;            /* RO # of PPP pkt */
+       u32     rcrc;           /* RO (0x470),# of CRC match pkt */
+};
+
+/* TSV, Transmit Status Vector */
+struct bcmgenet_tx_counters {
+       struct bcmgenet_pkt_counters pkt_cnt;
+       u32     pkts;           /* RO (0x4a8) Transmited pkt */
+       u32     mca;            /* RO # of xmited multicast pkt */
+       u32     bca;            /* RO # of xmited broadcast pkt */
+       u32     pf;             /* RO # of xmited pause frame count */
+       u32     cf;             /* RO # of xmited control frame count */
+       u32     fcs;            /* RO # of xmited FCS error count */
+       u32     ovr;            /* RO # of xmited oversize pkt */
+       u32     drf;            /* RO # of xmited deferral pkt */
+       u32     edf;            /* RO # of xmited Excessive deferral pkt*/
+       u32     scl;            /* RO # of xmited single collision pkt */
+       u32     mcl;            /* RO # of xmited multiple collision pkt*/
+       u32     lcl;            /* RO # of xmited late collision pkt */
+       u32     ecl;            /* RO # of xmited excessive collision pkt*/
+       u32     frg;            /* RO # of xmited fragments pkt*/
+       u32     ncl;            /* RO # of xmited total collision count */
+       u32     jbr;            /* RO # of xmited jabber count*/
+       u32     bytes;          /* RO # of xmited byte count */
+       u32     pok;            /* RO # of xmited good pkt */
+       u32     uc;             /* RO (0x0x4f0)# of xmited unitcast pkt */
+};
+
+struct bcmgenet_mib_counters {
+       struct bcmgenet_rx_counters rx;
+       struct bcmgenet_tx_counters tx;
+       u32     rx_runt_cnt;
+       u32     rx_runt_fcs;
+       u32     rx_runt_fcs_align;
+       u32     rx_runt_bytes;
+       u32     rbuf_ovflow_cnt;
+       u32     rbuf_err_cnt;
+       u32     mdf_err_cnt;
+};
+
+#define UMAC_HD_BKP_CTRL               0x004
+#define         HD_FC_EN                       (1 << 0)
+#define  HD_FC_BKOFF_OK                        (1 << 1)
+#define  IPG_CONFIG_RX_SHIFT           2
+#define  IPG_CONFIG_RX_MASK            0x1F
+
+#define UMAC_CMD                       0x008
+#define  CMD_TX_EN                     (1 << 0)
+#define  CMD_RX_EN                     (1 << 1)
+#define  UMAC_SPEED_10                 0
+#define  UMAC_SPEED_100                        1
+#define  UMAC_SPEED_1000               2
+#define  UMAC_SPEED_2500               3
+#define  CMD_SPEED_SHIFT               2
+#define  CMD_SPEED_MASK                        3
+#define  CMD_PROMISC                   (1 << 4)
+#define  CMD_PAD_EN                    (1 << 5)
+#define  CMD_CRC_FWD                   (1 << 6)
+#define  CMD_PAUSE_FWD                 (1 << 7)
+#define  CMD_RX_PAUSE_IGNORE           (1 << 8)
+#define  CMD_TX_ADDR_INS               (1 << 9)
+#define  CMD_HD_EN                     (1 << 10)
+#define  CMD_SW_RESET                  (1 << 13)
+#define  CMD_LCL_LOOP_EN               (1 << 15)
+#define  CMD_AUTO_CONFIG               (1 << 22)
+#define  CMD_CNTL_FRM_EN               (1 << 23)
+#define  CMD_NO_LEN_CHK                        (1 << 24)
+#define  CMD_RMT_LOOP_EN               (1 << 25)
+#define  CMD_PRBL_EN                   (1 << 27)
+#define  CMD_TX_PAUSE_IGNORE           (1 << 28)
+#define  CMD_TX_RX_EN                  (1 << 29)
+#define  CMD_RUNT_FILTER_DIS           (1 << 30)
+
+#define UMAC_MAC0                      0x00C
+#define UMAC_MAC1                      0x010
+#define UMAC_MAX_FRAME_LEN             0x014
+
+#define UMAC_TX_FLUSH                  0x334
+
+#define UMAC_MIB_START                 0x400
+
+#define UMAC_MDIO_CMD                  0x614
+#define  MDIO_START_BUSY               (1 << 29)
+#define  MDIO_READ_FAIL                        (1 << 28)
+#define  MDIO_RD                       (2 << 26)
+#define  MDIO_WR                       (1 << 26)
+#define  MDIO_PMD_SHIFT                        21
+#define  MDIO_PMD_MASK                 0x1F
+#define  MDIO_REG_SHIFT                        16
+#define  MDIO_REG_MASK                 0x1F
+
+#define UMAC_RBUF_OVFL_CNT             0x61C
+
+#define UMAC_MPD_CTRL                  0x620
+#define  MPD_EN                                (1 << 0)
+#define  MPD_PW_EN                     (1 << 27)
+#define  MPD_MSEQ_LEN_SHIFT            16
+#define  MPD_MSEQ_LEN_MASK             0xFF
+
+#define UMAC_MPD_PW_MS                 0x624
+#define UMAC_MPD_PW_LS                 0x628
+#define UMAC_RBUF_ERR_CNT              0x634
+#define UMAC_MDF_ERR_CNT               0x638
+#define UMAC_MDF_CTRL                  0x650
+#define UMAC_MDF_ADDR                  0x654
+#define UMAC_MIB_CTRL                  0x580
+#define  MIB_RESET_RX                  (1 << 0)
+#define  MIB_RESET_RUNT                        (1 << 1)
+#define  MIB_RESET_TX                  (1 << 2)
+
+#define RBUF_CTRL                      0x00
+#define  RBUF_64B_EN                   (1 << 0)
+#define  RBUF_ALIGN_2B                 (1 << 1)
+#define  RBUF_BAD_DIS                  (1 << 2)
+
+#define RBUF_STATUS                    0x0C
+#define  RBUF_STATUS_WOL               (1 << 0)
+#define  RBUF_STATUS_MPD_INTR_ACTIVE   (1 << 1)
+#define  RBUF_STATUS_ACPI_INTR_ACTIVE  (1 << 2)
+
+#define RBUF_CHK_CTRL                  0x14
+#define  RBUF_RXCHK_EN                 (1 << 0)
+#define  RBUF_SKIP_FCS                 (1 << 4)
+
+#define RBUF_TBUF_SIZE_CTRL            0xb4
+
+#define RBUF_HFB_CTRL_V1               0x38
+#define  RBUF_HFB_FILTER_EN_SHIFT      16
+#define  RBUF_HFB_FILTER_EN_MASK       0xffff0000
+#define  RBUF_HFB_EN                   (1 << 0)
+#define  RBUF_HFB_256B                 (1 << 1)
+#define  RBUF_ACPI_EN                  (1 << 2)
+
+#define RBUF_HFB_LEN_V1                        0x3C
+#define  RBUF_FLTR_LEN_MASK            0xFF
+#define  RBUF_FLTR_LEN_SHIFT           8
+
+#define TBUF_CTRL                      0x00
+#define TBUF_BP_MC                     0x0C
+
+#define TBUF_CTRL_V1                   0x80
+#define TBUF_BP_MC_V1                  0xA0
+
+#define HFB_CTRL                       0x00
+#define HFB_FLT_ENABLE_V3PLUS          0x04
+#define HFB_FLT_LEN_V2                 0x04
+#define HFB_FLT_LEN_V3PLUS             0x1C
+
+/* uniMac intrl2 registers */
+#define INTRL2_CPU_STAT                        0x00
+#define INTRL2_CPU_SET                 0x04
+#define INTRL2_CPU_CLEAR               0x08
+#define INTRL2_CPU_MASK_STATUS         0x0C
+#define INTRL2_CPU_MASK_SET            0x10
+#define INTRL2_CPU_MASK_CLEAR          0x14
+
+/* INTRL2 instance 0 definitions */
+#define UMAC_IRQ_SCB                   (1 << 0)
+#define UMAC_IRQ_EPHY                  (1 << 1)
+#define UMAC_IRQ_PHY_DET_R             (1 << 2)
+#define UMAC_IRQ_PHY_DET_F             (1 << 3)
+#define UMAC_IRQ_LINK_UP               (1 << 4)
+#define UMAC_IRQ_LINK_DOWN             (1 << 5)
+#define UMAC_IRQ_UMAC                  (1 << 6)
+#define UMAC_IRQ_UMAC_TSV              (1 << 7)
+#define UMAC_IRQ_TBUF_UNDERRUN         (1 << 8)
+#define UMAC_IRQ_RBUF_OVERFLOW         (1 << 9)
+#define UMAC_IRQ_HFB_SM                        (1 << 10)
+#define UMAC_IRQ_HFB_MM                        (1 << 11)
+#define UMAC_IRQ_MPD_R                 (1 << 12)
+#define UMAC_IRQ_RXDMA_MBDONE          (1 << 13)
+#define UMAC_IRQ_RXDMA_PDONE           (1 << 14)
+#define UMAC_IRQ_RXDMA_BDONE           (1 << 15)
+#define UMAC_IRQ_TXDMA_MBDONE          (1 << 16)
+#define UMAC_IRQ_TXDMA_PDONE           (1 << 17)
+#define UMAC_IRQ_TXDMA_BDONE           (1 << 18)
+/* Only valid for GENETv3+ */
+#define UMAC_IRQ_MDIO_DONE             (1 << 23)
+#define UMAC_IRQ_MDIO_ERROR            (1 << 24)
+
+/* Register block offsets */
+#define GENET_SYS_OFF                  0x0000
+#define GENET_GR_BRIDGE_OFF            0x0040
+#define GENET_EXT_OFF                  0x0080
+#define GENET_INTRL2_0_OFF             0x0200
+#define GENET_INTRL2_1_OFF             0x0240
+#define GENET_RBUF_OFF                 0x0300
+#define GENET_UMAC_OFF                 0x0800
+
+/* SYS block offsets and register definitions */
+#define SYS_REV_CTRL                   0x00
+#define SYS_PORT_CTRL                  0x04
+#define  PORT_MODE_INT_EPHY            0
+#define  PORT_MODE_INT_GPHY            1
+#define  PORT_MODE_EXT_EPHY            2
+#define  PORT_MODE_EXT_GPHY            3
+#define  PORT_MODE_EXT_RVMII_25                (4 | BIT(4))
+#define  PORT_MODE_EXT_RVMII_50                4
+#define  LED_ACT_SOURCE_MAC            (1 << 9)
+
+#define SYS_RBUF_FLUSH_CTRL            0x08
+#define SYS_TBUF_FLUSH_CTRL            0x0C
+#define RBUF_FLUSH_CTRL_V1             0x04
+
+/* Ext block register offsets and definitions */
+#define EXT_EXT_PWR_MGMT               0x00
+#define  EXT_PWR_DOWN_BIAS             (1 << 0)
+#define  EXT_PWR_DOWN_DLL              (1 << 1)
+#define  EXT_PWR_DOWN_PHY              (1 << 2)
+#define  EXT_PWR_DN_EN_LD              (1 << 3)
+#define  EXT_ENERGY_DET                        (1 << 4)
+#define  EXT_IDDQ_FROM_PHY             (1 << 5)
+#define  EXT_PHY_RESET                 (1 << 8)
+#define  EXT_ENERGY_DET_MASK           (1 << 12)
+
+#define EXT_RGMII_OOB_CTRL             0x0C
+#define  RGMII_MODE_EN                 (1 << 0)
+#define  RGMII_LINK                    (1 << 4)
+#define  OOB_DISABLE                   (1 << 5)
+#define  ID_MODE_DIS                   (1 << 16)
+
+#define EXT_GPHY_CTRL                  0x1C
+#define  EXT_CFG_IDDQ_BIAS             (1 << 0)
+#define  EXT_CFG_PWR_DOWN              (1 << 1)
+#define  EXT_GPHY_RESET                        (1 << 5)
+
+/* DMA rings size */
+#define DMA_RING_SIZE                  (0x40)
+#define DMA_RINGS_SIZE                 (DMA_RING_SIZE * (DESC_INDEX + 1))
+
+/* DMA registers common definitions */
+#define DMA_RW_POINTER_MASK            0x1FF
+#define DMA_P_INDEX_DISCARD_CNT_MASK   0xFFFF
+#define DMA_P_INDEX_DISCARD_CNT_SHIFT  16
+#define DMA_BUFFER_DONE_CNT_MASK       0xFFFF
+#define DMA_BUFFER_DONE_CNT_SHIFT      16
+#define DMA_P_INDEX_MASK               0xFFFF
+#define DMA_C_INDEX_MASK               0xFFFF
+
+/* DMA ring size register */
+#define DMA_RING_SIZE_MASK             0xFFFF
+#define DMA_RING_SIZE_SHIFT            16
+#define DMA_RING_BUFFER_SIZE_MASK      0xFFFF
+
+/* DMA interrupt threshold register */
+#define DMA_INTR_THRESHOLD_MASK                0x00FF
+
+/* DMA XON/XOFF register */
+#define DMA_XON_THREHOLD_MASK          0xFFFF
+#define DMA_XOFF_THRESHOLD_MASK                0xFFFF
+#define DMA_XOFF_THRESHOLD_SHIFT       16
+
+/* DMA flow period register */
+#define DMA_FLOW_PERIOD_MASK           0xFFFF
+#define DMA_MAX_PKT_SIZE_MASK          0xFFFF
+#define DMA_MAX_PKT_SIZE_SHIFT         16
+
+
+/* DMA control register */
+#define DMA_EN                         (1 << 0)
+#define DMA_RING_BUF_EN_SHIFT          0x01
+#define DMA_RING_BUF_EN_MASK           0xFFFF
+#define DMA_TSB_SWAP_EN                        (1 << 20)
+
+/* DMA status register */
+#define DMA_DISABLED                   (1 << 0)
+#define DMA_DESC_RAM_INIT_BUSY         (1 << 1)
+
+/* DMA SCB burst size register */
+#define DMA_SCB_BURST_SIZE_MASK                0x1F
+
+/* DMA activity vector register */
+#define DMA_ACTIVITY_VECTOR_MASK       0x1FFFF
+
+/* DMA backpressure mask register */
+#define DMA_BACKPRESSURE_MASK          0x1FFFF
+#define DMA_PFC_ENABLE                 (1 << 31)
+
+/* DMA backpressure status register */
+#define DMA_BACKPRESSURE_STATUS_MASK   0x1FFFF
+
+/* DMA override register */
+#define DMA_LITTLE_ENDIAN_MODE         (1 << 0)
+#define DMA_REGISTER_MODE              (1 << 1)
+
+/* DMA timeout register */
+#define DMA_TIMEOUT_MASK               0xFFFF
+#define DMA_TIMEOUT_VAL                        5000    /* micro seconds */
+
+/* TDMA rate limiting control register */
+#define DMA_RATE_LIMIT_EN_MASK         0xFFFF
+
+/* TDMA arbitration control register */
+#define DMA_ARBITER_MODE_MASK          0x03
+#define DMA_RING_BUF_PRIORITY_MASK     0x1F
+#define DMA_RING_BUF_PRIORITY_SHIFT    5
+#define DMA_RATE_ADJ_MASK              0xFF
+
+/* Tx/Rx Dma Descriptor common bits*/
+#define DMA_BUFLENGTH_MASK             0x0fff
+#define DMA_BUFLENGTH_SHIFT            16
+#define DMA_OWN                                0x8000
+#define DMA_EOP                                0x4000
+#define DMA_SOP                                0x2000
+#define DMA_WRAP                       0x1000
+/* Tx specific Dma descriptor bits */
+#define DMA_TX_UNDERRUN                        0x0200
+#define DMA_TX_APPEND_CRC              0x0040
+#define DMA_TX_OW_CRC                  0x0020
+#define DMA_TX_DO_CSUM                 0x0010
+#define DMA_TX_QTAG_SHIFT              7
+
+/* Rx Specific Dma descriptor bits */
+#define DMA_RX_CHK_V3PLUS              0x8000
+#define DMA_RX_CHK_V12                 0x1000
+#define DMA_RX_BRDCAST                 0x0040
+#define DMA_RX_MULT                    0x0020
+#define DMA_RX_LG                      0x0010
+#define DMA_RX_NO                      0x0008
+#define DMA_RX_RXER                    0x0004
+#define DMA_RX_CRC_ERROR               0x0002
+#define DMA_RX_OV                      0x0001
+#define DMA_RX_FI_MASK                 0x001F
+#define DMA_RX_FI_SHIFT                        0x0007
+#define DMA_DESC_ALLOC_MASK            0x00FF
+
+#define DMA_ARBITER_RR                 0x00
+#define DMA_ARBITER_WRR                        0x01
+#define DMA_ARBITER_SP                 0x02
+
+struct enet_cb {
+       struct sk_buff      *skb;
+       void __iomem *bd_addr;
+       DEFINE_DMA_UNMAP_ADDR(dma_addr);
+       DEFINE_DMA_UNMAP_LEN(dma_len);
+};
+
+/* power management mode */
+enum bcmgenet_power_mode {
+       GENET_POWER_CABLE_SENSE = 0,
+       GENET_POWER_PASSIVE,
+};
+
+struct bcmgenet_priv;
+
+/* We support both runtime GENET detection and compile-time
+ * to optimize code-paths for a given hardware
+ */
+enum bcmgenet_version {
+       GENET_V1 = 1,
+       GENET_V2,
+       GENET_V3,
+       GENET_V4
+};
+
+#define GENET_IS_V1(p) ((p)->version == GENET_V1)
+#define GENET_IS_V2(p) ((p)->version == GENET_V2)
+#define GENET_IS_V3(p) ((p)->version == GENET_V3)
+#define GENET_IS_V4(p) ((p)->version == GENET_V4)
+
+/* Hardware flags */
+#define GENET_HAS_40BITS       (1 << 0)
+#define GENET_HAS_EXT          (1 << 1)
+#define GENET_HAS_MDIO_INTR    (1 << 2)
+
+/* BCMGENET hardware parameters, keep this structure nicely aligned
+ * since it is going to be used in hot paths
+ */
+struct bcmgenet_hw_params {
+       u8              tx_queues;
+       u8              rx_queues;
+       u8              bds_cnt;
+       u8              bp_in_en_shift;
+       u32             bp_in_mask;
+       u8              hfb_filter_cnt;
+       u8              qtag_mask;
+       u16             tbuf_offset;
+       u32             hfb_offset;
+       u32             hfb_reg_offset;
+       u32             rdma_offset;
+       u32             tdma_offset;
+       u32             words_per_bd;
+       u32             flags;
+};
+
+struct bcmgenet_tx_ring {
+       spinlock_t      lock;           /* ring lock */
+       unsigned int    index;          /* ring index */
+       unsigned int    queue;          /* queue index */
+       struct enet_cb  *cbs;           /* tx ring buffer control block*/
+       unsigned int    size;           /* size of each tx ring */
+       unsigned int    c_index;        /* last consumer index of each ring*/
+       unsigned int    free_bds;       /* # of free bds for each ring */
+       unsigned int    write_ptr;      /* Tx ring write pointer SW copy */
+       unsigned int    prod_index;     /* Tx ring producer index SW copy */
+       unsigned int    cb_ptr;         /* Tx ring initial CB ptr */
+       unsigned int    end_ptr;        /* Tx ring end CB ptr */
+       void (*int_enable)(struct bcmgenet_priv *priv,
+                               struct bcmgenet_tx_ring *);
+       void (*int_disable)(struct bcmgenet_priv *priv,
+                               struct bcmgenet_tx_ring *);
+};
+
+/* device context */
+struct bcmgenet_priv {
+       void __iomem *base;
+       enum bcmgenet_version version;
+       struct net_device *dev;
+       u32 int0_mask;
+       u32 int1_mask;
+
+       /* NAPI for descriptor based rx */
+       struct napi_struct napi ____cacheline_aligned;
+
+       /* transmit variables */
+       void __iomem *tx_bds;
+       struct enet_cb *tx_cbs;
+       unsigned int num_tx_bds;
+
+       struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1];
+
+       /* receive variables */
+       void __iomem *rx_bds;
+       void __iomem *rx_bd_assign_ptr;
+       int rx_bd_assign_index;
+       struct enet_cb *rx_cbs;
+       unsigned int num_rx_bds;
+       unsigned int rx_buf_len;
+       unsigned int rx_read_ptr;
+       unsigned int rx_c_index;
+
+       /* other misc variables */
+       struct bcmgenet_hw_params *hw_params;
+
+       /* MDIO bus variables */
+       wait_queue_head_t wq;
+       struct phy_device *phydev;
+       struct device_node *phy_dn;
+       struct mii_bus *mii_bus;
+
+       /* PHY device variables */
+       int old_duplex;
+       int old_link;
+       int old_pause;
+       phy_interface_t phy_interface;
+       int phy_addr;
+       int ext_phy;
+
+       /* Interrupt variables */
+       struct work_struct bcmgenet_irq_work;
+       int irq0;
+       int irq1;
+       unsigned int irq0_stat;
+       unsigned int irq1_stat;
+
+       /* HW descriptors/checksum variables */
+       bool desc_64b_en;
+       bool desc_rxchk_en;
+       bool crc_fwd_en;
+
+       unsigned int dma_rx_chk_bit;
+
+       u32 msg_enable;
+
+       struct clk *clk;
+       struct platform_device *pdev;
+
+       /* WOL */
+       unsigned long wol_enabled;
+       struct clk *clk_wol;
+       u32 wolopts;
+
+       struct bcmgenet_mib_counters mib;
+};
+
+#define GENET_IO_MACRO(name, offset)                                   \
+static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv,  \
+                                       u32 off)                        \
+{                                                                      \
+       return __raw_readl(priv->base + offset + off);                  \
+}                                                                      \
+static inline void bcmgenet_##name##_writel(struct bcmgenet_priv *priv,        \
+                                       u32 val, u32 off)               \
+{                                                                      \
+       __raw_writel(val, priv->base + offset + off);                   \
+}
+
+GENET_IO_MACRO(ext, GENET_EXT_OFF);
+GENET_IO_MACRO(umac, GENET_UMAC_OFF);
+GENET_IO_MACRO(sys, GENET_SYS_OFF);
+
+/* interrupt l2 registers accessors */
+GENET_IO_MACRO(intrl2_0, GENET_INTRL2_0_OFF);
+GENET_IO_MACRO(intrl2_1, GENET_INTRL2_1_OFF);
+
+/* HFB register accessors  */
+GENET_IO_MACRO(hfb, priv->hw_params->hfb_offset);
+
+/* GENET v2+ HFB control and filter len helpers */
+GENET_IO_MACRO(hfb_reg, priv->hw_params->hfb_reg_offset);
+
+/* RBUF register accessors */
+GENET_IO_MACRO(rbuf, GENET_RBUF_OFF);
+
+/* MDIO routines */
+int bcmgenet_mii_init(struct net_device *dev);
+int bcmgenet_mii_config(struct net_device *dev);
+void bcmgenet_mii_exit(struct net_device *dev);
+void bcmgenet_mii_reset(struct net_device *dev);
+
+#endif /* __BCMGENET_H__ */
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
new file mode 100644 (file)
index 0000000..4608673
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Broadcom GENET MDIO routines
+ *
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/brcmphy.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_mdio.h>
+
+#include "bcmgenet.h"
+
+/* read a value from the MII */
+static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location)
+{
+       int ret;
+       struct net_device *dev = bus->priv;
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       u32 reg;
+
+       bcmgenet_umac_writel(priv, (MDIO_RD | (phy_id << MDIO_PMD_SHIFT) |
+                       (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD);
+       /* Start MDIO transaction*/
+       reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
+       reg |= MDIO_START_BUSY;
+       bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
+       wait_event_timeout(priv->wq,
+                       !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD)
+                               & MDIO_START_BUSY),
+                       HZ / 100);
+       ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
+
+       if (ret & MDIO_READ_FAIL)
+               return -EIO;
+
+       return ret & 0xffff;
+}
+
+/* write a value to the MII */
+static int bcmgenet_mii_write(struct mii_bus *bus, int phy_id,
+                       int location, u16 val)
+{
+       struct net_device *dev = bus->priv;
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       u32 reg;
+
+       bcmgenet_umac_writel(priv, (MDIO_WR | (phy_id << MDIO_PMD_SHIFT) |
+                       (location << MDIO_REG_SHIFT) | (0xffff & val)),
+                       UMAC_MDIO_CMD);
+       reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD);
+       reg |= MDIO_START_BUSY;
+       bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD);
+       wait_event_timeout(priv->wq,
+                       !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) &
+                               MDIO_START_BUSY),
+                       HZ / 100);
+
+       return 0;
+}
+
+/* setup netdev link state when PHY link status change and
+ * update UMAC and RGMII block when link up
+ */
+static void bcmgenet_mii_setup(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       u32 reg, cmd_bits = 0;
+       unsigned int status_changed = 0;
+
+       if (priv->old_link != phydev->link) {
+               status_changed = 1;
+               priv->old_link = phydev->link;
+       }
+
+       if (phydev->link) {
+               /* program UMAC and RGMII block based on established link
+                * speed, pause, and duplex.
+                * the speed set in umac->cmd tell RGMII block which clock
+                * 25MHz(100Mbps)/125MHz(1Gbps) to use for transmit.
+                * receive clock is provided by PHY.
+                */
+               reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+               reg &= ~OOB_DISABLE;
+               reg |= RGMII_LINK;
+               bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
+
+               /* speed */
+               if (phydev->speed == SPEED_1000)
+                       cmd_bits = UMAC_SPEED_1000;
+               else if (phydev->speed == SPEED_100)
+                       cmd_bits = UMAC_SPEED_100;
+               else
+                       cmd_bits = UMAC_SPEED_10;
+               cmd_bits <<= CMD_SPEED_SHIFT;
+
+               if (priv->old_duplex != phydev->duplex) {
+                       status_changed = 1;
+                       priv->old_duplex = phydev->duplex;
+               }
+
+               /* duplex */
+               if (phydev->duplex != DUPLEX_FULL)
+                       cmd_bits |= CMD_HD_EN;
+
+               if (priv->old_pause != phydev->pause) {
+                       status_changed = 1;
+                       priv->old_pause = phydev->pause;
+               }
+
+               /* pause capability */
+               if (!phydev->pause)
+                       cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE;
+
+               reg = bcmgenet_umac_readl(priv, UMAC_CMD);
+               reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) |
+                              CMD_HD_EN |
+                              CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE);
+               reg |= cmd_bits;
+               bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+       }
+
+       if (status_changed)
+               phy_print_status(phydev);
+}
+
+void bcmgenet_mii_reset(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       if (priv->phydev) {
+               phy_init_hw(priv->phydev);
+               phy_start_aneg(priv->phydev);
+       }
+}
+
+static void bcmgenet_ephy_power_up(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       u32 reg = 0;
+
+       /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */
+       if (!GENET_IS_V4(priv))
+               return;
+
+       reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL);
+       reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN);
+       reg |= EXT_GPHY_RESET;
+       bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
+       mdelay(2);
+
+       reg &= ~EXT_GPHY_RESET;
+       bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL);
+       udelay(20);
+}
+
+static void bcmgenet_internal_phy_setup(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       u32 reg;
+
+       /* Power up EPHY */
+       bcmgenet_ephy_power_up(dev);
+       /* enable APD */
+       reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT);
+       reg |= EXT_PWR_DN_EN_LD;
+       bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT);
+       bcmgenet_mii_reset(dev);
+}
+
+static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv)
+{
+       u32 reg;
+
+       /* Speed settings are set in bcmgenet_mii_setup() */
+       reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL);
+       reg |= LED_ACT_SOURCE_MAC;
+       bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL);
+}
+
+int bcmgenet_mii_config(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       struct device *kdev = &priv->pdev->dev;
+       const char *phy_name = NULL;
+       u32 id_mode_dis = 0;
+       u32 port_ctrl;
+       u32 reg;
+
+       priv->ext_phy = !phy_is_internal(priv->phydev) &&
+                       (priv->phy_interface != PHY_INTERFACE_MODE_MOCA);
+
+       if (phy_is_internal(priv->phydev))
+               priv->phy_interface = PHY_INTERFACE_MODE_NA;
+
+       switch (priv->phy_interface) {
+       case PHY_INTERFACE_MODE_NA:
+       case PHY_INTERFACE_MODE_MOCA:
+               /* Irrespective of the actually configured PHY speed (100 or
+                * 1000) GENETv4 only has an internal GPHY so we will just end
+                * up masking the Gigabit features from what we support, not
+                * switching to the EPHY
+                */
+               if (GENET_IS_V4(priv))
+                       port_ctrl = PORT_MODE_INT_GPHY;
+               else
+                       port_ctrl = PORT_MODE_INT_EPHY;
+
+               bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
+
+               if (phy_is_internal(priv->phydev)) {
+                       phy_name = "internal PHY";
+                       bcmgenet_internal_phy_setup(dev);
+               } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) {
+                       phy_name = "MoCA";
+                       bcmgenet_moca_phy_setup(priv);
+               }
+               break;
+
+       case PHY_INTERFACE_MODE_MII:
+               phy_name = "external MII";
+               phydev->supported &= PHY_BASIC_FEATURES;
+               bcmgenet_sys_writel(priv,
+                               PORT_MODE_EXT_EPHY, SYS_PORT_CTRL);
+               break;
+
+       case PHY_INTERFACE_MODE_REVMII:
+               phy_name = "external RvMII";
+               /* of_mdiobus_register took care of reading the 'max-speed'
+                * PHY property for us, effectively limiting the PHY supported
+                * capabilities, use that knowledge to also configure the
+                * Reverse MII interface correctly.
+                */
+               if ((priv->phydev->supported & PHY_BASIC_FEATURES) ==
+                               PHY_BASIC_FEATURES)
+                       port_ctrl = PORT_MODE_EXT_RVMII_25;
+               else
+                       port_ctrl = PORT_MODE_EXT_RVMII_50;
+               bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL);
+               break;
+
+       case PHY_INTERFACE_MODE_RGMII:
+               /* RGMII_NO_ID: TXC transitions at the same time as TXD
+                *              (requires PCB or receiver-side delay)
+                * RGMII:       Add 2ns delay on TXC (90 degree shift)
+                *
+                * ID is implicitly disabled for 100Mbps (RG)MII operation.
+                */
+               id_mode_dis = BIT(16);
+               /* fall through */
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               if (id_mode_dis)
+                       phy_name = "external RGMII (no delay)";
+               else
+                       phy_name = "external RGMII (TX delay)";
+               reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL);
+               reg |= RGMII_MODE_EN | id_mode_dis;
+               bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL);
+               bcmgenet_sys_writel(priv,
+                               PORT_MODE_EXT_GPHY, SYS_PORT_CTRL);
+               break;
+       default:
+               dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface);
+               return -EINVAL;
+       }
+
+       dev_info(kdev, "configuring instance for %s\n", phy_name);
+
+       return 0;
+}
+
+static int bcmgenet_mii_probe(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       struct phy_device *phydev;
+       unsigned int phy_flags;
+       int ret;
+
+       if (priv->phydev) {
+               pr_info("PHY already attached\n");
+               return 0;
+       }
+
+       if (priv->phy_dn)
+               phydev = of_phy_connect(dev, priv->phy_dn,
+                                       bcmgenet_mii_setup, 0,
+                                       priv->phy_interface);
+       else
+               phydev = of_phy_connect_fixed_link(dev,
+                                       bcmgenet_mii_setup,
+                                       priv->phy_interface);
+
+       if (!phydev) {
+               pr_err("could not attach to PHY\n");
+               return -ENODEV;
+       }
+
+       priv->old_link = -1;
+       priv->old_duplex = -1;
+       priv->old_pause = -1;
+       priv->phydev = phydev;
+
+       /* Configure port multiplexer based on what the probed PHY device since
+        * reading the 'max-speed' property determines the maximum supported
+        * PHY speed which is needed for bcmgenet_mii_config() to configure
+        * things appropriately.
+        */
+       ret = bcmgenet_mii_config(dev);
+       if (ret) {
+               phy_disconnect(priv->phydev);
+               return ret;
+       }
+
+       phy_flags = PHY_BRCM_100MBPS_WAR;
+
+       /* workarounds are only needed for 100Mpbs PHYs, and
+        * never on GENET V1 hardware
+        */
+       if ((phydev->supported & PHY_GBIT_FEATURES) || GENET_IS_V1(priv))
+               phy_flags = 0;
+
+       phydev->dev_flags |= phy_flags;
+       phydev->advertising = phydev->supported;
+
+       /* The internal PHY has its link interrupts routed to the
+        * Ethernet MAC ISRs
+        */
+       if (phy_is_internal(priv->phydev))
+               priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT;
+       else
+               priv->mii_bus->irq[phydev->addr] = PHY_POLL;
+
+       pr_info("attached PHY at address %d [%s]\n",
+                       phydev->addr, phydev->drv->name);
+
+       return 0;
+}
+
+static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv)
+{
+       struct mii_bus *bus;
+
+       if (priv->mii_bus)
+               return 0;
+
+       priv->mii_bus = mdiobus_alloc();
+       if (!priv->mii_bus) {
+               pr_err("failed to allocate\n");
+               return -ENOMEM;
+       }
+
+       bus = priv->mii_bus;
+       bus->priv = priv->dev;
+       bus->name = "bcmgenet MII bus";
+       bus->parent = &priv->pdev->dev;
+       bus->read = bcmgenet_mii_read;
+       bus->write = bcmgenet_mii_write;
+       snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d",
+                       priv->pdev->name, priv->pdev->id);
+
+       bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (!bus->irq) {
+               mdiobus_free(priv->mii_bus);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv)
+{
+       struct device_node *dn = priv->pdev->dev.of_node;
+       struct device *kdev = &priv->pdev->dev;
+       struct device_node *mdio_dn;
+       char *compat;
+       int ret;
+
+       compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version);
+       if (!compat)
+               return -ENOMEM;
+
+       mdio_dn = of_find_compatible_node(dn, NULL, compat);
+       kfree(compat);
+       if (!mdio_dn) {
+               dev_err(kdev, "unable to find MDIO bus node\n");
+               return -ENODEV;
+       }
+
+       ret = of_mdiobus_register(priv->mii_bus, mdio_dn);
+       if (ret) {
+               dev_err(kdev, "failed to register MDIO bus\n");
+               return ret;
+       }
+
+       /* Fetch the PHY phandle */
+       priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0);
+
+       /* Get the link mode */
+       priv->phy_interface = of_get_phy_mode(dn);
+
+       return 0;
+}
+
+int bcmgenet_mii_init(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+       int ret;
+
+       ret = bcmgenet_mii_alloc(priv);
+       if (ret)
+               return ret;
+
+       ret = bcmgenet_mii_of_init(priv);
+       if (ret)
+               goto out_free;
+
+       ret = bcmgenet_mii_probe(dev);
+       if (ret)
+               goto out;
+
+       return 0;
+
+out:
+       mdiobus_unregister(priv->mii_bus);
+out_free:
+       kfree(priv->mii_bus->irq);
+       mdiobus_free(priv->mii_bus);
+       return ret;
+}
+
+void bcmgenet_mii_exit(struct net_device *dev)
+{
+       struct bcmgenet_priv *priv = netdev_priv(dev);
+
+       mdiobus_unregister(priv->mii_bus);
+       kfree(priv->mii_bus->irq);
+       mdiobus_free(priv->mii_bus);
+}
index e2ca03e23dc1f7542c43d9f82b1fdd6ba9d0a5fe..b9f7022f4e81e13a38c31a4f53653f2c77a0f4db 100644 (file)
@@ -1401,11 +1401,6 @@ static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
        return ret;
 }
 
-static int tg3_mdio_reset(struct mii_bus *bp)
-{
-       return 0;
-}
-
 static void tg3_mdio_config_5785(struct tg3 *tp)
 {
        u32 val;
@@ -1542,7 +1537,6 @@ static int tg3_mdio_init(struct tg3 *tp)
        tp->mdio_bus->parent   = &tp->pdev->dev;
        tp->mdio_bus->read     = &tg3_mdio_read;
        tp->mdio_bus->write    = &tg3_mdio_write;
-       tp->mdio_bus->reset    = &tg3_mdio_reset;
        tp->mdio_bus->phy_mask = ~(1 << tp->phy_addr);
        tp->mdio_bus->irq      = &tp->mdio_irq[0];
 
@@ -2609,13 +2603,14 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
 
        tg3_writephy(tp, MII_CTRL1000, phy9_orig);
 
-       if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32)) {
-               reg32 &= ~0x3000;
-               tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
-       } else if (!err)
-               err = -EBUSY;
+       err = tg3_readphy(tp, MII_TG3_EXT_CTRL, &reg32);
+       if (err)
+               return err;
 
-       return err;
+       reg32 &= ~0x3000;
+       tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+
+       return 0;
 }
 
 static void tg3_carrier_off(struct tg3 *tp)
@@ -6321,6 +6316,7 @@ static const struct ptp_clock_info tg3_ptp_caps = {
        .n_alarm        = 0,
        .n_ext_ts       = 0,
        .n_per_out      = 1,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = tg3_ptp_adjfreq,
        .adjtime        = tg3_ptp_adjtime,
@@ -6592,7 +6588,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
                pkts_compl++;
                bytes_compl += skb->len;
 
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
 
                if (unlikely(tx_bug)) {
                        tg3_tx_recover(tp);
@@ -6842,8 +6838,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 
                work_mask |= opaque_key;
 
-               if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
-                   (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) {
+               if (desc->err_vlan & RXD_ERR_MASK) {
                drop_it:
                        tg3_recycle_rx(tnapi, tpr, opaque_key,
                                       desc_idx, *post_ptr);
@@ -6924,7 +6919,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
 
                if (len > (tp->dev->mtu + ETH_HLEN) &&
                    skb->protocol != htons(ETH_P_8021Q)) {
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        goto drop_it_no_recycle;
                }
 
@@ -7807,7 +7802,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                                          PCI_DMA_TODEVICE);
                /* Make sure the mapping succeeded */
                if (pci_dma_mapping_error(tp->pdev, new_addr)) {
-                       dev_kfree_skb(new_skb);
+                       dev_kfree_skb_any(new_skb);
                        ret = -1;
                } else {
                        u32 save_entry = *entry;
@@ -7822,13 +7817,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
                                            new_skb->len, base_flags,
                                            mss, vlan)) {
                                tg3_tx_skb_unmap(tnapi, save_entry, -1);
-                               dev_kfree_skb(new_skb);
+                               dev_kfree_skb_any(new_skb);
                                ret = -1;
                        }
                }
        }
 
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        *pskb = new_skb;
        return ret;
 }
@@ -7871,7 +7866,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
        } while (segs);
 
 tg3_tso_bug_end:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -7923,8 +7918,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
                struct iphdr *iph;
                u32 tcp_opt_len, hdr_len;
 
-               if (skb_header_cloned(skb) &&
-                   pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+               if (skb_cow_head(skb, 0))
                        goto drop;
 
                iph = ip_hdr(skb);
@@ -8093,7 +8087,7 @@ dma_error:
        tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i);
        tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
 drop:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 drop_nofree:
        tp->tx_dropped++;
        return NETDEV_TX_OK;
@@ -11361,12 +11355,10 @@ static bool tg3_enable_msix(struct tg3 *tp)
                msix_ent[i].vector = 0;
        }
 
-       rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt);
+       rc = pci_enable_msix_range(tp->pdev, msix_ent, 1, tp->irq_cnt);
        if (rc < 0) {
                return false;
-       } else if (rc != 0) {
-               if (pci_enable_msix(tp->pdev, msix_ent, rc))
-                       return false;
+       } else if (rc < tp->irq_cnt) {
                netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n",
                              tp->irq_cnt, rc);
                tp->irq_cnt = rc;
@@ -14113,12 +14105,12 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_netif_stop(tp);
 
+       tg3_set_mtu(dev, tp, new_mtu);
+
        tg3_full_lock(tp, 1);
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 
-       tg3_set_mtu(dev, tp, new_mtu);
-
        /* Reset PHY, otherwise the read DMA engine will be in a mode that
         * breaks all requests to 256 bytes.
         */
@@ -17649,8 +17641,6 @@ static int tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_bufmgr_config(tp);
 
-       features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
-
        /* 5700 B0 chips do not support checksumming correctly due
         * to hardware bugs.
         */
@@ -17682,7 +17672,8 @@ static int tg3_init_one(struct pci_dev *pdev,
                        features |= NETIF_F_TSO_ECN;
        }
 
-       dev->features |= features;
+       dev->features |= features | NETIF_F_HW_VLAN_CTAG_TX |
+                        NETIF_F_HW_VLAN_CTAG_RX;
        dev->vlan_features |= features;
 
        /*
index ef472385bce47dcea87f43e48f202ffabbddf16d..04321e5a356e45a0f7fc642f3817035d983dbd90 100644 (file)
@@ -2608,7 +2608,11 @@ struct tg3_rx_buffer_desc {
 #define RXD_ERR_TOO_SMALL              0x00400000
 #define RXD_ERR_NO_RESOURCES           0x00800000
 #define RXD_ERR_HUGE_FRAME             0x01000000
-#define RXD_ERR_MASK                   0xffff0000
+
+#define RXD_ERR_MASK   (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION |          \
+                        RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE |       \
+                        RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL |         \
+                        RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME)
 
        u32                             reserved;
        u32                             opaque;
index 1803c39590442d497d1cc7f543ef8148ac7e56ec..354ae9792badb329e89b0ab37f59ff78c73efd11 100644 (file)
@@ -1704,7 +1704,7 @@ bfa_flash_sem_get(void __iomem *bar)
        while (!bfa_raw_sem_get(bar)) {
                if (--n <= 0)
                        return BFA_STATUS_BADFLASH;
-               udelay(10000);
+               mdelay(10);
        }
        return BFA_STATUS_OK;
 }
index cf64f3d0b60d91a1de68836523c6304086dc9ece..675550fe8ee90dfe7f2c704787d7b900107f06d4 100644 (file)
@@ -707,7 +707,8 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget)
                else
                        skb_checksum_none_assert(skb);
 
-               if (flags & BNA_CQ_EF_VLAN)
+               if ((flags & BNA_CQ_EF_VLAN) &&
+                   (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX))
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag));
 
                if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type))
@@ -2094,7 +2095,9 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config)
                rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE;
        }
 
-       rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED;
+       rx_config->vlan_strip_status =
+               (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ?
+               BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED;
 }
 
 static void
@@ -2493,12 +2496,10 @@ bnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb)
 {
        int err;
 
-       if (skb_header_cloned(skb)) {
-               err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-               if (err) {
-                       BNAD_UPDATE_CTR(bnad, tso_err);
-                       return err;
-               }
+       err = skb_cow_head(skb, 0);
+       if (err < 0) {
+               BNAD_UPDATE_CTR(bnad, tso_err);
+               return err;
        }
 
        /*
@@ -2666,9 +2667,11 @@ bnad_enable_msix(struct bnad *bnad)
        for (i = 0; i < bnad->msix_num; i++)
                bnad->msix_table[i].entry = i;
 
-       ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num);
-       if (ret > 0) {
-               /* Not enough MSI-X vectors. */
+       ret = pci_enable_msix_range(bnad->pcidev, bnad->msix_table,
+                                   1, bnad->msix_num);
+       if (ret < 0) {
+               goto intx_mode;
+       } else if (ret < bnad->msix_num) {
                pr_warn("BNA: %d MSI-X vectors allocated < %d requested\n",
                        ret, bnad->msix_num);
 
@@ -2681,18 +2684,11 @@ bnad_enable_msix(struct bnad *bnad)
                bnad->msix_num = BNAD_NUM_TXQ + BNAD_NUM_RXP +
                         BNAD_MAILBOX_MSIX_VECTORS;
 
-               if (bnad->msix_num > ret)
+               if (bnad->msix_num > ret) {
+                       pci_disable_msix(bnad->pcidev);
                        goto intx_mode;
-
-               /* Try once more with adjusted numbers */
-               /* If this fails, fall back to INTx */
-               ret = pci_enable_msix(bnad->pcidev, bnad->msix_table,
-                                     bnad->msix_num);
-               if (ret)
-                       goto intx_mode;
-
-       } else if (ret < 0)
-               goto intx_mode;
+               }
+       }
 
        pci_intx(bnad->pcidev, 0);
 
@@ -2847,13 +2843,11 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                }
                if (unlikely((gso_size + skb_transport_offset(skb) +
                              tcp_hdrlen(skb)) >= skb->len)) {
-                       txqent->hdr.wi.opcode =
-                               __constant_htons(BNA_TXQ_WI_SEND);
+                       txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
                        txqent->hdr.wi.lso_mss = 0;
                        BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short);
                } else {
-                       txqent->hdr.wi.opcode =
-                               __constant_htons(BNA_TXQ_WI_SEND_LSO);
+                       txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO);
                        txqent->hdr.wi.lso_mss = htons(gso_size);
                }
 
@@ -2867,7 +2861,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                        htons(BNA_TXQ_WI_L4_HDR_N_OFFSET(
                        tcp_hdrlen(skb) >> 2, skb_transport_offset(skb)));
        } else  {
-               txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND);
+               txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND);
                txqent->hdr.wi.lso_mss = 0;
 
                if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) {
@@ -2878,11 +2872,10 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        u8 proto = 0;
 
-                       if (skb->protocol == __constant_htons(ETH_P_IP))
+                       if (skb->protocol == htons(ETH_P_IP))
                                proto = ip_hdr(skb)->protocol;
 #ifdef NETIF_F_IPV6_CSUM
-                       else if (skb->protocol ==
-                                __constant_htons(ETH_P_IPV6)) {
+                       else if (skb->protocol == htons(ETH_P_IPV6)) {
                                /* nexthdr may not be TCP immediately. */
                                proto = ipv6_hdr(skb)->nexthdr;
                        }
@@ -2951,17 +2944,17 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        /* Sanity checks for the skb */
 
        if (unlikely(skb->len <= ETH_HLEN)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                BNAD_UPDATE_CTR(bnad, tx_skb_too_short);
                return NETDEV_TX_OK;
        }
        if (unlikely(len > BFI_TX_MAX_DATA_PER_VECTOR)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
                return NETDEV_TX_OK;
        }
        if (unlikely(len == 0)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero);
                return NETDEV_TX_OK;
        }
@@ -2973,7 +2966,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
         * and the netif_tx_stop_all_queues() call.
         */
        if (unlikely(!tcb || !test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                BNAD_UPDATE_CTR(bnad, tx_skb_stopping);
                return NETDEV_TX_OK;
        }
@@ -2986,7 +2979,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        wis = BNA_TXQ_WI_NEEDED(vectors);       /* 4 vectors per work item */
 
        if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors);
                return NETDEV_TX_OK;
        }
@@ -3026,7 +3019,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
        /* Program the opcode, flags, frame_len, num_vectors in WI */
        if (bnad_txq_wi_prepare(bnad, tcb, skb, txqent)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
        txqent->hdr.wi.reserved = 0;
@@ -3052,7 +3045,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                        /* Undo the changes starting at tcb->producer_index */
                        bnad_tx_buff_unmap(bnad, unmap_q, q_depth,
                                tcb->producer_index);
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero);
                        return NETDEV_TX_OK;
                }
@@ -3064,8 +3057,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                        vect_id = 0;
                        BNA_QE_INDX_INC(prod, q_depth);
                        txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod];
-                       txqent->hdr.wi_ext.opcode =
-                               __constant_htons(BNA_TXQ_WI_EXTENSION);
+                       txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION);
                        unmap = &unmap_q[prod];
                }
 
@@ -3082,7 +3074,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        if (unlikely(len != skb->len)) {
                /* Undo the changes starting at tcb->producer_index */
                bnad_tx_buff_unmap(bnad, unmap_q, q_depth, tcb->producer_index);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch);
                return NETDEV_TX_OK;
        }
@@ -3245,11 +3237,6 @@ bnad_set_rx_mode(struct net_device *netdev)
                        BNA_RXMODE_ALLMULTI;
        bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL);
 
-       if (bnad->cfg_flags & BNAD_CF_PROMISC)
-               bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
-       else
-               bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
-
        spin_unlock_irqrestore(&bnad->bna_lock, flags);
 }
 
@@ -3374,6 +3361,27 @@ bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
        return 0;
 }
 
+static int bnad_set_features(struct net_device *dev, netdev_features_t features)
+{
+       struct bnad *bnad = netdev_priv(dev);
+       netdev_features_t changed = features ^ dev->features;
+
+       if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&bnad->bna_lock, flags);
+
+               if (features & NETIF_F_HW_VLAN_CTAG_RX)
+                       bna_rx_vlan_strip_enable(bnad->rx_info[0].rx);
+               else
+                       bna_rx_vlan_strip_disable(bnad->rx_info[0].rx);
+
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void
 bnad_netpoll(struct net_device *netdev)
@@ -3421,6 +3429,7 @@ static const struct net_device_ops bnad_netdev_ops = {
        .ndo_change_mtu         = bnad_change_mtu,
        .ndo_vlan_rx_add_vid    = bnad_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = bnad_vlan_rx_kill_vid,
+       .ndo_set_features       = bnad_set_features,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = bnad_netpoll
 #endif
@@ -3433,14 +3442,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
 
        netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX;
+               NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX |
+               NETIF_F_HW_VLAN_CTAG_RX;
 
        netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                NETIF_F_TSO | NETIF_F_TSO6;
 
-       netdev->features |= netdev->hw_features |
-               NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER;
+       netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER;
 
        if (using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
index 3190d38e16fbd5d59a8cbc0cca7378a500572402..ca97005e24b41217849beaf4b9a578fbaf1f2027 100644 (file)
@@ -199,11 +199,6 @@ static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        return 0;
 }
 
-static int macb_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 /**
  * macb_set_tx_clk() - Set a clock to a new frequency
  * @clk                Pointer to the clock to change
@@ -375,7 +370,6 @@ int macb_mii_init(struct macb *bp)
        bp->mii_bus->name = "MACB_mii_bus";
        bp->mii_bus->read = &macb_mdio_read;
        bp->mii_bus->write = &macb_mdio_write;
-       bp->mii_bus->reset = &macb_mdio_reset;
        snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                bp->pdev->name, bp->pdev->id);
        bp->mii_bus->priv = bp;
@@ -632,11 +626,16 @@ static void gem_rx_refill(struct macb *bp)
                                           "Unable to allocate sk_buff\n");
                                break;
                        }
-                       bp->rx_skbuff[entry] = skb;
 
                        /* now fill corresponding descriptor entry */
                        paddr = dma_map_single(&bp->pdev->dev, skb->data,
                                               bp->rx_buffer_size, DMA_FROM_DEVICE);
+                       if (dma_mapping_error(&bp->pdev->dev, paddr)) {
+                               dev_kfree_skb(skb);
+                               break;
+                       }
+
+                       bp->rx_skbuff[entry] = skb;
 
                        if (entry == RX_RING_SIZE - 1)
                                paddr |= MACB_BIT(RX_WRAP);
@@ -725,7 +724,7 @@ static int gem_rx(struct macb *bp, int budget)
                skb_put(skb, len);
                addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, addr));
                dma_unmap_single(&bp->pdev->dev, addr,
-                                len, DMA_FROM_DEVICE);
+                                bp->rx_buffer_size, DMA_FROM_DEVICE);
 
                skb->protocol = eth_type_trans(skb, bp->dev);
                skb_checksum_none_assert(skb);
@@ -1036,11 +1035,15 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        entry = macb_tx_ring_wrap(bp->tx_head);
-       bp->tx_head++;
        netdev_vdbg(bp->dev, "Allocated ring entry %u\n", entry);
        mapping = dma_map_single(&bp->pdev->dev, skb->data,
                                 len, DMA_TO_DEVICE);
+       if (dma_mapping_error(&bp->pdev->dev, mapping)) {
+               dev_kfree_skb_any(skb);
+               goto unlock;
+       }
 
+       bp->tx_head++;
        tx_skb = &bp->tx_skb[entry];
        tx_skb->skb = skb;
        tx_skb->mapping = mapping;
@@ -1066,6 +1069,7 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (CIRC_SPACE(bp->tx_head, bp->tx_tail, TX_RING_SIZE) < 1)
                netif_stop_queue(dev);
 
+unlock:
        spin_unlock_irqrestore(&bp->lock, flags);
 
        return NETDEV_TX_OK;
index d2a183c3a6cedeb4db48812c900afe8de49f05b4..521dfea44b837d57bc7a7297ac973cd4d8098d3e 100644 (file)
@@ -897,7 +897,7 @@ static void xgmac_tx_complete(struct xgmac_priv *priv)
                /* Check tx error on the last segment */
                if (desc_get_tx_ls(p)) {
                        desc_get_tx_status(priv, p);
-                       dev_kfree_skb(skb);
+                       dev_consume_skb_any(skb);
                }
 
                priv->tx_skbuff[entry] = NULL;
@@ -1105,7 +1105,7 @@ static netdev_tx_t xgmac_xmit(struct sk_buff *skb, struct net_device *dev)
        len = skb_headlen(skb);
        paddr = dma_map_single(priv->device, skb->data, len, DMA_TO_DEVICE);
        if (dma_mapping_error(priv->device, paddr)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
        priv->tx_skbuff[entry] = skb;
@@ -1169,7 +1169,7 @@ dma_err:
        desc = first;
        dma_unmap_single(priv->device, desc_get_buf_addr(desc),
                         desc_get_buf_len(desc), DMA_TO_DEVICE);
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
index 45d77334d7d9a6c1a053be81599edcbf8b74c3b7..07bbb711b7e5a716aba3e8d2e3e958e2ce8fa506 100644 (file)
@@ -3088,30 +3088,22 @@ static int cxgb_enable_msix(struct adapter *adap)
 {
        struct msix_entry entries[SGE_QSETS + 1];
        int vectors;
-       int i, err;
+       int i;
 
        vectors = ARRAY_SIZE(entries);
        for (i = 0; i < vectors; ++i)
                entries[i].entry = i;
 
-       while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0)
-               vectors = err;
-
-       if (err < 0)
-               pci_disable_msix(adap->pdev);
-
-       if (!err && vectors < (adap->params.nports + 1)) {
-               pci_disable_msix(adap->pdev);
-               err = -1;
-       }
+       vectors = pci_enable_msix_range(adap->pdev, entries,
+                                       adap->params.nports + 1, vectors);
+       if (vectors < 0)
+               return vectors;
 
-       if (!err) {
-               for (i = 0; i < vectors; ++i)
-                       adap->msix_info[i].vec = entries[i].vector;
-               adap->msix_nvectors = vectors;
-       }
+       for (i = 0; i < vectors; ++i)
+               adap->msix_info[i].vec = entries[i].vector;
+       adap->msix_nvectors = vectors;
 
-       return err;
+       return 0;
 }
 
 static void print_port_info(struct adapter *adap, const struct adapter_info *ai)
index 632b318eb38a5852a77e94cb86f19e3a094ae774..8b069f96e920e4dec0e2c28cb197747ea56438c5 100644 (file)
@@ -298,7 +298,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
                        if (need_unmap)
                                unmap_skb(d->skb, q, cidx, pdev);
                        if (d->eop) {
-                               kfree_skb(d->skb);
+                               dev_consume_skb_any(d->skb);
                                d->skb = NULL;
                        }
                }
@@ -1188,7 +1188,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
                        cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
                                              V_WR_TID(q->token));
                        wr_gen2(d, gen);
-                       kfree_skb(skb);
+                       dev_consume_skb_any(skb);
                        return;
                }
 
@@ -1233,7 +1233,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
         * anything shorter than an Ethernet header.
         */
        if (unlikely(skb->len < ETH_HLEN)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index 1f4b9b30b9ed0bbaa969014e4bf6c1162d439d98..32db37709263bc14e596056bc7a9df80cc65bb62 100644 (file)
@@ -66,6 +66,7 @@ enum {
        SERNUM_LEN = 24,    /* Serial # length */
        EC_LEN     = 16,    /* E/C length */
        ID_LEN     = 16,    /* ID length */
+       PN_LEN     = 16,    /* Part Number length */
 };
 
 enum {
@@ -254,6 +255,7 @@ struct vpd_params {
        u8 ec[EC_LEN + 1];
        u8 sn[SERNUM_LEN + 1];
        u8 id[ID_LEN + 1];
+       u8 pn[PN_LEN + 1];
 };
 
 struct pci_params {
@@ -306,6 +308,7 @@ struct adapter_params {
        unsigned char bypass;
 
        unsigned int ofldq_wr_cred;
+       bool ulptx_memwrite_dsgl;          /* use of T5 DSGL allowed */
 };
 
 #include "t4fw_api.h"
@@ -497,6 +500,7 @@ struct sge_txq {
        spinlock_t db_lock;
        int db_disabled;
        unsigned short db_pidx;
+       unsigned short db_pidx_inc;
        u64 udb;
 };
 
@@ -553,8 +557,13 @@ struct sge {
        u32 pktshift;               /* padding between CPL & packet data */
        u32 fl_align;               /* response queue message alignment */
        u32 fl_starve_thres;        /* Free List starvation threshold */
-       unsigned int starve_thres;
-       u8 idma_state[2];
+
+       /* State variables for detecting an SGE Ingress DMA hang */
+       unsigned int idma_1s_thresh;/* SGE same State Counter 1s threshold */
+       unsigned int idma_stalled[2];/* SGE synthesized stalled timers in HZ */
+       unsigned int idma_state[2]; /* SGE IDMA Hang detect state */
+       unsigned int idma_qid[2];   /* SGE IDMA Hung Ingress Queue ID */
+
        unsigned int egr_start;
        unsigned int ingr_start;
        void *egr_map[MAX_EGRQ];    /* qid->queue egress queue map */
@@ -957,7 +966,7 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
               u64 *parity);
 int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
                u64 *parity);
-
+const char *t4_get_port_type_description(enum fw_port_type port_type);
 void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
 void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
 void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
@@ -1029,4 +1038,5 @@ void t4_db_dropped(struct adapter *adapter);
 int t4_mem_win_read_len(struct adapter *adap, u32 addr, __be32 *data, int len);
 int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox,
                         u32 addr, u32 val);
+void t4_sge_decode_idma_state(struct adapter *adapter, int state);
 #endif /* __CXGB4_H__ */
index 43ab35fea48d2be9fe6dfcd4d1e9dc10651724be..6fe58913403ab24f61ddf7f7e8d02714e040d250 100644 (file)
@@ -254,6 +254,14 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
        CH_DEVICE(0x5011, 4),
        CH_DEVICE(0x5012, 4),
        CH_DEVICE(0x5013, 4),
+       CH_DEVICE(0x5014, 4),
+       CH_DEVICE(0x5015, 4),
+       CH_DEVICE(0x5080, 4),
+       CH_DEVICE(0x5081, 4),
+       CH_DEVICE(0x5082, 4),
+       CH_DEVICE(0x5083, 4),
+       CH_DEVICE(0x5084, 4),
+       CH_DEVICE(0x5085, 4),
        CH_DEVICE(0x5401, 4),
        CH_DEVICE(0x5402, 4),
        CH_DEVICE(0x5403, 4),
@@ -273,6 +281,14 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = {
        CH_DEVICE(0x5411, 4),
        CH_DEVICE(0x5412, 4),
        CH_DEVICE(0x5413, 4),
+       CH_DEVICE(0x5414, 4),
+       CH_DEVICE(0x5415, 4),
+       CH_DEVICE(0x5480, 4),
+       CH_DEVICE(0x5481, 4),
+       CH_DEVICE(0x5482, 4),
+       CH_DEVICE(0x5483, 4),
+       CH_DEVICE(0x5484, 4),
+       CH_DEVICE(0x5485, 4),
        { 0, }
 };
 
@@ -423,15 +439,18 @@ static void link_report(struct net_device *dev)
                const struct port_info *p = netdev_priv(dev);
 
                switch (p->link_cfg.speed) {
-               case SPEED_10000:
+               case 10000:
                        s = "10Gbps";
                        break;
-               case SPEED_1000:
+               case 1000:
                        s = "1000Mbps";
                        break;
-               case SPEED_100:
+               case 100:
                        s = "100Mbps";
                        break;
+               case 40000:
+                       s = "40Gbps";
+                       break;
                }
 
                netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s,
@@ -2061,7 +2080,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
                0x40200, 0x40298,
                0x402ac, 0x4033c,
                0x403f8, 0x403fc,
-               0x41300, 0x413c4,
+               0x41304, 0x413c4,
                0x41400, 0x4141c,
                0x41480, 0x414d0,
                0x44000, 0x44078,
@@ -2089,7 +2108,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
                0x48200, 0x48298,
                0x482ac, 0x4833c,
                0x483f8, 0x483fc,
-               0x49300, 0x493c4,
+               0x49304, 0x493c4,
                0x49400, 0x4941c,
                0x49480, 0x494d0,
                0x4c000, 0x4c078,
@@ -2199,6 +2218,8 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
        else if (type == FW_PORT_TYPE_FIBER_XFI ||
                 type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP)
                v |= SUPPORTED_FIBRE;
+       else if (type == FW_PORT_TYPE_BP40_BA)
+               v |= SUPPORTED_40000baseSR4_Full;
 
        if (caps & FW_PORT_CAP_ANEG)
                v |= SUPPORTED_Autoneg;
@@ -2215,6 +2236,8 @@ static unsigned int to_fw_linkcaps(unsigned int caps)
                v |= FW_PORT_CAP_SPEED_1G;
        if (caps & ADVERTISED_10000baseT_Full)
                v |= FW_PORT_CAP_SPEED_10G;
+       if (caps & ADVERTISED_40000baseSR4_Full)
+               v |= FW_PORT_CAP_SPEED_40G;
        return v;
 }
 
@@ -2263,12 +2286,14 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
 static unsigned int speed_to_caps(int speed)
 {
-       if (speed == SPEED_100)
+       if (speed == 100)
                return FW_PORT_CAP_SPEED_100M;
-       if (speed == SPEED_1000)
+       if (speed == 1000)
                return FW_PORT_CAP_SPEED_1G;
-       if (speed == SPEED_10000)
+       if (speed == 10000)
                return FW_PORT_CAP_SPEED_10G;
+       if (speed == 40000)
+               return FW_PORT_CAP_SPEED_40G;
        return 0;
 }
 
@@ -2296,8 +2321,10 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (cmd->autoneg == AUTONEG_DISABLE) {
                cap = speed_to_caps(speed);
 
-               if (!(lc->supported & cap) || (speed == SPEED_1000) ||
-                   (speed == SPEED_10000))
+               if (!(lc->supported & cap) ||
+                   (speed == 1000) ||
+                   (speed == 10000) ||
+                   (speed == 40000))
                        return -EINVAL;
                lc->requested_speed = cap;
                lc->advertising = 0;
@@ -3205,8 +3232,8 @@ static int cxgb4_clip_get(const struct net_device *dev,
        c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
                        FW_CMD_REQUEST | FW_CMD_WRITE);
        c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c));
-       *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
-       *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+       c.ip_hi = *(__be64 *)(lip->s6_addr);
+       c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
        return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
 }
 
@@ -3221,8 +3248,8 @@ static int cxgb4_clip_release(const struct net_device *dev,
        c.op_to_write = htonl(FW_CMD_OP(FW_CLIP_CMD) |
                        FW_CMD_REQUEST | FW_CMD_READ);
        c.alloc_to_len16 = htonl(F_FW_CLIP_CMD_FREE | FW_LEN16(c));
-       *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
-       *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+       c.ip_hi = *(__be64 *)(lip->s6_addr);
+       c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
        return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
 }
 
@@ -3563,14 +3590,25 @@ static void drain_db_fifo(struct adapter *adap, int usecs)
 
 static void disable_txq_db(struct sge_txq *q)
 {
-       spin_lock_irq(&q->db_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&q->db_lock, flags);
        q->db_disabled = 1;
-       spin_unlock_irq(&q->db_lock);
+       spin_unlock_irqrestore(&q->db_lock, flags);
 }
 
-static void enable_txq_db(struct sge_txq *q)
+static void enable_txq_db(struct adapter *adap, struct sge_txq *q)
 {
        spin_lock_irq(&q->db_lock);
+       if (q->db_pidx_inc) {
+               /* Make sure that all writes to the TX descriptors
+                * are committed before we tell HW about them.
+                */
+               wmb();
+               t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
+                            QID(q->cntxt_id) | PIDX(q->db_pidx_inc));
+               q->db_pidx_inc = 0;
+       }
        q->db_disabled = 0;
        spin_unlock_irq(&q->db_lock);
 }
@@ -3592,11 +3630,32 @@ static void enable_dbs(struct adapter *adap)
        int i;
 
        for_each_ethrxq(&adap->sge, i)
-               enable_txq_db(&adap->sge.ethtxq[i].q);
+               enable_txq_db(adap, &adap->sge.ethtxq[i].q);
        for_each_ofldrxq(&adap->sge, i)
-               enable_txq_db(&adap->sge.ofldtxq[i].q);
+               enable_txq_db(adap, &adap->sge.ofldtxq[i].q);
        for_each_port(adap, i)
-               enable_txq_db(&adap->sge.ctrlq[i].q);
+               enable_txq_db(adap, &adap->sge.ctrlq[i].q);
+}
+
+static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
+{
+       if (adap->uld_handle[CXGB4_ULD_RDMA])
+               ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
+                               cmd);
+}
+
+static void process_db_full(struct work_struct *work)
+{
+       struct adapter *adap;
+
+       adap = container_of(work, struct adapter, db_full_task);
+
+       drain_db_fifo(adap, dbfifo_drain_delay);
+       enable_dbs(adap);
+       notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
+       t4_set_reg_field(adap, SGE_INT_ENABLE3,
+                        DBFIFO_HP_INT | DBFIFO_LP_INT,
+                        DBFIFO_HP_INT | DBFIFO_LP_INT);
 }
 
 static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
@@ -3604,7 +3663,7 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
        u16 hw_pidx, hw_cidx;
        int ret;
 
-       spin_lock_bh(&q->db_lock);
+       spin_lock_irq(&q->db_lock);
        ret = read_eq_indices(adap, (u16)q->cntxt_id, &hw_pidx, &hw_cidx);
        if (ret)
                goto out;
@@ -3621,7 +3680,8 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
        }
 out:
        q->db_disabled = 0;
-       spin_unlock_bh(&q->db_lock);
+       q->db_pidx_inc = 0;
+       spin_unlock_irq(&q->db_lock);
        if (ret)
                CH_WARN(adap, "DB drop recovery failed.\n");
 }
@@ -3637,29 +3697,6 @@ static void recover_all_queues(struct adapter *adap)
                sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
 }
 
-static void notify_rdma_uld(struct adapter *adap, enum cxgb4_control cmd)
-{
-       mutex_lock(&uld_mutex);
-       if (adap->uld_handle[CXGB4_ULD_RDMA])
-               ulds[CXGB4_ULD_RDMA].control(adap->uld_handle[CXGB4_ULD_RDMA],
-                               cmd);
-       mutex_unlock(&uld_mutex);
-}
-
-static void process_db_full(struct work_struct *work)
-{
-       struct adapter *adap;
-
-       adap = container_of(work, struct adapter, db_full_task);
-
-       notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
-       drain_db_fifo(adap, dbfifo_drain_delay);
-       t4_set_reg_field(adap, SGE_INT_ENABLE3,
-                        DBFIFO_HP_INT | DBFIFO_LP_INT,
-                        DBFIFO_HP_INT | DBFIFO_LP_INT);
-       notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
-}
-
 static void process_db_drop(struct work_struct *work)
 {
        struct adapter *adap;
@@ -3667,11 +3704,13 @@ static void process_db_drop(struct work_struct *work)
        adap = container_of(work, struct adapter, db_drop_task);
 
        if (is_t4(adap->params.chip)) {
-               disable_dbs(adap);
+               drain_db_fifo(adap, dbfifo_drain_delay);
                notify_rdma_uld(adap, CXGB4_CONTROL_DB_DROP);
-               drain_db_fifo(adap, 1);
+               drain_db_fifo(adap, dbfifo_drain_delay);
                recover_all_queues(adap);
+               drain_db_fifo(adap, dbfifo_drain_delay);
                enable_dbs(adap);
+               notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
        } else {
                u32 dropped_db = t4_read_reg(adap, 0x010ac);
                u16 qid = (dropped_db >> 15) & 0x1ffff;
@@ -3712,6 +3751,8 @@ static void process_db_drop(struct work_struct *work)
 void t4_db_full(struct adapter *adap)
 {
        if (is_t4(adap->params.chip)) {
+               disable_dbs(adap);
+               notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
                t4_set_reg_field(adap, SGE_INT_ENABLE3,
                                 DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
                queue_work(workq, &adap->db_full_task);
@@ -3720,8 +3761,11 @@ void t4_db_full(struct adapter *adap)
 
 void t4_db_dropped(struct adapter *adap)
 {
-       if (is_t4(adap->params.chip))
-               queue_work(workq, &adap->db_drop_task);
+       if (is_t4(adap->params.chip)) {
+               disable_dbs(adap);
+               notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
+       }
+       queue_work(workq, &adap->db_drop_task);
 }
 
 static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -3765,6 +3809,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
        lli.dbfifo_int_thresh = dbfifo_int_thresh;
        lli.sge_pktshift = adap->sge.pktshift;
        lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN;
+       lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl;
 
        handle = ulds[uld].add(&lli);
        if (IS_ERR(handle)) {
@@ -5369,6 +5414,21 @@ static int adap_init0(struct adapter *adap)
        val[0] = 1;
        (void) t4_set_params(adap, adap->mbox, adap->fn, 0, 1, params, val);
 
+       /*
+        * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL
+        * capability.  Earlier versions of the firmware didn't have the
+        * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no
+        * permission to use ULPTX MEMWRITE DSGL.
+        */
+       if (is_t4(adap->params.chip)) {
+               adap->params.ulptx_memwrite_dsgl = false;
+       } else {
+               params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL);
+               ret = t4_query_params(adap, adap->mbox, adap->fn, 0,
+                                     1, params, val);
+               adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0);
+       }
+
        /*
         * Get device capabilities so we can determine what resources we need
         * to manage.
@@ -5603,9 +5663,10 @@ static const struct pci_error_handlers cxgb4_eeh = {
        .resume         = eeh_resume,
 };
 
-static inline bool is_10g_port(const struct link_config *lc)
+static inline bool is_x_10g_port(const struct link_config *lc)
 {
-       return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
+       return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0 ||
+              (lc->supported & FW_PORT_CAP_SPEED_40G) != 0;
 }
 
 static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx,
@@ -5629,7 +5690,7 @@ static void cfg_queues(struct adapter *adap)
        int i, q10g = 0, n10g = 0, qidx = 0;
 
        for_each_port(adap, i)
-               n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg);
+               n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
 
        /*
         * We default to 1 queue per non-10G port and up to # of cores queues
@@ -5644,7 +5705,7 @@ static void cfg_queues(struct adapter *adap)
                struct port_info *pi = adap2pinfo(adap, i);
 
                pi->first_qset = qidx;
-               pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1;
+               pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1;
                qidx += pi->nqsets;
        }
 
@@ -5737,7 +5798,7 @@ static void reduce_ethqs(struct adapter *adap, int n)
 static int enable_msix(struct adapter *adap)
 {
        int ofld_need = 0;
-       int i, err, want, need;
+       int i, want, need;
        struct sge *s = &adap->sge;
        unsigned int nchan = adap->params.nports;
        struct msix_entry entries[MAX_INGQ + 1];
@@ -5753,32 +5814,30 @@ static int enable_msix(struct adapter *adap)
        }
        need = adap->params.nports + EXTRA_VECS + ofld_need;
 
-       while ((err = pci_enable_msix(adap->pdev, entries, want)) >= need)
-               want = err;
+       want = pci_enable_msix_range(adap->pdev, entries, need, want);
+       if (want < 0)
+               return want;
 
-       if (!err) {
-               /*
-                * Distribute available vectors to the various queue groups.
-                * Every group gets its minimum requirement and NIC gets top
-                * priority for leftovers.
-                */
-               i = want - EXTRA_VECS - ofld_need;
-               if (i < s->max_ethqsets) {
-                       s->max_ethqsets = i;
-                       if (i < s->ethqsets)
-                               reduce_ethqs(adap, i);
-               }
-               if (is_offload(adap)) {
-                       i = want - EXTRA_VECS - s->max_ethqsets;
-                       i -= ofld_need - nchan;
-                       s->ofldqsets = (i / nchan) * nchan;  /* round down */
-               }
-               for (i = 0; i < want; ++i)
-                       adap->msix_info[i].vec = entries[i].vector;
-       } else if (err > 0)
-               dev_info(adap->pdev_dev,
-                        "only %d MSI-X vectors left, not using MSI-X\n", err);
-       return err;
+       /*
+        * Distribute available vectors to the various queue groups.
+        * Every group gets its minimum requirement and NIC gets top
+        * priority for leftovers.
+        */
+       i = want - EXTRA_VECS - ofld_need;
+       if (i < s->max_ethqsets) {
+               s->max_ethqsets = i;
+               if (i < s->ethqsets)
+                       reduce_ethqs(adap, i);
+       }
+       if (is_offload(adap)) {
+               i = want - EXTRA_VECS - s->max_ethqsets;
+               i -= ofld_need - nchan;
+               s->ofldqsets = (i / nchan) * nchan;  /* round down */
+       }
+       for (i = 0; i < want; ++i)
+               adap->msix_info[i].vec = entries[i].vector;
+
+       return 0;
 }
 
 #undef EXTRA_VECS
@@ -5801,11 +5860,6 @@ static int init_rss(struct adapter *adap)
 
 static void print_port_info(const struct net_device *dev)
 {
-       static const char *base[] = {
-               "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4",
-               "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4"
-       };
-
        char buf[80];
        char *bufp = buf;
        const char *spd = "";
@@ -5823,9 +5877,11 @@ static void print_port_info(const struct net_device *dev)
                bufp += sprintf(bufp, "1000/");
        if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G)
                bufp += sprintf(bufp, "10G/");
+       if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G)
+               bufp += sprintf(bufp, "40G/");
        if (bufp != buf)
                --bufp;
-       sprintf(bufp, "BASE-%s", base[pi->port_type]);
+       sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type));
 
        netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n",
                    adap->params.vpd.id,
@@ -5833,8 +5889,8 @@ static void print_port_info(const struct net_device *dev)
                    is_offload(adap) ? "R" : "", adap->params.pci.width, spd,
                    (adap->flags & USING_MSIX) ? " MSI-X" :
                    (adap->flags & USING_MSI) ? " MSI" : "");
-       netdev_info(dev, "S/N: %s, E/C: %s\n",
-                   adap->params.vpd.sn, adap->params.vpd.ec);
+       netdev_info(dev, "S/N: %s, P/N: %s\n",
+                   adap->params.vpd.sn, adap->params.vpd.pn);
 }
 
 static void enable_pcie_relaxed_ordering(struct pci_dev *dev)
@@ -6179,6 +6235,7 @@ static struct pci_driver cxgb4_driver = {
        .id_table = cxgb4_pci_tbl,
        .probe    = init_one,
        .remove   = remove_one,
+       .shutdown = remove_one,
        .err_handler = &cxgb4_eeh,
 };
 
index 4dd0a82533e442f8b330c5ede554359ea450a087..e274a047528fca6ed11c9773db2d0a188e16da14 100644 (file)
@@ -253,6 +253,7 @@ struct cxgb4_lld_info {
                                             /* packet data */
        bool enable_fw_ofld_conn;            /* Enable connection through fw */
                                             /* WR */
+       bool ulptx_memwrite_dsgl;            /* use of T5 DSGL allowed */
 };
 
 struct cxgb4_uld_info {
index 47ffa64fcf19e89a495191252006cb21eb40d993..ca95cf2954eb33f62719130a8b0432fbb324c2b6 100644 (file)
  */
 #define TX_QCHECK_PERIOD (HZ / 2)
 
+/* SGE Hung Ingress DMA Threshold Warning time (in Hz) and Warning Repeat Rate
+ * (in RX_QCHECK_PERIOD multiples).  If we find one of the SGE Ingress DMA
+ * State Machines in the same state for this amount of time (in HZ) then we'll
+ * issue a warning about a potential hang.  We'll repeat the warning as the
+ * SGE Ingress DMA Channel appears to be hung every N RX_QCHECK_PERIODs till
+ * the situation clears.  If the situation clears, we'll note that as well.
+ */
+#define SGE_IDMA_WARN_THRESH (1 * HZ)
+#define SGE_IDMA_WARN_REPEAT (20 * RX_QCHECK_PERIOD)
+
 /*
  * Max number of Tx descriptors to be reclaimed by the Tx timer.
  */
@@ -373,7 +383,7 @@ static void free_tx_desc(struct adapter *adap, struct sge_txq *q,
                if (d->skb) {                       /* an SGL is present */
                        if (unmap)
                                unmap_sgl(dev, d->skb, d->sgl, q);
-                       kfree_skb(d->skb);
+                       dev_consume_skb_any(d->skb);
                        d->skb = NULL;
                }
                ++d;
@@ -706,11 +716,17 @@ static inline unsigned int flits_to_desc(unsigned int n)
  *     @skb: the packet
  *
  *     Returns whether an Ethernet packet is small enough to fit as
- *     immediate data.
+ *     immediate data. Return value corresponds to headroom required.
  */
 static inline int is_eth_imm(const struct sk_buff *skb)
 {
-       return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt);
+       int hdrlen = skb_shinfo(skb)->gso_size ?
+                       sizeof(struct cpl_tx_pkt_lso_core) : 0;
+
+       hdrlen += sizeof(struct cpl_tx_pkt);
+       if (skb->len <= MAX_IMM_TX_PKT_LEN - hdrlen)
+               return hdrlen;
+       return 0;
 }
 
 /**
@@ -723,9 +739,10 @@ static inline int is_eth_imm(const struct sk_buff *skb)
 static inline unsigned int calc_tx_flits(const struct sk_buff *skb)
 {
        unsigned int flits;
+       int hdrlen = is_eth_imm(skb);
 
-       if (is_eth_imm(skb))
-               return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8);
+       if (hdrlen)
+               return DIV_ROUND_UP(skb->len + hdrlen, sizeof(__be64));
 
        flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4;
        if (skb_shinfo(skb)->gso_size)
@@ -843,9 +860,10 @@ static void cxgb_pio_copy(u64 __iomem *dst, u64 *src)
 static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
 {
        unsigned int *wr, index;
+       unsigned long flags;
 
        wmb();            /* write descriptors before telling HW */
-       spin_lock(&q->db_lock);
+       spin_lock_irqsave(&q->db_lock, flags);
        if (!q->db_disabled) {
                if (is_t4(adap->params.chip)) {
                        t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
@@ -861,9 +879,10 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
                                writel(n,  adap->bar2 + q->udb + 8);
                        wmb();
                }
-       }
+       } else
+               q->db_pidx_inc += n;
        q->db_pidx = q->pidx;
-       spin_unlock(&q->db_lock);
+       spin_unlock_irqrestore(&q->db_lock, flags);
 }
 
 /**
@@ -971,6 +990,7 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n)
  */
 netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+       int len;
        u32 wr_mid;
        u64 cntrl, *end;
        int qidx, credits;
@@ -982,13 +1002,14 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        struct cpl_tx_pkt_core *cpl;
        const struct skb_shared_info *ssi;
        dma_addr_t addr[MAX_SKB_FRAGS + 1];
+       bool immediate = false;
 
        /*
         * The chip min packet length is 10 octets but play safe and reject
         * anything shorter than an Ethernet header.
         */
        if (unlikely(skb->len < ETH_HLEN)) {
-out_free:      dev_kfree_skb(skb);
+out_free:      dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -1011,7 +1032,10 @@ out_free:        dev_kfree_skb(skb);
                return NETDEV_TX_BUSY;
        }
 
-       if (!is_eth_imm(skb) &&
+       if (is_eth_imm(skb))
+               immediate = true;
+
+       if (!immediate &&
            unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) {
                q->mapping_err++;
                goto out_free;
@@ -1028,6 +1052,7 @@ out_free: dev_kfree_skb(skb);
        wr->r3 = cpu_to_be64(0);
        end = (u64 *)wr + flits;
 
+       len = immediate ? skb->len : 0;
        ssi = skb_shinfo(skb);
        if (ssi->gso_size) {
                struct cpl_tx_pkt_lso *lso = (void *)wr;
@@ -1035,8 +1060,9 @@ out_free: dev_kfree_skb(skb);
                int l3hdr_len = skb_network_header_len(skb);
                int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN;
 
+               len += sizeof(*lso);
                wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
-                                      FW_WR_IMMDLEN(sizeof(*lso)));
+                                      FW_WR_IMMDLEN(len));
                lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) |
                                        LSO_FIRST_SLICE | LSO_LAST_SLICE |
                                        LSO_IPV6(v6) |
@@ -1054,9 +1080,7 @@ out_free: dev_kfree_skb(skb);
                q->tso++;
                q->tx_cso += ssi->gso_segs;
        } else {
-               int len;
-
-               len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl);
+               len += sizeof(*cpl);
                wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) |
                                       FW_WR_IMMDLEN(len));
                cpl = (void *)(wr + 1);
@@ -1078,9 +1102,9 @@ out_free: dev_kfree_skb(skb);
        cpl->len = htons(skb->len);
        cpl->ctrl1 = cpu_to_be64(cntrl);
 
-       if (is_eth_imm(skb)) {
+       if (immediate) {
                inline_tx_skb(skb, &q->q, cpl + 1);
-               dev_kfree_skb(skb);
+               dev_consume_skb_any(skb);
        } else {
                int last_desc;
 
@@ -1467,8 +1491,12 @@ static inline int ofld_send(struct adapter *adap, struct sk_buff *skb)
 {
        unsigned int idx = skb_txq(skb);
 
-       if (unlikely(is_ctrl_pkt(skb)))
+       if (unlikely(is_ctrl_pkt(skb))) {
+               /* Single ctrl queue is a requirement for LE workaround path */
+               if (adap->tids.nsftids)
+                       idx = 0;
                return ctrl_xmit(&adap->sge.ctrlq[idx], skb);
+       }
        return ofld_xmit(&adap->sge.ofldtxq[idx], skb);
 }
 
@@ -1992,7 +2020,7 @@ irq_handler_t t4_intr_handler(struct adapter *adap)
 static void sge_rx_timer_cb(unsigned long data)
 {
        unsigned long m;
-       unsigned int i, cnt[2];
+       unsigned int i, idma_same_state_cnt[2];
        struct adapter *adap = (struct adapter *)data;
        struct sge *s = &adap->sge;
 
@@ -2015,21 +2043,64 @@ static void sge_rx_timer_cb(unsigned long data)
                }
 
        t4_write_reg(adap, SGE_DEBUG_INDEX, 13);
-       cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
-       cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
-
-       for (i = 0; i < 2; i++)
-               if (cnt[i] >= s->starve_thres) {
-                       if (s->idma_state[i] || cnt[i] == 0xffffffff)
-                               continue;
-                       s->idma_state[i] = 1;
-                       t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
-                       m = t4_read_reg(adap, SGE_DEBUG_DATA_LOW) >> (i * 16);
-                       dev_warn(adap->pdev_dev,
-                                "SGE idma%u starvation detected for "
-                                "queue %lu\n", i, m & 0xffff);
-               } else if (s->idma_state[i])
-                       s->idma_state[i] = 0;
+       idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
+       idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+
+       for (i = 0; i < 2; i++) {
+               u32 debug0, debug11;
+
+               /* If the Ingress DMA Same State Counter ("timer") is less
+                * than 1s, then we can reset our synthesized Stall Timer and
+                * continue.  If we have previously emitted warnings about a
+                * potential stalled Ingress Queue, issue a note indicating
+                * that the Ingress Queue has resumed forward progress.
+                */
+               if (idma_same_state_cnt[i] < s->idma_1s_thresh) {
+                       if (s->idma_stalled[i] >= SGE_IDMA_WARN_THRESH)
+                               CH_WARN(adap, "SGE idma%d, queue%u,resumed after %d sec\n",
+                                       i, s->idma_qid[i],
+                                       s->idma_stalled[i]/HZ);
+                       s->idma_stalled[i] = 0;
+                       continue;
+               }
+
+               /* Synthesize an SGE Ingress DMA Same State Timer in the Hz
+                * domain.  The first time we get here it'll be because we
+                * passed the 1s Threshold; each additional time it'll be
+                * because the RX Timer Callback is being fired on its regular
+                * schedule.
+                *
+                * If the stall is below our Potential Hung Ingress Queue
+                * Warning Threshold, continue.
+                */
+               if (s->idma_stalled[i] == 0)
+                       s->idma_stalled[i] = HZ;
+               else
+                       s->idma_stalled[i] += RX_QCHECK_PERIOD;
+
+               if (s->idma_stalled[i] < SGE_IDMA_WARN_THRESH)
+                       continue;
+
+               /* We'll issue a warning every SGE_IDMA_WARN_REPEAT Hz */
+               if (((s->idma_stalled[i] - HZ) % SGE_IDMA_WARN_REPEAT) != 0)
+                       continue;
+
+               /* Read and save the SGE IDMA State and Queue ID information.
+                * We do this every time in case it changes across time ...
+                */
+               t4_write_reg(adap, SGE_DEBUG_INDEX, 0);
+               debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+               s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
+
+               t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
+               debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+               s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff;
+
+               CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n",
+                       i, s->idma_qid[i], s->idma_state[i],
+                       s->idma_stalled[i]/HZ, debug0, debug11);
+               t4_sge_decode_idma_state(adap, s->idma_state[i]);
+       }
 
        mod_timer(&s->rx_timer, jiffies + RX_QCHECK_PERIOD);
 }
@@ -2580,11 +2651,19 @@ static int t4_sge_init_soft(struct adapter *adap)
        fl_small_mtu = READ_FL_BUF(RX_SMALL_MTU_BUF);
        fl_large_mtu = READ_FL_BUF(RX_LARGE_MTU_BUF);
 
+       /* We only bother using the Large Page logic if the Large Page Buffer
+        * is larger than our Page Size Buffer.
+        */
+       if (fl_large_pg <= fl_small_pg)
+               fl_large_pg = 0;
+
        #undef READ_FL_BUF
 
+       /* The Page Size Buffer must be exactly equal to our Page Size and the
+        * Large Page Size Buffer should be 0 (per above) or a power of 2.
+        */
        if (fl_small_pg != PAGE_SIZE ||
-           (fl_large_pg != 0 && (fl_large_pg < fl_small_pg ||
-                                 (fl_large_pg & (fl_large_pg-1)) != 0))) {
+           (fl_large_pg & (fl_large_pg-1)) != 0) {
                dev_err(adap->pdev_dev, "bad SGE FL page buffer sizes [%d, %d]\n",
                        fl_small_pg, fl_large_pg);
                return -EINVAL;
@@ -2699,8 +2778,8 @@ static int t4_sge_init_hard(struct adapter *adap)
 int t4_sge_init(struct adapter *adap)
 {
        struct sge *s = &adap->sge;
-       u32 sge_control;
-       int ret;
+       u32 sge_control, sge_conm_ctrl;
+       int ret, egress_threshold;
 
        /*
         * Ingress Padding Boundary and Egress Status Page Size are set up by
@@ -2725,15 +2804,24 @@ int t4_sge_init(struct adapter *adap)
         * SGE's Egress Congestion Threshold.  If it isn't, then we can get
         * stuck waiting for new packets while the SGE is waiting for us to
         * give it more Free List entries.  (Note that the SGE's Egress
-        * Congestion Threshold is in units of 2 Free List pointers.)
+        * Congestion Threshold is in units of 2 Free List pointers.) For T4,
+        * there was only a single field to control this.  For T5 there's the
+        * original field which now only applies to Unpacked Mode Free List
+        * buffers and a new field which only applies to Packed Mode Free List
+        * buffers.
         */
-       s->fl_starve_thres
-               = EGRTHRESHOLD_GET(t4_read_reg(adap, SGE_CONM_CTRL))*2 + 1;
+       sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL);
+       if (is_t4(adap->params.chip))
+               egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl);
+       else
+               egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl);
+       s->fl_starve_thres = 2*egress_threshold + 1;
 
        setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap);
        setup_timer(&s->tx_timer, sge_tx_timer_cb, (unsigned long)adap);
-       s->starve_thres = core_ticks_per_usec(adap) * 1000000;  /* 1 s */
-       s->idma_state[0] = s->idma_state[1] = 0;
+       s->idma_1s_thresh = core_ticks_per_usec(adap) * 1000000;  /* 1 s */
+       s->idma_stalled[0] = 0;
+       s->idma_stalled[1] = 0;
        spin_lock_init(&s->intrq_lock);
 
        return 0;
index 2c109343d57083a651bcaf9ef08772dd8029ec1f..fb2fe65903c2b7675701e1911a53b6e484566a73 100644 (file)
@@ -573,7 +573,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 {
        u32 cclk_param, cclk_val;
        int i, ret, addr;
-       int ec, sn;
+       int ec, sn, pn;
        u8 *vpd, csum;
        unsigned int vpdr_len, kw_offset, id_len;
 
@@ -638,6 +638,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
 
        FIND_VPD_KW(ec, "EC");
        FIND_VPD_KW(sn, "SN");
+       FIND_VPD_KW(pn, "PN");
 #undef FIND_VPD_KW
 
        memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len);
@@ -647,6 +648,8 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
        i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE);
        memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN));
        strim(p->sn);
+       memcpy(p->pn, vpd + pn, min(i, PN_LEN));
+       strim(p->pn);
 
        /*
         * Ask firmware for the Core Clock since it knows how to translate the
@@ -1155,7 +1158,8 @@ out:
 }
 
 #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
-                    FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG)
+                    FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
+                    FW_PORT_CAP_ANEG)
 
 /**
  *     t4_link_start - apply link configuration to MAC/PHY
@@ -2246,6 +2250,36 @@ static unsigned int get_mps_bg_map(struct adapter *adap, int idx)
        return 1 << idx;
 }
 
+/**
+ *      t4_get_port_type_description - return Port Type string description
+ *      @port_type: firmware Port Type enumeration
+ */
+const char *t4_get_port_type_description(enum fw_port_type port_type)
+{
+       static const char *const port_type_description[] = {
+               "R XFI",
+               "R XAUI",
+               "T SGMII",
+               "T XFI",
+               "T XAUI",
+               "KX4",
+               "CX4",
+               "KX",
+               "KR",
+               "R SFP+",
+               "KR/KX",
+               "KR/KX/KX4",
+               "R QSFP_10G",
+               "",
+               "R QSFP",
+               "R BP40_BA",
+       };
+
+       if (port_type < ARRAY_SIZE(port_type_description))
+               return port_type_description[port_type];
+       return "UNKNOWN";
+}
+
 /**
  *     t4_get_port_stats - collect port statistics
  *     @adap: the adapter
@@ -2562,6 +2596,112 @@ int t4_mdio_wr(struct adapter *adap, unsigned int mbox, unsigned int phy_addr,
        return t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
 }
 
+/**
+ *     t4_sge_decode_idma_state - decode the idma state
+ *     @adap: the adapter
+ *     @state: the state idma is stuck in
+ */
+void t4_sge_decode_idma_state(struct adapter *adapter, int state)
+{
+       static const char * const t4_decode[] = {
+               "IDMA_IDLE",
+               "IDMA_PUSH_MORE_CPL_FIFO",
+               "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO",
+               "Not used",
+               "IDMA_PHYSADDR_SEND_PCIEHDR",
+               "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST",
+               "IDMA_PHYSADDR_SEND_PAYLOAD",
+               "IDMA_SEND_FIFO_TO_IMSG",
+               "IDMA_FL_REQ_DATA_FL_PREP",
+               "IDMA_FL_REQ_DATA_FL",
+               "IDMA_FL_DROP",
+               "IDMA_FL_H_REQ_HEADER_FL",
+               "IDMA_FL_H_SEND_PCIEHDR",
+               "IDMA_FL_H_PUSH_CPL_FIFO",
+               "IDMA_FL_H_SEND_CPL",
+               "IDMA_FL_H_SEND_IP_HDR_FIRST",
+               "IDMA_FL_H_SEND_IP_HDR",
+               "IDMA_FL_H_REQ_NEXT_HEADER_FL",
+               "IDMA_FL_H_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_H_SEND_IP_HDR_PADDING",
+               "IDMA_FL_D_SEND_PCIEHDR",
+               "IDMA_FL_D_SEND_CPL_AND_IP_HDR",
+               "IDMA_FL_D_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_PCIEHDR",
+               "IDMA_FL_PUSH_CPL_FIFO",
+               "IDMA_FL_SEND_CPL",
+               "IDMA_FL_SEND_PAYLOAD_FIRST",
+               "IDMA_FL_SEND_PAYLOAD",
+               "IDMA_FL_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_SEND_PADDING",
+               "IDMA_FL_SEND_COMPLETION_TO_IMSG",
+               "IDMA_FL_SEND_FIFO_TO_IMSG",
+               "IDMA_FL_REQ_DATAFL_DONE",
+               "IDMA_FL_REQ_HEADERFL_DONE",
+       };
+       static const char * const t5_decode[] = {
+               "IDMA_IDLE",
+               "IDMA_ALMOST_IDLE",
+               "IDMA_PUSH_MORE_CPL_FIFO",
+               "IDMA_PUSH_CPL_MSG_HEADER_TO_FIFO",
+               "IDMA_SGEFLRFLUSH_SEND_PCIEHDR",
+               "IDMA_PHYSADDR_SEND_PCIEHDR",
+               "IDMA_PHYSADDR_SEND_PAYLOAD_FIRST",
+               "IDMA_PHYSADDR_SEND_PAYLOAD",
+               "IDMA_SEND_FIFO_TO_IMSG",
+               "IDMA_FL_REQ_DATA_FL",
+               "IDMA_FL_DROP",
+               "IDMA_FL_DROP_SEND_INC",
+               "IDMA_FL_H_REQ_HEADER_FL",
+               "IDMA_FL_H_SEND_PCIEHDR",
+               "IDMA_FL_H_PUSH_CPL_FIFO",
+               "IDMA_FL_H_SEND_CPL",
+               "IDMA_FL_H_SEND_IP_HDR_FIRST",
+               "IDMA_FL_H_SEND_IP_HDR",
+               "IDMA_FL_H_REQ_NEXT_HEADER_FL",
+               "IDMA_FL_H_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_H_SEND_IP_HDR_PADDING",
+               "IDMA_FL_D_SEND_PCIEHDR",
+               "IDMA_FL_D_SEND_CPL_AND_IP_HDR",
+               "IDMA_FL_D_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_PCIEHDR",
+               "IDMA_FL_PUSH_CPL_FIFO",
+               "IDMA_FL_SEND_CPL",
+               "IDMA_FL_SEND_PAYLOAD_FIRST",
+               "IDMA_FL_SEND_PAYLOAD",
+               "IDMA_FL_REQ_NEXT_DATA_FL",
+               "IDMA_FL_SEND_NEXT_PCIEHDR",
+               "IDMA_FL_SEND_PADDING",
+               "IDMA_FL_SEND_COMPLETION_TO_IMSG",
+       };
+       static const u32 sge_regs[] = {
+               SGE_DEBUG_DATA_LOW_INDEX_2,
+               SGE_DEBUG_DATA_LOW_INDEX_3,
+               SGE_DEBUG_DATA_HIGH_INDEX_10,
+       };
+       const char **sge_idma_decode;
+       int sge_idma_decode_nstates;
+       int i;
+
+       if (is_t4(adapter->params.chip)) {
+               sge_idma_decode = (const char **)t4_decode;
+               sge_idma_decode_nstates = ARRAY_SIZE(t4_decode);
+       } else {
+               sge_idma_decode = (const char **)t5_decode;
+               sge_idma_decode_nstates = ARRAY_SIZE(t5_decode);
+       }
+
+       if (state < sge_idma_decode_nstates)
+               CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]);
+       else
+               CH_WARN(adapter, "idma state %d unknown\n", state);
+
+       for (i = 0; i < ARRAY_SIZE(sge_regs); i++)
+               CH_WARN(adapter, "SGE register %#x value %#x\n",
+                       sge_regs[i], t4_read_reg(adapter, sge_regs[i]));
+}
+
 /**
  *      t4_fw_hello - establish communication with FW
  *      @adap: the adapter
@@ -3533,11 +3673,13 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl)
                if (stat & FW_PORT_CMD_TXPAUSE)
                        fc |= PAUSE_TX;
                if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
-                       speed = SPEED_100;
+                       speed = 100;
                else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
-                       speed = SPEED_1000;
+                       speed = 1000;
                else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
-                       speed = SPEED_10000;
+                       speed = 10000;
+               else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
+                       speed = 40000;
 
                if (link_ok != lc->link_ok || speed != lc->speed ||
                    fc != lc->fc) {                    /* something changed */
index cd6874b571ee2585c3ef1c9f8c418c7c643b8d46..f2738c7107898f2cf9112c74e33edc2f5ab16053 100644 (file)
@@ -116,6 +116,7 @@ enum CPL_error {
        CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
        CPL_ERR_RTX_NEG_ADVICE     = 35,
        CPL_ERR_PERSIST_NEG_ADVICE = 36,
+       CPL_ERR_KEEPALV_NEG_ADVICE = 37,
        CPL_ERR_ABORT_FAILED       = 42,
        CPL_ERR_IWARP_FLM          = 50,
 };
index 4082522d81408bf0a23cff8eaf9700bef14533a9..225ad8a5722de026bf0302b4f4f49886100e66f5 100644 (file)
 #define  EGRTHRESHOLD(x)     ((x) << EGRTHRESHOLDshift)
 #define  EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift)
 
+#define EGRTHRESHOLDPACKING_MASK       0x3fU
+#define EGRTHRESHOLDPACKING_SHIFT      14
+#define EGRTHRESHOLDPACKING(x)         ((x) << EGRTHRESHOLDPACKING_SHIFT)
+#define EGRTHRESHOLDPACKING_GET(x)     (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \
+                                         EGRTHRESHOLDPACKING_MASK)
+
 #define SGE_DBFIFO_STATUS 0x10a4
 #define  HP_INT_THRESH_SHIFT 28
 #define  HP_INT_THRESH_MASK  0xfU
 #define SGE_DEBUG_INDEX 0x10cc
 #define SGE_DEBUG_DATA_HIGH 0x10d0
 #define SGE_DEBUG_DATA_LOW 0x10d4
+#define SGE_DEBUG_DATA_LOW_INDEX_2     0x12c8
+#define SGE_DEBUG_DATA_LOW_INDEX_3     0x12cc
+#define SGE_DEBUG_DATA_HIGH_INDEX_10   0x12a8
 #define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4
 
 #define S_HP_INT_THRESH    28
index 74fea74ce0aa25a676045868fa0b48c4a3800860..9cc973fbcf26761b322810fa91dcf61f528b3fc7 100644 (file)
@@ -932,6 +932,7 @@ enum fw_params_param_dev {
        FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
        FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
        FW_PARAMS_PARAM_DEV_CF = 0x0D,
+       FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17,
 };
 
 /*
@@ -1742,6 +1743,9 @@ enum fw_port_type {
        FW_PORT_TYPE_SFP,
        FW_PORT_TYPE_BP_AP,
        FW_PORT_TYPE_BP4_AP,
+       FW_PORT_TYPE_QSFP_10G,
+       FW_PORT_TYPE_QSFP,
+       FW_PORT_TYPE_BP40_BA,
 
        FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK
 };
index 0899c098359446346f7abe1939ac214705fd0acb..52859288de7b4d5b8c550c9a1e53fe5845225da0 100644 (file)
@@ -2444,7 +2444,7 @@ static void reduce_ethqs(struct adapter *adapter, int n)
  */
 static int enable_msix(struct adapter *adapter)
 {
-       int i, err, want, need;
+       int i, want, need, nqsets;
        struct msix_entry entries[MSIX_ENTRIES];
        struct sge *s = &adapter->sge;
 
@@ -2460,26 +2460,23 @@ static int enable_msix(struct adapter *adapter)
         */
        want = s->max_ethqsets + MSIX_EXTRAS;
        need = adapter->params.nports + MSIX_EXTRAS;
-       while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need)
-               want = err;
 
-       if (err == 0) {
-               int nqsets = want - MSIX_EXTRAS;
-               if (nqsets < s->max_ethqsets) {
-                       dev_warn(adapter->pdev_dev, "only enough MSI-X vectors"
-                                " for %d Queue Sets\n", nqsets);
-                       s->max_ethqsets = nqsets;
-                       if (nqsets < s->ethqsets)
-                               reduce_ethqs(adapter, nqsets);
-               }
-               for (i = 0; i < want; ++i)
-                       adapter->msix_info[i].vec = entries[i].vector;
-       } else if (err > 0) {
-               pci_disable_msix(adapter->pdev);
-               dev_info(adapter->pdev_dev, "only %d MSI-X vectors left,"
-                        " not using MSI-X\n", err);
+       want = pci_enable_msix_range(adapter->pdev, entries, need, want);
+       if (want < 0)
+               return want;
+
+       nqsets = want - MSIX_EXTRAS;
+       if (nqsets < s->max_ethqsets) {
+               dev_warn(adapter->pdev_dev, "only enough MSI-X vectors"
+                        " for %d Queue Sets\n", nqsets);
+               s->max_ethqsets = nqsets;
+               if (nqsets < s->ethqsets)
+                       reduce_ethqs(adapter, nqsets);
        }
-       return err;
+       for (i = 0; i < want; ++i)
+               adapter->msix_info[i].vec = entries[i].vector;
+
+       return 0;
 }
 
 static const struct net_device_ops cxgb4vf_netdev_ops  = {
@@ -2947,6 +2944,14 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4vf_pci_tbl) = {
        CH_DEVICE(0x5811, 0),   /* T520-lp-cr */
        CH_DEVICE(0x5812, 0),   /* T560-cr */
        CH_DEVICE(0x5813, 0),   /* T580-cr */
+       CH_DEVICE(0x5814, 0),   /* T580-so-cr */
+       CH_DEVICE(0x5815, 0),   /* T502-bt */
+       CH_DEVICE(0x5880, 0),
+       CH_DEVICE(0x5881, 0),
+       CH_DEVICE(0x5882, 0),
+       CH_DEVICE(0x5883, 0),
+       CH_DEVICE(0x5884, 0),
+       CH_DEVICE(0x5885, 0),
        { 0, }
 };
 
index 0a89963c48ce78148d1abe6cd86151e850c24062..9cfa4b4bb089d398a1b687a71d32f0856d15fa47 100644 (file)
@@ -401,7 +401,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *tq,
                if (sdesc->skb) {
                        if (need_unmap)
                                unmap_sgl(dev, sdesc->skb, sdesc->sgl, tq);
-                       kfree_skb(sdesc->skb);
+                       dev_consume_skb_any(sdesc->skb);
                        sdesc->skb = NULL;
                }
 
@@ -1275,7 +1275,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                 * need it any longer.
                 */
                inline_tx_skb(skb, &txq->q, cpl + 1);
-               dev_kfree_skb(skb);
+               dev_consume_skb_any(skb);
        } else {
                /*
                 * Write the skb's Scatter/Gather list into the TX Packet CPL
@@ -1354,7 +1354,7 @@ out_free:
         * An error of some sort happened.  Free the TX skb and tell the
         * OS that we've "dealt" with the packet ...
         */
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
index 19f642a45f40859874a94663cd3fc503f58014ed..fe84fbabc0d4d95761d35c1f55a5c04d60f63221 100644 (file)
@@ -1174,7 +1174,7 @@ static netdev_tx_t net_send_packet(struct sk_buff *skb, struct net_device *dev)
        writewords(lp, TX_FRAME_PORT, skb->data, (skb->len + 1) >> 1);
        spin_unlock_irqrestore(&lp->lock, flags);
        dev->stats.tx_bytes += skb->len;
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        /* We DO NOT call netif_wake_queue() here.
         * We also DO NOT call netif_start_queue().
index b740bfce72ef371a82077fe4b3c7f498c9430423..2945718ce8068e4355628852ed200d539c9c2273 100644 (file)
@@ -521,7 +521,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
        unsigned int txq_map;
 
        if (skb->len <= 0) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -536,7 +536,7 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
        if (skb_shinfo(skb)->gso_size == 0 &&
            skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC &&
            skb_linearize(skb)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -1086,14 +1086,15 @@ static int enic_poll(struct napi_struct *napi, int budget)
        unsigned int intr = enic_legacy_io_intr();
        unsigned int rq_work_to_do = budget;
        unsigned int wq_work_to_do = -1; /* no limit */
-       unsigned int  work_done, rq_work_done, wq_work_done;
+       unsigned int  work_done, rq_work_done = 0, wq_work_done;
        int err;
 
        /* Service RQ (first) and WQ
         */
 
-       rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
-               rq_work_to_do, enic_rq_service, NULL);
+       if (budget > 0)
+               rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
+                       rq_work_to_do, enic_rq_service, NULL);
 
        wq_work_done = vnic_cq_service(&enic->cq[cq_wq],
                wq_work_to_do, enic_wq_service, NULL);
@@ -1141,14 +1142,15 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        unsigned int cq = enic_cq_rq(enic, rq);
        unsigned int intr = enic_msix_rq_intr(enic, rq);
        unsigned int work_to_do = budget;
-       unsigned int work_done;
+       unsigned int work_done = 0;
        int err;
 
        /* Service RQ
         */
 
-       work_done = vnic_cq_service(&enic->cq[cq],
-               work_to_do, enic_rq_service, NULL);
+       if (budget > 0)
+               work_done = vnic_cq_service(&enic->cq[cq],
+                       work_to_do, enic_rq_service, NULL);
 
        /* Return intr event credits for this polling
         * cycle.  An intr event is the completion of a
@@ -1796,7 +1798,8 @@ static int enic_set_intr_mode(struct enic *enic)
            enic->cq_count >= n + m &&
            enic->intr_count >= n + m + 2) {
 
-               if (!pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) {
+               if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
+                                         n + m + 2, n + m + 2) > 0) {
 
                        enic->rq_count = n;
                        enic->wq_count = m;
@@ -1815,7 +1818,8 @@ static int enic_set_intr_mode(struct enic *enic)
            enic->wq_count >= m &&
            enic->cq_count >= 1 + m &&
            enic->intr_count >= 1 + m + 2) {
-               if (!pci_enable_msix(enic->pdev, enic->msix_entry, 1 + m + 2)) {
+               if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
+                                         1 + m + 2, 1 + m + 2) > 0) {
 
                        enic->rq_count = 1;
                        enic->wq_count = m;
index a1a2b4028a5c6675cbf84e35c1cbca9d8f2663f0..8c4b93be333bc704a736fa8333977f7b76800aad 100644 (file)
@@ -1033,7 +1033,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_unlock_irqrestore(&db->lock, flags);
 
        /* free this SKB */
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
index 5ad9e3e3c0b8a5095564ae4c4369c3ac531c9591..53f0c618045c937b7edfbcbdb35083914c92bdd9 100644 (file)
@@ -696,7 +696,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
        /* Too large packet check */
        if (skb->len > MAX_PACKET_SIZE) {
                pr_err("big packet = %d\n", (u16)skb->len);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -743,7 +743,7 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
        dw32(DCR7, db->cr7_data);
 
        /* free this SKB */
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
index add05f14b38be17311f3344bd23860064fac8ce1..1642de78aac84c86b51cbae27c16d9748d70fb19 100644 (file)
@@ -1939,6 +1939,7 @@ static void tulip_remove_one(struct pci_dev *pdev)
        pci_iounmap(pdev, tp->base_addr);
        free_netdev (dev);
        pci_release_regions (pdev);
+       pci_disable_device(pdev);
 
        /* pci_power_off (pdev, -1); */
 }
index aa4ee385091faa850c0ddd9e6f89146be4c401cf..aa801a6af7b9904752c7f3acebc2d01940527128 100644 (file)
@@ -607,7 +607,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
        /* Too large packet check */
        if (skb->len > MAX_PACKET_SIZE) {
                netdev_err(dev, "big packet = %d\n", (u16)skb->len);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -648,7 +648,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
        uw32(DCR7, db->cr7_data);
 
        /* free this SKB */
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
index 113cd799a131f925fcbd3b5946d4f185249d376f..d9e5ca0d48c125c88e55b319975fcab5e0a4ad99 100644 (file)
@@ -1137,7 +1137,7 @@ start_tx (struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_OK;
 
 drop_frame:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        np->tx_skbuff[entry] = NULL;
        dev->stats.tx_dropped++;
        return NETDEV_TX_OK;
index 8a79a32a5674127e58992bac133fadce0d049ef1..e9b0faba3078aa5757f80be9d3355bc21efdd1db 100644 (file)
@@ -170,11 +170,6 @@ static int dnet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        return 0;
 }
 
-static int dnet_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static void dnet_handle_link_change(struct net_device *dev)
 {
        struct dnet *bp = netdev_priv(dev);
@@ -322,7 +317,6 @@ static int dnet_mii_init(struct dnet *bp)
        bp->mii_bus->name = "dnet_mii_bus";
        bp->mii_bus->read = &dnet_mdio_read;
        bp->mii_bus->write = &dnet_mdio_write;
-       bp->mii_bus->reset = &dnet_mdio_reset;
 
        snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                bp->pdev->name, bp->pdev->id);
index 8d09615da585671a4d0fa9d00dc9cc6ba80f6517..8ccaa2520dc3e9f154ae10b5e866e99173531274 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -34,7 +34,7 @@
 #include "be_hw.h"
 #include "be_roce.h"
 
-#define DRV_VER                        "10.0.600.0u"
+#define DRV_VER                        "10.2u"
 #define DRV_NAME               "be2net"
 #define BE_NAME                        "Emulex BladeEngine2"
 #define BE3_NAME               "Emulex BladeEngine3"
@@ -88,7 +88,6 @@ static inline char *nic_name(struct pci_dev *pdev)
 #define BE_MIN_MTU             256
 
 #define BE_NUM_VLANS_SUPPORTED 64
-#define BE_UMC_NUM_VLANS_SUPPORTED     15
 #define BE_MAX_EQD             128u
 #define        BE_MAX_TX_FRAG_COUNT    30
 
@@ -262,9 +261,10 @@ struct be_tx_obj {
 /* Struct to remember the pages posted for rx frags */
 struct be_rx_page_info {
        struct page *page;
+       /* set to page-addr for last frag of the page & frag-addr otherwise */
        DEFINE_DMA_UNMAP_ADDR(bus);
        u16 page_offset;
-       bool last_page_user;
+       bool last_frag;         /* last frag of the page */
 };
 
 struct be_rx_stats {
@@ -293,9 +293,10 @@ struct be_rx_compl_info {
        u8 ip_csum;
        u8 l4_csum;
        u8 ipv6;
-       u8 vtm;
+       u8 qnq;
        u8 pkt_type;
        u8 ip_frag;
+       u8 tunneled;
 };
 
 struct be_rx_obj {
@@ -350,13 +351,16 @@ struct be_drv_stats {
        u32 roce_drops_crc;
 };
 
+/* A vlan-id of 0xFFFF must be used to clear transparent vlan-tagging */
+#define BE_RESET_VLAN_TAG_ID   0xFFFF
+
 struct be_vf_cfg {
        unsigned char mac_addr[ETH_ALEN];
        int if_handle;
        int pmac_id;
-       u16 def_vid;
        u16 vlan_tag;
        u32 tx_rate;
+       u32 plink_tracking;
 };
 
 enum vf_state {
@@ -368,10 +372,11 @@ enum vf_state {
 #define BE_FLAGS_WORKER_SCHEDULED              (1 << 3)
 #define BE_FLAGS_VLAN_PROMISC                  (1 << 4)
 #define BE_FLAGS_NAPI_ENABLED                  (1 << 9)
-#define BE_UC_PMAC_COUNT               30
-#define BE_VF_UC_PMAC_COUNT            2
 #define BE_FLAGS_QNQ_ASYNC_EVT_RCVD            (1 << 11)
+#define BE_FLAGS_VXLAN_OFFLOADS                        (1 << 12)
 
+#define BE_UC_PMAC_COUNT                       30
+#define BE_VF_UC_PMAC_COUNT                    2
 /* Ethtool set_dump flags */
 #define LANCER_INITIATE_FW_DUMP                        0x1
 
@@ -465,6 +470,7 @@ struct be_adapter {
 
        u32 port_num;
        bool promiscuous;
+       u8 mc_type;
        u32 function_mode;
        u32 function_caps;
        u32 rx_fc;              /* Rx flow control */
@@ -490,6 +496,7 @@ struct be_adapter {
        u32 sli_family;
        u8 hba_port_num;
        u16 pvid;
+       __be16 vxlan_port;
        struct phy_info phy;
        u8 wol_cap;
        bool wol_en;
@@ -534,6 +541,14 @@ static inline u16 be_max_qs(struct be_adapter *adapter)
        return min_t(u16, num, num_online_cpus());
 }
 
+/* Is BE in pvid_tagging mode */
+#define be_pvid_tagging_enabled(adapter)       (adapter->pvid)
+
+/* Is BE in QNQ multi-channel mode */
+#define be_is_qnq_mode(adapter)                (adapter->mc_type == FLEX10 ||  \
+                                        adapter->mc_type == vNIC1 ||   \
+                                        adapter->mc_type == UFP)
+
 #define lancer_chip(adapter)   (adapter->pdev->device == OC_DEVICE_ID3 || \
                                 adapter->pdev->device == OC_DEVICE_ID4)
 
index 48076a6370c3546df9fadef933337d9b77ffca6c..d1ec15af0d2482f46c425bb7d2f6c99976c16329 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -202,8 +202,12 @@ static void be_async_link_state_process(struct be_adapter *adapter,
        /* When link status changes, link speed must be re-queried from FW */
        adapter->phy.link_speed = -1;
 
-       /* Ignore physical link event */
-       if (lancer_chip(adapter) &&
+       /* On BEx the FW does not send a separate link status
+        * notification for physical and logical link.
+        * On other chips just process the logical link
+        * status notification
+        */
+       if (!BEx_chip(adapter) &&
            !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK))
                return;
 
@@ -211,7 +215,8 @@ static void be_async_link_state_process(struct be_adapter *adapter,
         * it may not be received in some cases.
         */
        if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT)
-               be_link_status_update(adapter, evt->port_link_status);
+               be_link_status_update(adapter,
+                                     evt->port_link_status & LINK_STATUS_MASK);
 }
 
 /* Grp5 CoS Priority evt */
@@ -239,10 +244,12 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter,
 static void be_async_grp5_pvid_state_process(struct be_adapter *adapter,
                struct be_async_event_grp5_pvid_state *evt)
 {
-       if (evt->enabled)
+       if (evt->enabled) {
                adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK;
-       else
+               dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid);
+       } else {
                adapter->pvid = 0;
+       }
 }
 
 static void be_async_grp5_evt_process(struct be_adapter *adapter,
@@ -3296,6 +3303,21 @@ static struct be_pcie_res_desc *be_get_pcie_desc(u8 devfn, u8 *buf,
        return NULL;
 }
 
+static struct be_port_res_desc *be_get_port_desc(u8 *buf, u32 desc_count)
+{
+       struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf;
+       int i;
+
+       for (i = 0; i < desc_count; i++) {
+               if (hdr->desc_type == PORT_RESOURCE_DESC_TYPE_V1)
+                       return (struct be_port_res_desc *)hdr;
+
+               hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0;
+               hdr = (void *)hdr + hdr->desc_len;
+       }
+       return NULL;
+}
+
 static void be_copy_nic_desc(struct be_resources *res,
                             struct be_nic_res_desc *desc)
 {
@@ -3439,6 +3461,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
 {
        struct be_cmd_resp_get_profile_config *resp;
        struct be_pcie_res_desc *pcie;
+       struct be_port_res_desc *port;
        struct be_nic_res_desc *nic;
        struct be_queue_info *mccq = &adapter->mcc_obj.q;
        struct be_dma_mem cmd;
@@ -3466,6 +3489,10 @@ int be_cmd_get_profile_config(struct be_adapter *adapter,
        if (pcie)
                res->max_vfs = le16_to_cpu(pcie->num_vfs);
 
+       port = be_get_port_desc(resp->func_param, desc_count);
+       if (port)
+               adapter->mc_type = port->mc_type;
+
        nic = be_get_nic_desc(resp->func_param, desc_count);
        if (nic)
                be_copy_nic_desc(res, nic);
@@ -3476,14 +3503,11 @@ err:
        return status;
 }
 
-/* Currently only Lancer uses this command and it supports version 0 only
- * Uses sync mcc
- */
-int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
-                             u8 domain)
+int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
+                             int size, u8 version, u8 domain)
 {
-       struct be_mcc_wrb *wrb;
        struct be_cmd_req_set_profile_config *req;
+       struct be_mcc_wrb *wrb;
        int status;
 
        spin_lock_bh(&adapter->mcc_lock);
@@ -3495,44 +3519,116 @@ int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps,
        }
 
        req = embedded_payload(wrb);
-
        be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
                               OPCODE_COMMON_SET_PROFILE_CONFIG, sizeof(*req),
                               wrb, NULL);
+       req->hdr.version = version;
        req->hdr.domain = domain;
        req->desc_count = cpu_to_le32(1);
-       req->nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0;
-       req->nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0;
-       req->nic_desc.flags = (1 << QUN) | (1 << IMM) | (1 << NOSV);
-       req->nic_desc.pf_num = adapter->pf_number;
-       req->nic_desc.vf_num = domain;
-
-       /* Mark fields invalid */
-       req->nic_desc.unicast_mac_count = 0xFFFF;
-       req->nic_desc.mcc_count = 0xFFFF;
-       req->nic_desc.vlan_count = 0xFFFF;
-       req->nic_desc.mcast_mac_count = 0xFFFF;
-       req->nic_desc.txq_count = 0xFFFF;
-       req->nic_desc.rq_count = 0xFFFF;
-       req->nic_desc.rssq_count = 0xFFFF;
-       req->nic_desc.lro_count = 0xFFFF;
-       req->nic_desc.cq_count = 0xFFFF;
-       req->nic_desc.toe_conn_count = 0xFFFF;
-       req->nic_desc.eq_count = 0xFFFF;
-       req->nic_desc.link_param = 0xFF;
-       req->nic_desc.bw_min = 0xFFFFFFFF;
-       req->nic_desc.acpi_params = 0xFF;
-       req->nic_desc.wol_param = 0x0F;
-
-       /* Change BW */
-       req->nic_desc.bw_min = cpu_to_le32(bps);
-       req->nic_desc.bw_max = cpu_to_le32(bps);
+       memcpy(req->desc, desc, size);
+
        status = be_mcc_notify_wait(adapter);
 err:
        spin_unlock_bh(&adapter->mcc_lock);
        return status;
 }
 
+/* Mark all fields invalid */
+void be_reset_nic_desc(struct be_nic_res_desc *nic)
+{
+       memset(nic, 0, sizeof(*nic));
+       nic->unicast_mac_count = 0xFFFF;
+       nic->mcc_count = 0xFFFF;
+       nic->vlan_count = 0xFFFF;
+       nic->mcast_mac_count = 0xFFFF;
+       nic->txq_count = 0xFFFF;
+       nic->rq_count = 0xFFFF;
+       nic->rssq_count = 0xFFFF;
+       nic->lro_count = 0xFFFF;
+       nic->cq_count = 0xFFFF;
+       nic->toe_conn_count = 0xFFFF;
+       nic->eq_count = 0xFFFF;
+       nic->link_param = 0xFF;
+       nic->acpi_params = 0xFF;
+       nic->wol_param = 0x0F;
+       nic->bw_min = 0xFFFFFFFF;
+       nic->bw_max = 0xFFFFFFFF;
+}
+
+int be_cmd_config_qos(struct be_adapter *adapter, u32 bps, u8 domain)
+{
+       if (lancer_chip(adapter)) {
+               struct be_nic_res_desc nic_desc;
+
+               be_reset_nic_desc(&nic_desc);
+               nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0;
+               nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0;
+               nic_desc.flags = (1 << QUN_SHIFT) | (1 << IMM_SHIFT) |
+                                       (1 << NOSV_SHIFT);
+               nic_desc.pf_num = adapter->pf_number;
+               nic_desc.vf_num = domain;
+               nic_desc.bw_max = cpu_to_le32(bps);
+
+               return be_cmd_set_profile_config(adapter, &nic_desc,
+                                                RESOURCE_DESC_SIZE_V0,
+                                                0, domain);
+       } else {
+               return be_cmd_set_qos(adapter, bps, domain);
+       }
+}
+
+int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_manage_iface_filters *req;
+       int status;
+
+       if (iface == 0xFFFFFFFF)
+               return -1;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                              OPCODE_COMMON_MANAGE_IFACE_FILTERS, sizeof(*req),
+                              wrb, NULL);
+       req->op = op;
+       req->target_iface_id = cpu_to_le32(iface);
+
+       status = be_mcc_notify_wait(adapter);
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
+int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port)
+{
+       struct be_port_res_desc port_desc;
+
+       memset(&port_desc, 0, sizeof(port_desc));
+       port_desc.hdr.desc_type = PORT_RESOURCE_DESC_TYPE_V1;
+       port_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V1;
+       port_desc.flags = (1 << IMM_SHIFT) | (1 << NOSV_SHIFT);
+       port_desc.link_num = adapter->hba_port_num;
+       if (port) {
+               port_desc.nv_flags = NV_TYPE_VXLAN | (1 << SOCVID_SHIFT) |
+                                       (1 << RCVID_SHIFT);
+               port_desc.nv_port = swab16(port);
+       } else {
+               port_desc.nv_flags = NV_TYPE_DISABLED;
+               port_desc.nv_port = 0;
+       }
+
+       return be_cmd_set_profile_config(adapter, &port_desc,
+                                        RESOURCE_DESC_SIZE_V1, 1, 0);
+}
+
 int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
                     int vf_num)
 {
@@ -3723,6 +3819,45 @@ err:
        return status;
 }
 
+int be_cmd_set_logical_link_config(struct be_adapter *adapter,
+                                  int link_state, u8 domain)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_set_ll_link *req;
+       int status;
+
+       if (BEx_chip(adapter) || lancer_chip(adapter))
+               return 0;
+
+       spin_lock_bh(&adapter->mcc_lock);
+
+       wrb = wrb_from_mccq(adapter);
+       if (!wrb) {
+               status = -EBUSY;
+               goto err;
+       }
+
+       req = embedded_payload(wrb);
+
+       be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                              OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG,
+                              sizeof(*req), wrb, NULL);
+
+       req->hdr.version = 1;
+       req->hdr.domain = domain;
+
+       if (link_state == IFLA_VF_LINK_STATE_ENABLE)
+               req->link_config |= 1;
+
+       if (link_state == IFLA_VF_LINK_STATE_AUTO)
+               req->link_config |= 1 << PLINK_TRACK_SHIFT;
+
+       status = be_mcc_notify_wait(adapter);
+err:
+       spin_unlock_bh(&adapter->mcc_lock);
+       return status;
+}
+
 int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,
                        int wrb_payload_size, u16 *cmd_status, u16 *ext_status)
 {
index fc4e076dc202624721c7d505a482ca64d6c984d4..b60e4d53c1c9a9f29be9d1c2c07099dab28b378a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -203,6 +203,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_BEACON_STATE                 70
 #define OPCODE_COMMON_READ_TRANSRECV_DATA              73
 #define OPCODE_COMMON_GET_PORT_NAME                    77
+#define OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG          80
 #define OPCODE_COMMON_SET_INTERRUPT_ENABLE             89
 #define OPCODE_COMMON_SET_FN_PRIVILEGES                        100
 #define OPCODE_COMMON_GET_PHY_DETAILS                  102
@@ -221,6 +222,7 @@ struct be_mcc_mailbox {
 #define OPCODE_COMMON_GET_FN_PRIVILEGES                        170
 #define OPCODE_COMMON_READ_OBJECT                      171
 #define OPCODE_COMMON_WRITE_OBJECT                     172
+#define OPCODE_COMMON_MANAGE_IFACE_FILTERS             193
 #define OPCODE_COMMON_GET_IFACE_LIST                   194
 #define OPCODE_COMMON_ENABLE_DISABLE_VF                        196
 
@@ -1098,14 +1100,6 @@ struct be_cmd_resp_query_fw_cfg {
        u32 function_caps;
 };
 
-/* Is BE in a multi-channel mode */
-static inline bool be_is_mc(struct be_adapter *adapter)
-{
-       return adapter->function_mode & FLEX10_MODE ||
-               adapter->function_mode & VNIC_MODE ||
-               adapter->function_mode & UMC_ENABLED;
-}
-
 /******************** RSS Config ****************************************/
 /* RSS type            Input parameters used to compute RX hash
  * RSS_ENABLE_IPV4     SRC IPv4, DST IPv4
@@ -1828,20 +1822,36 @@ struct be_cmd_req_set_ext_fat_caps {
 #define NIC_RESOURCE_DESC_TYPE_V0              0x41
 #define PCIE_RESOURCE_DESC_TYPE_V1             0x50
 #define NIC_RESOURCE_DESC_TYPE_V1              0x51
+#define PORT_RESOURCE_DESC_TYPE_V1             0x55
 #define MAX_RESOURCE_DESC                      264
 
-/* QOS unit number */
-#define QUN                                    4
-/* Immediate */
-#define IMM                                    6
-/* No save */
-#define NOSV                                   7
+#define IMM_SHIFT                              6       /* Immediate */
+#define NOSV_SHIFT                             7       /* No save */
 
 struct be_res_desc_hdr {
        u8 desc_type;
        u8 desc_len;
 } __packed;
 
+struct be_port_res_desc {
+       struct be_res_desc_hdr hdr;
+       u8 rsvd0;
+       u8 flags;
+       u8 link_num;
+       u8 mc_type;
+       u16 rsvd1;
+
+#define NV_TYPE_MASK                           0x3     /* bits 0-1 */
+#define NV_TYPE_DISABLED                       1
+#define NV_TYPE_VXLAN                          3
+#define SOCVID_SHIFT                           2       /* Strip outer vlan */
+#define RCVID_SHIFT                            4       /* Report vlan */
+       u8 nv_flags;
+       u8 rsvd2;
+       __le16 nv_port;                                 /* vxlan/gre port */
+       u32 rsvd3[19];
+} __packed;
+
 struct be_pcie_res_desc {
        struct be_res_desc_hdr hdr;
        u8 rsvd0;
@@ -1862,6 +1872,8 @@ struct be_pcie_res_desc {
 struct be_nic_res_desc {
        struct be_res_desc_hdr hdr;
        u8 rsvd1;
+
+#define QUN_SHIFT                              4 /* QoS is in absolute units */
        u8 flags;
        u8 vf_num;
        u8 rsvd2;
@@ -1891,6 +1903,23 @@ struct be_nic_res_desc {
        u32 rsvd8[7];
 } __packed;
 
+/************ Multi-Channel type ***********/
+enum mc_type {
+       MC_NONE = 0x01,
+       UMC = 0x02,
+       FLEX10 = 0x03,
+       vNIC1 = 0x04,
+       nPAR = 0x05,
+       UFP = 0x06,
+       vNIC2 = 0x07
+};
+
+/* Is BE in a multi-channel mode */
+static inline bool be_is_mc(struct be_adapter *adapter)
+{
+       return adapter->mc_type > MC_NONE;
+}
+
 struct be_cmd_req_get_func_config {
        struct be_cmd_req_hdr hdr;
 };
@@ -1919,7 +1948,7 @@ struct be_cmd_req_set_profile_config {
        struct be_cmd_req_hdr hdr;
        u32 rsvd;
        u32 desc_count;
-       struct be_nic_res_desc nic_desc;
+       u8 desc[RESOURCE_DESC_SIZE_V1];
 };
 
 struct be_cmd_resp_set_profile_config {
@@ -1971,6 +2000,33 @@ struct be_cmd_resp_get_iface_list {
        struct be_if_desc if_desc;
 };
 
+/*************** Set logical link ********************/
+#define PLINK_TRACK_SHIFT      8
+struct be_cmd_req_set_ll_link {
+       struct be_cmd_req_hdr hdr;
+       u32 link_config; /* Bit 0: UP_DOWN, Bit 9: PLINK */
+};
+
+/************** Manage IFACE Filters *******************/
+#define OP_CONVERT_NORMAL_TO_TUNNEL            0
+#define OP_CONVERT_TUNNEL_TO_NORMAL            1
+
+struct be_cmd_req_manage_iface_filters {
+       struct be_cmd_req_hdr hdr;
+       u8  op;
+       u8  rsvd0;
+       u8  flags;
+       u8  rsvd1;
+       u32 tunnel_iface_id;
+       u32 target_iface_id;
+       u8  mac[6];
+       u16 vlan_tag;
+       u32 tenant_id;
+       u32 filter_id;
+       u32 cap_flags;
+       u32 cap_control_flags;
+} __packed;
+
 int be_pci_fnum_get(struct be_adapter *adapter);
 int be_fw_wait_ready(struct be_adapter *adapter);
 int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -2045,7 +2101,7 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
 int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
                        u8 loopback_type, u8 enable);
 int be_cmd_get_phy_info(struct be_adapter *adapter);
-int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
+int be_cmd_config_qos(struct be_adapter *adapter, u32 bps, u8 domain);
 void be_detect_error(struct be_adapter *adapter);
 int be_cmd_get_die_temperature(struct be_adapter *adapter);
 int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
@@ -2086,9 +2142,14 @@ int be_cmd_get_func_config(struct be_adapter *adapter,
                           struct be_resources *res);
 int be_cmd_get_profile_config(struct be_adapter *adapter,
                              struct be_resources *res, u8 domain);
-int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps, u8 domain);
+int be_cmd_set_profile_config(struct be_adapter *adapter, void *desc,
+                             int size, u8 version, u8 domain);
 int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile);
 int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg,
                     int vf_num);
 int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain);
 int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable);
+int be_cmd_set_logical_link_config(struct be_adapter *adapter,
+                                         int link_state, u8 domain);
+int be_cmd_set_vxlan_port(struct be_adapter *adapter, __be16 port);
+int be_cmd_manage_iface(struct be_adapter *adapter, u32 iface, u8 op);
index 05be0070f55fd453ed1cb35427c44d921ba08443..15ba96cba65df1ba051cc3b2e49b72640d92c217 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -357,10 +357,10 @@ be_get_ethtool_stats(struct net_device *netdev,
                struct be_rx_stats *stats = rx_stats(rxo);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->sync);
+                       start = u64_stats_fetch_begin_irq(&stats->sync);
                        data[base] = stats->rx_bytes;
                        data[base + 1] = stats->rx_pkts;
-               } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&stats->sync, start));
 
                for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
                        p = (u8 *)stats + et_rx_stats[i].offset;
@@ -373,19 +373,19 @@ be_get_ethtool_stats(struct net_device *netdev,
                struct be_tx_stats *stats = tx_stats(txo);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->sync_compl);
+                       start = u64_stats_fetch_begin_irq(&stats->sync_compl);
                        data[base] = stats->tx_compl;
-               } while (u64_stats_fetch_retry_bh(&stats->sync_compl, start));
+               } while (u64_stats_fetch_retry_irq(&stats->sync_compl, start));
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->sync);
+                       start = u64_stats_fetch_begin_irq(&stats->sync);
                        for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
                                p = (u8 *)stats + et_tx_stats[i].offset;
                                data[base + i] =
                                        (et_tx_stats[i].size == sizeof(u64)) ?
                                                *(u64 *)p : *(u32 *)p;
                        }
-               } while (u64_stats_fetch_retry_bh(&stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&stats->sync, start));
                base += ETHTOOL_TXSTATS_NUM;
        }
 }
@@ -802,16 +802,18 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
 
        if (test->flags & ETH_TEST_FL_OFFLINE) {
                if (be_loopback_test(adapter, BE_MAC_LOOPBACK,
-                                               &data[0]) != 0) {
+                                    &data[0]) != 0)
                        test->flags |= ETH_TEST_FL_FAILED;
-               }
+
                if (be_loopback_test(adapter, BE_PHY_LOOPBACK,
-                                               &data[1]) != 0) {
-                       test->flags |= ETH_TEST_FL_FAILED;
-               }
-               if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
-                                               &data[2]) != 0) {
+                                    &data[1]) != 0)
                        test->flags |= ETH_TEST_FL_FAILED;
+
+               if (test->flags & ETH_TEST_FL_EXTERNAL_LB) {
+                       if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
+                                            &data[2]) != 0)
+                               test->flags |= ETH_TEST_FL_FAILED;
+                       test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
                }
        }
 
index dc88782185f26f000e4e58cd793f90f6064bbfb6..3bd198550edbb95a64602e28535e8eb56758a220 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -368,7 +368,7 @@ struct amap_eth_rx_compl_v0 {
        u8 numfrags[3];         /* dword 1 */
        u8 rss_flush;           /* dword 2 */
        u8 cast_enc[2];         /* dword 2 */
-       u8 vtm;                 /* dword 2 */
+       u8 qnq;                 /* dword 2 */
        u8 rss_bank;            /* dword 2 */
        u8 rsvd1[23];           /* dword 2 */
        u8 lro_pkt;             /* dword 2 */
@@ -401,13 +401,14 @@ struct amap_eth_rx_compl_v1 {
        u8 numfrags[3];         /* dword 1 */
        u8 rss_flush;           /* dword 2 */
        u8 cast_enc[2];         /* dword 2 */
-       u8 vtm;                 /* dword 2 */
+       u8 qnq;                 /* dword 2 */
        u8 rss_bank;            /* dword 2 */
        u8 port[2];             /* dword 2 */
        u8 vntagp;              /* dword 2 */
        u8 header_len[8];       /* dword 2 */
        u8 header_split[2];     /* dword 2 */
-       u8 rsvd1[13];           /* dword 2 */
+       u8 rsvd1[12];           /* dword 2 */
+       u8 tunneled;
        u8 valid;               /* dword 2 */
        u8 rsshash[32];         /* dword 3 */
 } __packed;
index 04ac9c6a0d3972d4e18ee91a8ce3a8bf2e141cd7..c89dc85ad8d60439f02039f96f7d756591415bf6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -23,6 +23,7 @@
 #include <linux/aer.h>
 #include <linux/if_bridge.h>
 #include <net/busy_poll.h>
+#include <net/vxlan.h>
 
 MODULE_VERSION(DRV_VER);
 MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -591,10 +592,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
        for_all_rx_queues(adapter, rxo, i) {
                const struct be_rx_stats *rx_stats = rx_stats(rxo);
                do {
-                       start = u64_stats_fetch_begin_bh(&rx_stats->sync);
+                       start = u64_stats_fetch_begin_irq(&rx_stats->sync);
                        pkts = rx_stats(rxo)->rx_pkts;
                        bytes = rx_stats(rxo)->rx_bytes;
-               } while (u64_stats_fetch_retry_bh(&rx_stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&rx_stats->sync, start));
                stats->rx_packets += pkts;
                stats->rx_bytes += bytes;
                stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
@@ -605,10 +606,10 @@ static struct rtnl_link_stats64 *be_get_stats64(struct net_device *netdev,
        for_all_tx_queues(adapter, txo, i) {
                const struct be_tx_stats *tx_stats = tx_stats(txo);
                do {
-                       start = u64_stats_fetch_begin_bh(&tx_stats->sync);
+                       start = u64_stats_fetch_begin_irq(&tx_stats->sync);
                        pkts = tx_stats(txo)->tx_pkts;
                        bytes = tx_stats(txo)->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tx_stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&tx_stats->sync, start));
                stats->tx_packets += pkts;
                stats->tx_bytes += bytes;
        }
@@ -652,7 +653,7 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status)
                adapter->flags |= BE_FLAGS_LINK_STATUS_INIT;
        }
 
-       if ((link_status & LINK_STATUS_MASK) == LINK_UP)
+       if (link_status)
                netif_carrier_on(netdev);
        else
                netif_carrier_off(netdev);
@@ -718,10 +719,23 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
        return vlan_tag;
 }
 
+/* Used only for IP tunnel packets */
+static u16 skb_inner_ip_proto(struct sk_buff *skb)
+{
+       return (inner_ip_hdr(skb)->version == 4) ?
+               inner_ip_hdr(skb)->protocol : inner_ipv6_hdr(skb)->nexthdr;
+}
+
+static u16 skb_ip_proto(struct sk_buff *skb)
+{
+       return (ip_hdr(skb)->version == 4) ?
+               ip_hdr(skb)->protocol : ipv6_hdr(skb)->nexthdr;
+}
+
 static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
                struct sk_buff *skb, u32 wrb_cnt, u32 len, bool skip_hw_vlan)
 {
-       u16 vlan_tag;
+       u16 vlan_tag, proto;
 
        memset(hdr, 0, sizeof(*hdr));
 
@@ -734,9 +748,15 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
                if (skb_is_gso_v6(skb) && !lancer_chip(adapter))
                        AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               if (is_tcp_pkt(skb))
+               if (skb->encapsulation) {
+                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, ipcs, hdr, 1);
+                       proto = skb_inner_ip_proto(skb);
+               } else {
+                       proto = skb_ip_proto(skb);
+               }
+               if (proto == IPPROTO_TCP)
                        AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
-               else if (is_udp_pkt(skb))
+               else if (proto == IPPROTO_UDP)
                        AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
        }
 
@@ -913,24 +933,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter,
        return BE3_chip(adapter) && be_ipv6_exthdr_check(skb);
 }
 
-static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
-                                          struct sk_buff *skb,
-                                          bool *skip_hw_vlan)
+static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+                                                 struct sk_buff *skb,
+                                                 bool *skip_hw_vlan)
 {
        struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
        unsigned int eth_hdr_len;
        struct iphdr *ip;
 
-       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less
-        * may cause a transmit stall on that port. So the work-around is to
-        * pad short packets (<= 32 bytes) to a 36-byte length.
-        */
-       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
-               if (skb_padto(skb, 36))
-                       goto tx_drop;
-               skb->len = 36;
-       }
-
        /* For padded packets, BE HW modifies tot_len field in IP header
         * incorrecly when VLAN tag is inserted by HW.
         * For padded packets, Lancer computes incorrect checksum.
@@ -945,9 +955,9 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
        }
 
        /* If vlan tag is already inlined in the packet, skip HW VLAN
-        * tagging in UMC mode
+        * tagging in pvid-tagging mode
         */
-       if ((adapter->function_mode & UMC_ENABLED) &&
+       if (be_pvid_tagging_enabled(adapter) &&
            veh->h_vlan_proto == htons(ETH_P_8021Q))
                        *skip_hw_vlan = true;
 
@@ -959,7 +969,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            vlan_tx_tag_present(skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        /* HW may lockup when VLAN HW tagging is requested on
@@ -981,15 +991,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
            be_vlan_tag_tx_chk(adapter, skb)) {
                skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
                if (unlikely(!skb))
-                       goto tx_drop;
+                       goto err;
        }
 
        return skb;
 tx_drop:
        dev_kfree_skb_any(skb);
+err:
        return NULL;
 }
 
+static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
+                                          struct sk_buff *skb,
+                                          bool *skip_hw_vlan)
+{
+       /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or
+        * less may cause a transmit stall on that port. So the work-around is
+        * to pad short packets (<= 32 bytes) to a 36-byte length.
+        */
+       if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) {
+               if (skb_padto(skb, 36))
+                       return NULL;
+               skb->len = 36;
+       }
+
+       if (BEx_chip(adapter) || lancer_chip(adapter)) {
+               skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan);
+               if (!skb)
+                       return NULL;
+       }
+
+       return skb;
+}
+
 static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1124,7 +1158,10 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
 
        /* Packets with VID 0 are always received by Lancer by default */
        if (lancer_chip(adapter) && vid == 0)
-               goto ret;
+               return status;
+
+       if (adapter->vlan_tag[vid])
+               return status;
 
        adapter->vlan_tag[vid] = 1;
        adapter->vlans_added++;
@@ -1134,7 +1171,7 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
                adapter->vlans_added--;
                adapter->vlan_tag[vid] = 0;
        }
-ret:
+
        return status;
 }
 
@@ -1157,6 +1194,14 @@ ret:
        return status;
 }
 
+static void be_clear_promisc(struct be_adapter *adapter)
+{
+       adapter->promiscuous = false;
+       adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
+
+       be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+}
+
 static void be_set_rx_mode(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
@@ -1170,9 +1215,7 @@ static void be_set_rx_mode(struct net_device *netdev)
 
        /* BE was previously in promiscuous mode; disable it */
        if (adapter->promiscuous) {
-               adapter->promiscuous = false;
-               be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
-
+               be_clear_promisc(adapter);
                if (adapter->vlans_added)
                        be_vid_config(adapter);
        }
@@ -1268,6 +1311,7 @@ static int be_get_vf_config(struct net_device *netdev, int vf,
        vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK;
        vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT;
        memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN);
+       vi->linkstate = adapter->vf_cfg[vf].plink_tracking;
 
        return 0;
 }
@@ -1287,24 +1331,20 @@ static int be_set_vf_vlan(struct net_device *netdev,
 
        if (vlan || qos) {
                vlan |= qos << VLAN_PRIO_SHIFT;
-               if (vf_cfg->vlan_tag != vlan) {
-                       /* If this is new value, program it. Else skip. */
-                       vf_cfg->vlan_tag = vlan;
+               if (vf_cfg->vlan_tag != vlan)
                        status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
                                                       vf_cfg->if_handle, 0);
-               }
        } else {
                /* Reset Transparent Vlan Tagging. */
-               vf_cfg->vlan_tag = 0;
-               vlan = vf_cfg->def_vid;
-               status = be_cmd_set_hsw_config(adapter, vlan, vf + 1,
-                                              vf_cfg->if_handle, 0);
+               status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID,
+                                              vf + 1, vf_cfg->if_handle, 0);
        }
 
-
-       if (status)
+       if (!status)
+               vf_cfg->vlan_tag = vlan;
+       else
                dev_info(&adapter->pdev->dev,
-                               "VLAN %d config on VF %d failed\n", vlan, vf);
+                        "VLAN %d config on VF %d failed\n", vlan, vf);
        return status;
 }
 
@@ -1326,11 +1366,7 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
                return -EINVAL;
        }
 
-       if (lancer_chip(adapter))
-               status = be_cmd_set_profile_config(adapter, rate / 10, vf + 1);
-       else
-               status = be_cmd_set_qos(adapter, rate / 10, vf + 1);
-
+       status = be_cmd_config_qos(adapter, rate / 10, vf + 1);
        if (status)
                dev_err(&adapter->pdev->dev,
                                "tx rate %d on VF %d failed\n", rate, vf);
@@ -1338,6 +1374,24 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
                adapter->vf_cfg[vf].tx_rate = rate;
        return status;
 }
+static int be_set_vf_link_state(struct net_device *netdev, int vf,
+                               int link_state)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       int status;
+
+       if (!sriov_enabled(adapter))
+               return -EPERM;
+
+       if (vf >= adapter->num_vfs)
+               return -EINVAL;
+
+       status = be_cmd_set_logical_link_config(adapter, link_state, vf+1);
+       if (!status)
+               adapter->vf_cfg[vf].plink_tracking = link_state;
+
+       return status;
+}
 
 static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts,
                          ulong now)
@@ -1370,15 +1424,15 @@ static void be_eqd_update(struct be_adapter *adapter)
 
                rxo = &adapter->rx_obj[eqo->idx];
                do {
-                       start = u64_stats_fetch_begin_bh(&rxo->stats.sync);
+                       start = u64_stats_fetch_begin_irq(&rxo->stats.sync);
                        rx_pkts = rxo->stats.rx_pkts;
-               } while (u64_stats_fetch_retry_bh(&rxo->stats.sync, start));
+               } while (u64_stats_fetch_retry_irq(&rxo->stats.sync, start));
 
                txo = &adapter->tx_obj[eqo->idx];
                do {
-                       start = u64_stats_fetch_begin_bh(&txo->stats.sync);
+                       start = u64_stats_fetch_begin_irq(&txo->stats.sync);
                        tx_pkts = txo->stats.tx_reqs;
-               } while (u64_stats_fetch_retry_bh(&txo->stats.sync, start));
+               } while (u64_stats_fetch_retry_irq(&txo->stats.sync, start));
 
 
                /* Skip, if wrapped around or first calculation */
@@ -1433,9 +1487,10 @@ static void be_rx_stats_update(struct be_rx_obj *rxo,
 static inline bool csum_passed(struct be_rx_compl_info *rxcp)
 {
        /* L4 checksum is not reliable for non TCP/UDP packets.
-        * Also ignore ipcksm for ipv6 pkts */
+        * Also ignore ipcksm for ipv6 pkts
+        */
        return (rxcp->tcpf || rxcp->udpf) && rxcp->l4_csum &&
-                               (rxcp->ip_csum || rxcp->ipv6);
+               (rxcp->ip_csum || rxcp->ipv6) && !rxcp->err;
 }
 
 static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
@@ -1448,11 +1503,15 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo)
        rx_page_info = &rxo->page_info_tbl[frag_idx];
        BUG_ON(!rx_page_info->page);
 
-       if (rx_page_info->last_page_user) {
+       if (rx_page_info->last_frag) {
                dma_unmap_page(&adapter->pdev->dev,
                               dma_unmap_addr(rx_page_info, bus),
                               adapter->big_page_size, DMA_FROM_DEVICE);
-               rx_page_info->last_page_user = false;
+               rx_page_info->last_frag = false;
+       } else {
+               dma_sync_single_for_cpu(&adapter->pdev->dev,
+                                       dma_unmap_addr(rx_page_info, bus),
+                                       rx_frag_size, DMA_FROM_DEVICE);
        }
 
        queue_tail_inc(rxq);
@@ -1574,6 +1633,8 @@ static void be_rx_compl_process(struct be_rx_obj *rxo, struct napi_struct *napi,
        skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]);
        if (netdev->features & NETIF_F_RXHASH)
                skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
+
+       skb->encapsulation = rxcp->tunneled;
        skb_mark_napi_id(skb, napi);
 
        if (rxcp->vlanf)
@@ -1630,6 +1691,8 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo,
        skb_record_rx_queue(skb, rxo - &adapter->rx_obj[0]);
        if (adapter->netdev->features & NETIF_F_RXHASH)
                skb_set_hash(skb, rxcp->rss_hash, PKT_HASH_TYPE_L3);
+
+       skb->encapsulation = rxcp->tunneled;
        skb_mark_napi_id(skb, napi);
 
        if (rxcp->vlanf)
@@ -1660,12 +1723,14 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl,
        rxcp->rss_hash =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl);
        if (rxcp->vlanf) {
-               rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
+               rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, qnq,
                                          compl);
                rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
                                               compl);
        }
        rxcp->port = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, port, compl);
+       rxcp->tunneled =
+               AMAP_GET_BITS(struct amap_eth_rx_compl_v1, tunneled, compl);
 }
 
 static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
@@ -1690,7 +1755,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl,
        rxcp->rss_hash =
                AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl);
        if (rxcp->vlanf) {
-               rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
+               rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, qnq,
                                          compl);
                rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
                                               compl);
@@ -1723,9 +1788,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
                rxcp->l4_csum = 0;
 
        if (rxcp->vlanf) {
-               /* vlanf could be wrongly set in some cards.
-                * ignore if vtm is not set */
-               if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm)
+               /* In QNQ modes, if qnq bit is not set, then the packet was
+                * tagged only with the transparent outer vlan-tag and must
+                * not be treated as a vlan packet by host
+                */
+               if (be_is_qnq_mode(adapter) && !rxcp->qnq)
                        rxcp->vlanf = 0;
 
                if (!lancer_chip(adapter))
@@ -1784,17 +1851,16 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
                                rx_stats(rxo)->rx_post_fail++;
                                break;
                        }
-                       page_info->page_offset = 0;
+                       page_offset = 0;
                } else {
                        get_page(pagep);
-                       page_info->page_offset = page_offset + rx_frag_size;
+                       page_offset += rx_frag_size;
                }
-               page_offset = page_info->page_offset;
+               page_info->page_offset = page_offset;
                page_info->page = pagep;
-               dma_unmap_addr_set(page_info, bus, page_dmaaddr);
-               frag_dmaaddr = page_dmaaddr + page_info->page_offset;
 
                rxd = queue_head_node(rxq);
+               frag_dmaaddr = page_dmaaddr + page_info->page_offset;
                rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
                rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
 
@@ -1802,15 +1868,24 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp)
                if ((page_offset + rx_frag_size + rx_frag_size) >
                                        adapter->big_page_size) {
                        pagep = NULL;
-                       page_info->last_page_user = true;
+                       page_info->last_frag = true;
+                       dma_unmap_addr_set(page_info, bus, page_dmaaddr);
+               } else {
+                       dma_unmap_addr_set(page_info, bus, frag_dmaaddr);
                }
 
                prev_page_info = page_info;
                queue_head_inc(rxq);
                page_info = &rxo->page_info_tbl[rxq->head];
        }
-       if (pagep)
-               prev_page_info->last_page_user = true;
+
+       /* Mark the last frag of a page when we break out of the above loop
+        * with no more slots available in the RXQ
+        */
+       if (pagep) {
+               prev_page_info->last_frag = true;
+               dma_unmap_addr_set(prev_page_info, bus, page_dmaaddr);
+       }
 
        if (posted) {
                atomic_add(posted, &rxq->used);
@@ -1867,7 +1942,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter,
                queue_tail_inc(txq);
        } while (cur_index != last_index);
 
-       kfree_skb(sent_skb);
+       dev_kfree_skb_any(sent_skb);
        return num_wrbs;
 }
 
@@ -2423,6 +2498,9 @@ void be_detect_error(struct be_adapter *adapter)
        u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0;
        u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;
        u32 i;
+       bool error_detected = false;
+       struct device *dev = &adapter->pdev->dev;
+       struct net_device *netdev = adapter->netdev;
 
        if (be_hw_error(adapter))
                return;
@@ -2434,6 +2512,21 @@ void be_detect_error(struct be_adapter *adapter)
                                        SLIPORT_ERROR1_OFFSET);
                        sliport_err2 = ioread32(adapter->db +
                                        SLIPORT_ERROR2_OFFSET);
+                       adapter->hw_error = true;
+                       /* Do not log error messages if its a FW reset */
+                       if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
+                           sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
+                               dev_info(dev, "Firmware update in progress\n");
+                       } else {
+                               error_detected = true;
+                               dev_err(dev, "Error detected in the card\n");
+                               dev_err(dev, "ERR: sliport status 0x%x\n",
+                                       sliport_status);
+                               dev_err(dev, "ERR: sliport error1 0x%x\n",
+                                       sliport_err1);
+                               dev_err(dev, "ERR: sliport error2 0x%x\n",
+                                       sliport_err2);
+                       }
                }
        } else {
                pci_read_config_dword(adapter->pdev,
@@ -2447,51 +2540,33 @@ void be_detect_error(struct be_adapter *adapter)
 
                ue_lo = (ue_lo & ~ue_lo_mask);
                ue_hi = (ue_hi & ~ue_hi_mask);
-       }
-
-       /* On certain platforms BE hardware can indicate spurious UEs.
-        * Allow the h/w to stop working completely in case of a real UE.
-        * Hence not setting the hw_error for UE detection.
-        */
-       if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
-               adapter->hw_error = true;
-               /* Do not log error messages if its a FW reset */
-               if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
-                   sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
-                       dev_info(&adapter->pdev->dev,
-                                "Firmware update in progress\n");
-                       return;
-               } else {
-                       dev_err(&adapter->pdev->dev,
-                               "Error detected in the card\n");
-               }
-       }
-
-       if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
-               dev_err(&adapter->pdev->dev,
-                       "ERR: sliport status 0x%x\n", sliport_status);
-               dev_err(&adapter->pdev->dev,
-                       "ERR: sliport error1 0x%x\n", sliport_err1);
-               dev_err(&adapter->pdev->dev,
-                       "ERR: sliport error2 0x%x\n", sliport_err2);
-       }
 
-       if (ue_lo) {
-               for (i = 0; ue_lo; ue_lo >>= 1, i++) {
-                       if (ue_lo & 1)
-                               dev_err(&adapter->pdev->dev,
-                               "UE: %s bit set\n", ue_status_low_desc[i]);
-               }
-       }
+               /* On certain platforms BE hardware can indicate spurious UEs.
+                * Allow HW to stop working completely in case of a real UE.
+                * Hence not setting the hw_error for UE detection.
+                */
 
-       if (ue_hi) {
-               for (i = 0; ue_hi; ue_hi >>= 1, i++) {
-                       if (ue_hi & 1)
-                               dev_err(&adapter->pdev->dev,
-                               "UE: %s bit set\n", ue_status_hi_desc[i]);
+               if (ue_lo || ue_hi) {
+                       error_detected = true;
+                       dev_err(dev,
+                               "Unrecoverable Error detected in the adapter");
+                       dev_err(dev, "Please reboot server to recover");
+                       if (skyhawk_chip(adapter))
+                               adapter->hw_error = true;
+                       for (i = 0; ue_lo; ue_lo >>= 1, i++) {
+                               if (ue_lo & 1)
+                                       dev_err(dev, "UE: %s bit set\n",
+                                               ue_status_low_desc[i]);
+                       }
+                       for (i = 0; ue_hi; ue_hi >>= 1, i++) {
+                               if (ue_hi & 1)
+                                       dev_err(dev, "UE: %s bit set\n",
+                                               ue_status_hi_desc[i]);
+                       }
                }
        }
-
+       if (error_detected)
+               netif_carrier_off(netdev);
 }
 
 static void be_msix_disable(struct be_adapter *adapter)
@@ -2505,7 +2580,7 @@ static void be_msix_disable(struct be_adapter *adapter)
 
 static int be_msix_enable(struct be_adapter *adapter)
 {
-       int i, status, num_vec;
+       int i, num_vec;
        struct device *dev = &adapter->pdev->dev;
 
        /* If RoCE is supported, program the max number of NIC vectors that
@@ -2521,24 +2596,11 @@ static int be_msix_enable(struct be_adapter *adapter)
        for (i = 0; i < num_vec; i++)
                adapter->msix_entries[i].entry = i;
 
-       status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
-       if (status == 0) {
-               goto done;
-       } else if (status >= MIN_MSIX_VECTORS) {
-               num_vec = status;
-               status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-                                        num_vec);
-               if (!status)
-                       goto done;
-       }
-
-       dev_warn(dev, "MSIx enable failed\n");
+       num_vec = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                       MIN_MSIX_VECTORS, num_vec);
+       if (num_vec < 0)
+               goto fail;
 
-       /* INTx is not supported in VFs, so fail probe if enable_msix fails */
-       if (!be_physfn(adapter))
-               return status;
-       return 0;
-done:
        if (be_roce_supported(adapter) && num_vec > MIN_MSIX_VECTORS) {
                adapter->num_msix_roce_vec = num_vec / 2;
                dev_info(dev, "enabled %d MSI-x vector(s) for RoCE\n",
@@ -2550,6 +2612,14 @@ done:
        dev_info(dev, "enabled %d MSI-x vector(s) for NIC\n",
                 adapter->num_msix_vec);
        return 0;
+
+fail:
+       dev_warn(dev, "MSIx enable failed\n");
+
+       /* INTx is not supported in VFs, so fail probe if enable_msix fails */
+       if (!be_physfn(adapter))
+               return num_vec;
+       return 0;
 }
 
 static inline int be_msix_vec_get(struct be_adapter *adapter,
@@ -2791,6 +2861,9 @@ static int be_open(struct net_device *netdev)
 
        netif_tx_start_all_queues(netdev);
        be_roce_dev_open(adapter);
+
+       if (skyhawk_chip(adapter))
+               vxlan_get_rx_port(netdev);
        return 0;
 err:
        be_close(adapter->netdev);
@@ -2946,6 +3019,19 @@ static void be_mac_clear(struct be_adapter *adapter)
        }
 }
 
+static void be_disable_vxlan_offloads(struct be_adapter *adapter)
+{
+       if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS)
+               be_cmd_manage_iface(adapter, adapter->if_handle,
+                                   OP_CONVERT_TUNNEL_TO_NORMAL);
+
+       if (adapter->vxlan_port)
+               be_cmd_set_vxlan_port(adapter, 0);
+
+       adapter->flags &= ~BE_FLAGS_VXLAN_OFFLOADS;
+       adapter->vxlan_port = 0;
+}
+
 static int be_clear(struct be_adapter *adapter)
 {
        be_cancel_worker(adapter);
@@ -2953,6 +3039,8 @@ static int be_clear(struct be_adapter *adapter)
        if (sriov_enabled(adapter))
                be_vf_clear(adapter);
 
+       be_disable_vxlan_offloads(adapter);
+
        /* delete the primary mac along with the uc-mac list */
        be_mac_clear(adapter);
 
@@ -3013,11 +3101,11 @@ static int be_vf_setup_init(struct be_adapter *adapter)
 
 static int be_vf_setup(struct be_adapter *adapter)
 {
+       struct device *dev = &adapter->pdev->dev;
        struct be_vf_cfg *vf_cfg;
-       u16 def_vlan, lnk_speed;
        int status, old_vfs, vf;
-       struct device *dev = &adapter->pdev->dev;
        u32 privileges;
+       u16 lnk_speed;
 
        old_vfs = pci_num_vf(adapter->pdev);
        if (old_vfs) {
@@ -3077,21 +3165,19 @@ static int be_vf_setup(struct be_adapter *adapter)
                 * Allow full available bandwidth
                 */
                if (BE3_chip(adapter) && !old_vfs)
-                       be_cmd_set_qos(adapter, 1000, vf+1);
+                       be_cmd_config_qos(adapter, 1000, vf + 1);
 
                status = be_cmd_link_status_query(adapter, &lnk_speed,
                                                  NULL, vf + 1);
                if (!status)
                        vf_cfg->tx_rate = lnk_speed;
 
-               status = be_cmd_get_hsw_config(adapter, &def_vlan,
-                                              vf + 1, vf_cfg->if_handle, NULL);
-               if (status)
-                       goto err;
-               vf_cfg->def_vid = def_vlan;
-
-               if (!old_vfs)
+               if (!old_vfs) {
                        be_cmd_enable_vf(adapter, vf + 1);
+                       be_cmd_set_logical_link_config(adapter,
+                                                      IFLA_VF_LINK_STATE_AUTO,
+                                                      vf+1);
+               }
        }
 
        if (!old_vfs) {
@@ -3109,19 +3195,38 @@ err:
        return status;
 }
 
+/* Converting function_mode bits on BE3 to SH mc_type enums */
+
+static u8 be_convert_mc_type(u32 function_mode)
+{
+       if (function_mode & VNIC_MODE && function_mode & FLEX10_MODE)
+               return vNIC1;
+       else if (function_mode & FLEX10_MODE)
+               return FLEX10;
+       else if (function_mode & VNIC_MODE)
+               return vNIC2;
+       else if (function_mode & UMC_ENABLED)
+               return UMC;
+       else
+               return MC_NONE;
+}
+
 /* On BE2/BE3 FW does not suggest the supported limits */
 static void BEx_get_resources(struct be_adapter *adapter,
                              struct be_resources *res)
 {
        struct pci_dev *pdev = adapter->pdev;
        bool use_sriov = false;
-       int max_vfs;
-
-       max_vfs = pci_sriov_get_totalvfs(pdev);
-
-       if (BE3_chip(adapter) && sriov_want(adapter)) {
-               res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
-               use_sriov = res->max_vfs;
+       int max_vfs = 0;
+
+       if (be_physfn(adapter) && BE3_chip(adapter)) {
+               be_cmd_get_profile_config(adapter, res, 0);
+               /* Some old versions of BE3 FW don't report max_vfs value */
+               if (res->max_vfs == 0) {
+                       max_vfs = pci_sriov_get_totalvfs(pdev);
+                       res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0;
+               }
+               use_sriov = res->max_vfs && sriov_want(adapter);
        }
 
        if (be_physfn(adapter))
@@ -3129,17 +3234,32 @@ static void BEx_get_resources(struct be_adapter *adapter,
        else
                res->max_uc_mac = BE_VF_UC_PMAC_COUNT;
 
-       if (adapter->function_mode & FLEX10_MODE)
-               res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
-       else if (adapter->function_mode & UMC_ENABLED)
-               res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED;
-       else
+       adapter->mc_type = be_convert_mc_type(adapter->function_mode);
+
+       if (be_is_mc(adapter)) {
+               /* Assuming that there are 4 channels per port,
+                * when multi-channel is enabled
+                */
+               if (be_is_qnq_mode(adapter))
+                       res->max_vlans = BE_NUM_VLANS_SUPPORTED/8;
+               else
+                       /* In a non-qnq multichannel mode, the pvid
+                        * takes up one vlan entry
+                        */
+                       res->max_vlans = (BE_NUM_VLANS_SUPPORTED / 4) - 1;
+       } else {
                res->max_vlans = BE_NUM_VLANS_SUPPORTED;
+       }
+
        res->max_mcast_mac = BE_MAX_MC;
 
-       /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */
-       if (BE2_chip(adapter) || use_sriov || be_is_mc(adapter) ||
-           !be_physfn(adapter) || (adapter->port_num > 1))
+       /* 1) For BE3 1Gb ports, FW does not support multiple TXQs
+        * 2) Create multiple TX rings on a BE3-R multi-channel interface
+        *    *only* if it is RSS-capable.
+        */
+       if (BE2_chip(adapter) || use_sriov ||  (adapter->port_num > 1) ||
+           !be_physfn(adapter) || (be_is_mc(adapter) &&
+           !(adapter->function_caps & BE_FUNCTION_CAPS_RSS)))
                res->max_tx_qs = 1;
        else
                res->max_tx_qs = BE3_MAX_TX_QS;
@@ -3151,7 +3271,7 @@ static void BEx_get_resources(struct be_adapter *adapter,
        res->max_rx_qs = res->max_rss_qs + 1;
 
        if (be_physfn(adapter))
-               res->max_evt_qs = (max_vfs > 0) ?
+               res->max_evt_qs = (res->max_vfs > 0) ?
                                        BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS;
        else
                res->max_evt_qs = 1;
@@ -3242,9 +3362,8 @@ static int be_get_config(struct be_adapter *adapter)
        if (status)
                return status;
 
-       /* primary mac needs 1 pmac entry */
-       adapter->pmac_id = kcalloc(be_max_uc(adapter) + 1, sizeof(u32),
-                                  GFP_KERNEL);
+       adapter->pmac_id = kcalloc(be_max_uc(adapter),
+                                  sizeof(*adapter->pmac_id), GFP_KERNEL);
        if (!adapter->pmac_id)
                return -ENOMEM;
 
@@ -3418,6 +3537,10 @@ static int be_setup(struct be_adapter *adapter)
                be_cmd_set_flow_control(adapter, adapter->tx_fc,
                                        adapter->rx_fc);
 
+       if (be_physfn(adapter))
+               be_cmd_set_logical_link_config(adapter,
+                                              IFLA_VF_LINK_STATE_AUTO, 0);
+
        if (sriov_want(adapter)) {
                if (be_max_vfs(adapter))
                        be_vf_setup(adapter);
@@ -4042,6 +4165,65 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                                       BRIDGE_MODE_VEPA : BRIDGE_MODE_VEB);
 }
 
+static void be_add_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
+                             __be16 port)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct device *dev = &adapter->pdev->dev;
+       int status;
+
+       if (lancer_chip(adapter) || BEx_chip(adapter))
+               return;
+
+       if (adapter->flags & BE_FLAGS_VXLAN_OFFLOADS) {
+               dev_warn(dev, "Cannot add UDP port %d for VxLAN offloads\n",
+                        be16_to_cpu(port));
+               dev_info(dev,
+                        "Only one UDP port supported for VxLAN offloads\n");
+               return;
+       }
+
+       status = be_cmd_manage_iface(adapter, adapter->if_handle,
+                                    OP_CONVERT_NORMAL_TO_TUNNEL);
+       if (status) {
+               dev_warn(dev, "Failed to convert normal interface to tunnel\n");
+               goto err;
+       }
+
+       status = be_cmd_set_vxlan_port(adapter, port);
+       if (status) {
+               dev_warn(dev, "Failed to add VxLAN port\n");
+               goto err;
+       }
+       adapter->flags |= BE_FLAGS_VXLAN_OFFLOADS;
+       adapter->vxlan_port = port;
+
+       dev_info(dev, "Enabled VxLAN offloads for UDP port %d\n",
+                be16_to_cpu(port));
+       return;
+err:
+       be_disable_vxlan_offloads(adapter);
+       return;
+}
+
+static void be_del_vxlan_port(struct net_device *netdev, sa_family_t sa_family,
+                             __be16 port)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       if (lancer_chip(adapter) || BEx_chip(adapter))
+               return;
+
+       if (adapter->vxlan_port != port)
+               return;
+
+       be_disable_vxlan_offloads(adapter);
+
+       dev_info(&adapter->pdev->dev,
+                "Disabled VxLAN offloads for UDP port %d\n",
+                be16_to_cpu(port));
+}
+
 static const struct net_device_ops be_netdev_ops = {
        .ndo_open               = be_open,
        .ndo_stop               = be_close,
@@ -4057,20 +4239,29 @@ static const struct net_device_ops be_netdev_ops = {
        .ndo_set_vf_vlan        = be_set_vf_vlan,
        .ndo_set_vf_tx_rate     = be_set_vf_tx_rate,
        .ndo_get_vf_config      = be_get_vf_config,
+       .ndo_set_vf_link_state  = be_set_vf_link_state,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = be_netpoll,
 #endif
        .ndo_bridge_setlink     = be_ndo_bridge_setlink,
        .ndo_bridge_getlink     = be_ndo_bridge_getlink,
 #ifdef CONFIG_NET_RX_BUSY_POLL
-       .ndo_busy_poll          = be_busy_poll
+       .ndo_busy_poll          = be_busy_poll,
 #endif
+       .ndo_add_vxlan_port     = be_add_vxlan_port,
+       .ndo_del_vxlan_port     = be_del_vxlan_port,
 };
 
 static void be_netdev_init(struct net_device *netdev)
 {
        struct be_adapter *adapter = netdev_priv(netdev);
 
+       if (skyhawk_chip(adapter)) {
+               netdev->hw_enc_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                                          NETIF_F_TSO | NETIF_F_TSO6 |
+                                          NETIF_F_GSO_UDP_TUNNEL;
+               netdev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+       }
        netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
                NETIF_F_HW_VLAN_CTAG_TX;
@@ -4417,14 +4608,32 @@ static bool be_reset_required(struct be_adapter *adapter)
 
 static char *mc_name(struct be_adapter *adapter)
 {
-       if (adapter->function_mode & FLEX10_MODE)
-               return "FLEX10";
-       else if (adapter->function_mode & VNIC_MODE)
-               return "vNIC";
-       else if (adapter->function_mode & UMC_ENABLED)
-               return "UMC";
-       else
-               return "";
+       char *str = ""; /* default */
+
+       switch (adapter->mc_type) {
+       case UMC:
+               str = "UMC";
+               break;
+       case FLEX10:
+               str = "FLEX10";
+               break;
+       case vNIC1:
+               str = "vNIC-1";
+               break;
+       case nPAR:
+               str = "nPAR";
+               break;
+       case UFP:
+               str = "UFP";
+               break;
+       case vNIC2:
+               str = "vNIC-2";
+               break;
+       default:
+               str = "";
+       }
+
+       return str;
 }
 
 static inline char *func_name(struct be_adapter *adapter)
index 9cd5415fe017dc359d2aae2e679eddc40e75f5e0..a5dae4a62bb37923c5d1df5f2aa5fdfa343b64e0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
index 2cd1129e19af960185a3f706d9ab5ed165e409a7..a3ef8f804b9e68f79a40691509725c817a1eb927 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005 - 2013 Emulex
+ * Copyright (C) 2005 - 2014 Emulex
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
index 4de8cfd149cfbd0fb6ed0c2782852c1eee599fa9..8b70ca7e342b6f16a8d6624293ee1b940bcff3d5 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/etherdevice.h>
+#include <linux/clk.h>
 #include <linux/crc32.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -51,6 +52,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
 #define        ETH_HASH0       0x48
 #define        ETH_HASH1       0x4c
 #define        ETH_TXCTRL      0x50
+#define        ETH_END         0x54
 
 /* mode register */
 #define        MODER_RXEN      (1 <<  0) /* receive enable */
@@ -179,6 +181,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
  * @membase:   pointer to buffer memory region
  * @dma_alloc: dma allocated buffer size
  * @io_region_size:    I/O memory region size
+ * @num_bd:    number of buffer descriptors
  * @num_tx:    number of send buffers
  * @cur_tx:    last send buffer written
  * @dty_tx:    last buffer actually sent
@@ -199,6 +202,7 @@ struct ethoc {
        int dma_alloc;
        resource_size_t io_region_size;
 
+       unsigned int num_bd;
        unsigned int num_tx;
        unsigned int cur_tx;
        unsigned int dty_tx;
@@ -216,6 +220,7 @@ struct ethoc {
 
        struct phy_device *phy;
        struct mii_bus *mdio;
+       struct clk *clk;
        s8 phy_id;
 };
 
@@ -655,11 +660,6 @@ static int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
        return -EBUSY;
 }
 
-static int ethoc_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static void ethoc_mdio_poll(struct net_device *dev)
 {
 }
@@ -688,6 +688,11 @@ static int ethoc_mdio_probe(struct net_device *dev)
        }
 
        priv->phy = phy;
+       phy->advertising &= ~(ADVERTISED_1000baseT_Full |
+                             ADVERTISED_1000baseT_Half);
+       phy->supported &= ~(SUPPORTED_1000baseT_Full |
+                           SUPPORTED_1000baseT_Half);
+
        return 0;
 }
 
@@ -890,6 +895,102 @@ out:
        return NETDEV_TX_OK;
 }
 
+static int ethoc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct ethoc *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phy;
+
+       if (!phydev)
+               return -EOPNOTSUPP;
+
+       return phy_ethtool_gset(phydev, cmd);
+}
+
+static int ethoc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct ethoc *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phy;
+
+       if (!phydev)
+               return -EOPNOTSUPP;
+
+       return phy_ethtool_sset(phydev, cmd);
+}
+
+static int ethoc_get_regs_len(struct net_device *netdev)
+{
+       return ETH_END;
+}
+
+static void ethoc_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                          void *p)
+{
+       struct ethoc *priv = netdev_priv(dev);
+       u32 *regs_buff = p;
+       unsigned i;
+
+       regs->version = 0;
+       for (i = 0; i < ETH_END / sizeof(u32); ++i)
+               regs_buff[i] = ethoc_read(priv, i * sizeof(u32));
+}
+
+static void ethoc_get_ringparam(struct net_device *dev,
+                               struct ethtool_ringparam *ring)
+{
+       struct ethoc *priv = netdev_priv(dev);
+
+       ring->rx_max_pending = priv->num_bd - 1;
+       ring->rx_mini_max_pending = 0;
+       ring->rx_jumbo_max_pending = 0;
+       ring->tx_max_pending = priv->num_bd - 1;
+
+       ring->rx_pending = priv->num_rx;
+       ring->rx_mini_pending = 0;
+       ring->rx_jumbo_pending = 0;
+       ring->tx_pending = priv->num_tx;
+}
+
+static int ethoc_set_ringparam(struct net_device *dev,
+                              struct ethtool_ringparam *ring)
+{
+       struct ethoc *priv = netdev_priv(dev);
+
+       if (ring->tx_pending < 1 || ring->rx_pending < 1 ||
+           ring->tx_pending + ring->rx_pending > priv->num_bd)
+               return -EINVAL;
+       if (ring->rx_mini_pending || ring->rx_jumbo_pending)
+               return -EINVAL;
+
+       if (netif_running(dev)) {
+               netif_tx_disable(dev);
+               ethoc_disable_rx_and_tx(priv);
+               ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX);
+               synchronize_irq(dev->irq);
+       }
+
+       priv->num_tx = rounddown_pow_of_two(ring->tx_pending);
+       priv->num_rx = ring->rx_pending;
+       ethoc_init_ring(priv, dev->mem_start);
+
+       if (netif_running(dev)) {
+               ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX);
+               ethoc_enable_rx_and_tx(priv);
+               netif_wake_queue(dev);
+       }
+       return 0;
+}
+
+const struct ethtool_ops ethoc_ethtool_ops = {
+       .get_settings = ethoc_get_settings,
+       .set_settings = ethoc_set_settings,
+       .get_regs_len = ethoc_get_regs_len,
+       .get_regs = ethoc_get_regs,
+       .get_link = ethtool_op_get_link,
+       .get_ringparam = ethoc_get_ringparam,
+       .set_ringparam = ethoc_set_ringparam,
+       .get_ts_info = ethtool_op_get_ts_info,
+};
+
 static const struct net_device_ops ethoc_netdev_ops = {
        .ndo_open = ethoc_open,
        .ndo_stop = ethoc_stop,
@@ -917,6 +1018,8 @@ static int ethoc_probe(struct platform_device *pdev)
        int num_bd;
        int ret = 0;
        bool random_mac = false;
+       struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0;
 
        /* allocate networking device */
        netdev = alloc_etherdev(sizeof(struct ethoc));
@@ -1016,6 +1119,7 @@ static int ethoc_probe(struct platform_device *pdev)
                ret = -ENODEV;
                goto error;
        }
+       priv->num_bd = num_bd;
        /* num_tx must be a power of two */
        priv->num_tx = rounddown_pow_of_two(num_bd >> 1);
        priv->num_rx = num_bd - priv->num_tx;
@@ -1030,8 +1134,7 @@ static int ethoc_probe(struct platform_device *pdev)
        }
 
        /* Allow the platform setup code to pass in a MAC address. */
-       if (dev_get_platdata(&pdev->dev)) {
-               struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       if (pdata) {
                memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
                priv->phy_id = pdata->phy_id;
        } else {
@@ -1069,6 +1172,27 @@ static int ethoc_probe(struct platform_device *pdev)
        if (random_mac)
                netdev->addr_assign_type = NET_ADDR_RANDOM;
 
+       /* Allow the platform setup code to adjust MII management bus clock. */
+       if (!eth_clkfreq) {
+               struct clk *clk = devm_clk_get(&pdev->dev, NULL);
+
+               if (!IS_ERR(clk)) {
+                       priv->clk = clk;
+                       clk_prepare_enable(clk);
+                       eth_clkfreq = clk_get_rate(clk);
+               }
+       }
+       if (eth_clkfreq) {
+               u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1);
+
+               if (!clkdiv)
+                       clkdiv = 2;
+               dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv);
+               ethoc_write(priv, MIIMODER,
+                           (ethoc_read(priv, MIIMODER) & MIIMODER_NOPRE) |
+                           clkdiv);
+       }
+
        /* register MII bus */
        priv->mdio = mdiobus_alloc();
        if (!priv->mdio) {
@@ -1081,7 +1205,6 @@ static int ethoc_probe(struct platform_device *pdev)
                        priv->mdio->name, pdev->id);
        priv->mdio->read = ethoc_mdio_read;
        priv->mdio->write = ethoc_mdio_write;
-       priv->mdio->reset = ethoc_mdio_reset;
        priv->mdio->priv = priv;
 
        priv->mdio->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
@@ -1111,6 +1234,7 @@ static int ethoc_probe(struct platform_device *pdev)
        netdev->netdev_ops = &ethoc_netdev_ops;
        netdev->watchdog_timeo = ETHOC_TIMEOUT;
        netdev->features |= 0;
+       netdev->ethtool_ops = &ethoc_ethtool_ops;
 
        /* setup NAPI */
        netif_napi_add(netdev, &priv->napi, ethoc_poll, 64);
@@ -1133,6 +1257,8 @@ free_mdio:
        kfree(priv->mdio->irq);
        mdiobus_free(priv->mdio);
 free:
+       if (priv->clk)
+               clk_disable_unprepare(priv->clk);
        free_netdev(netdev);
 out:
        return ret;
@@ -1157,6 +1283,8 @@ static int ethoc_remove(struct platform_device *pdev)
                        kfree(priv->mdio->irq);
                        mdiobus_free(priv->mdio);
                }
+               if (priv->clk)
+                       clk_disable_unprepare(priv->clk);
                unregister_netdev(netdev);
                free_netdev(netdev);
        }
index c11ecbc98149ccd7b3e7a884979d362c8da724cf..68069eabc4f855c0636d12b69854e44919ffb863 100644 (file)
@@ -940,11 +940,6 @@ static int ftgmac100_mdiobus_write(struct mii_bus *bus, int phy_addr,
        return -EIO;
 }
 
-static int ftgmac100_mdiobus_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 /******************************************************************************
  * struct ethtool_ops functions
  *****************************************************************************/
@@ -1262,7 +1257,6 @@ static int ftgmac100_probe(struct platform_device *pdev)
        priv->mii_bus->priv = netdev;
        priv->mii_bus->read = ftgmac100_mdiobus_read;
        priv->mii_bus->write = ftgmac100_mdiobus_write;
-       priv->mii_bus->reset = ftgmac100_mdiobus_reset;
        priv->mii_bus->irq = priv->phy_irq;
 
        for (i = 0; i < PHY_MAX_ADDR; i++)
index 549ce13b92acee78b6559e360c427c8720b7493b..71debd1c18c9923a895f313c71f3b4617974433f 100644 (file)
@@ -14,7 +14,6 @@ obj-$(CONFIG_FSL_XGMAC_MDIO) += xgmac_mdio.o
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
 obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
 gianfar_driver-objs := gianfar.o \
-               gianfar_ethtool.o \
-               gianfar_sysfs.o
+               gianfar_ethtool.o
 obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
 ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o
index d4782b42401b0159b6375891db99bfc9999b0ecd..e19315eaf2dd65a13bad1f064f856d0e04378dcb 100644 (file)
@@ -338,7 +338,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        /* Protocol checksum off-load for TCP and UDP. */
        if (fec_enet_clear_csum(skb, ndev)) {
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -389,12 +389,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                        netdev_err(ndev, "Tx DMA memory map failed\n");
                return NETDEV_TX_OK;
        }
-       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
-        * it's the last BD of the frame, and to put the CRC on the end.
-        */
-       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
-                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
-       bdp->cbd_sc = status;
 
        if (fep->bufdesc_ex) {
 
@@ -416,6 +410,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                }
        }
 
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        * it's the last BD of the frame, and to put the CRC on the end.
+        */
+       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+       bdp->cbd_sc = status;
+
        bdp_pre = fec_enet_get_prevdesc(bdp, fep);
        if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
            !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
@@ -527,13 +528,6 @@ fec_restart(struct net_device *ndev, int duplex)
        /* Clear any outstanding interrupt. */
        writel(0xffc00000, fep->hwp + FEC_IEVENT);
 
-       /* Setup multicast filter. */
-       set_multicast_list(ndev);
-#ifndef CONFIG_M5272
-       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
-       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
-#endif
-
        /* Set maximum receive buffer size. */
        writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
 
@@ -654,6 +648,13 @@ fec_restart(struct net_device *ndev, int duplex)
 
        writel(rcntl, fep->hwp + FEC_R_CNTRL);
 
+       /* Setup multicast filter. */
+       set_multicast_list(ndev);
+#ifndef CONFIG_M5272
+       writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
+       writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
+#endif
+
        if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) {
                /* enable ENET endian swap */
                ecntl |= (1 << 8);
@@ -1254,11 +1255,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        return 0;
 }
 
-static int fec_enet_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static int fec_enet_mii_probe(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
@@ -1383,7 +1379,6 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        fep->mii_bus->name = "fec_enet_mii_bus";
        fep->mii_bus->read = fec_enet_mdio_read;
        fep->mii_bus->write = fec_enet_mdio_write;
-       fep->mii_bus->reset = fec_enet_mdio_reset;
        snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                pdev->name, fep->dev_id + 1);
        fep->mii_bus->priv = fep;
@@ -1778,8 +1773,6 @@ fec_enet_open(struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        int ret;
 
-       napi_enable(&fep->napi);
-
        /* I should reset the ring buffers here, but I don't yet know
         * a simple way to do that.
         */
@@ -1794,6 +1787,8 @@ fec_enet_open(struct net_device *ndev)
                fec_enet_free_buffers(ndev);
                return ret;
        }
+
+       napi_enable(&fep->napi);
        phy_start(fep->phy_dev);
        netif_start_queue(ndev);
        fep->opened = 1;
index 89ccb5b087080005f1629605804957a7487d71a8..82386b29914a8640bd2e17f956bdd0946fc5c3ce 100644 (file)
@@ -372,6 +372,7 @@ void fec_ptp_init(struct platform_device *pdev)
        fep->ptp_caps.n_alarm = 0;
        fep->ptp_caps.n_ext_ts = 0;
        fep->ptp_caps.n_per_out = 0;
+       fep->ptp_caps.n_pins = 0;
        fep->ptp_caps.pps = 0;
        fep->ptp_caps.adjfreq = fec_ptp_adjfreq;
        fep->ptp_caps.adjtime = fec_ptp_adjtime;
index 62f042d4aaa93cc85e79b079272ac26150b263a3..dc80db41d6b3397388b0210283c4c7fd3ce07680 100644 (file)
@@ -91,6 +91,9 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
        u16 pkt_len, sc;
        int curidx;
 
+       if (budget <= 0)
+               return received;
+
        /*
         * First, grab all of the stats for the incoming packet.
         * These get messed up if we get called due to a busy condition.
index 7e69c983d12a81d35f2a9863e7e914892266f0ca..ebf5d6429a8df569ad1d024fb270caac8f7aced8 100644 (file)
@@ -95,12 +95,6 @@ static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location,
 
 }
 
-static int fs_enet_fec_mii_reset(struct mii_bus *bus)
-{
-       /* nothing here - for now */
-       return 0;
-}
-
 static struct of_device_id fs_enet_mdio_fec_match[];
 static int fs_enet_mdio_probe(struct platform_device *ofdev)
 {
@@ -128,7 +122,6 @@ static int fs_enet_mdio_probe(struct platform_device *ofdev)
        new_bus->name = "FEC MII Bus";
        new_bus->read = &fs_enet_fec_mii_read;
        new_bus->write = &fs_enet_fec_mii_write;
-       new_bus->reset = &fs_enet_fec_mii_reset;
 
        ret = of_address_to_resource(ofdev->dev.of_node, 0, &res);
        if (ret)
index ad5a5aadc7e15901a3722ac673f36a25a3a99884..9125d9abf0998d31e3179bd9c712af487855d5a9 100644 (file)
@@ -9,7 +9,7 @@
  * Maintainer: Kumar Gala
  * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc.
  * Copyright 2007 MontaVista Software, Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -121,7 +121,6 @@ static irqreturn_t gfar_error(int irq, void *dev_id);
 static irqreturn_t gfar_transmit(int irq, void *dev_id);
 static irqreturn_t gfar_interrupt(int irq, void *dev_id);
 static void adjust_link(struct net_device *dev);
-static void init_registers(struct net_device *dev);
 static int init_phy(struct net_device *dev);
 static int gfar_probe(struct platform_device *ofdev);
 static int gfar_remove(struct platform_device *ofdev);
@@ -129,8 +128,10 @@ static void free_skb_resources(struct gfar_private *priv);
 static void gfar_set_multi(struct net_device *dev);
 static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
 static void gfar_configure_serdes(struct net_device *dev);
-static int gfar_poll(struct napi_struct *napi, int budget);
-static int gfar_poll_sq(struct napi_struct *napi, int budget);
+static int gfar_poll_rx(struct napi_struct *napi, int budget);
+static int gfar_poll_tx(struct napi_struct *napi, int budget);
+static int gfar_poll_rx_sq(struct napi_struct *napi, int budget);
+static int gfar_poll_tx_sq(struct napi_struct *napi, int budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void gfar_netpoll(struct net_device *dev);
 #endif
@@ -138,9 +139,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit);
 static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue);
 static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
                               int amount_pull, struct napi_struct *napi);
-void gfar_halt(struct net_device *dev);
-static void gfar_halt_nodisable(struct net_device *dev);
-void gfar_start(struct net_device *dev);
+static void gfar_halt_nodisable(struct gfar_private *priv);
 static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num,
                                  const u8 *addr);
@@ -332,72 +331,76 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv)
        }
 }
 
-static void gfar_init_mac(struct net_device *ndev)
+static void gfar_rx_buff_size_config(struct gfar_private *priv)
 {
-       struct gfar_private *priv = netdev_priv(ndev);
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       u32 rctrl = 0;
-       u32 tctrl = 0;
-       u32 attrs = 0;
-
-       /* write the tx/rx base registers */
-       gfar_init_tx_rx_base(priv);
-
-       /* Configure the coalescing support */
-       gfar_configure_coalescing_all(priv);
+       int frame_size = priv->ndev->mtu + ETH_HLEN;
 
        /* set this when rx hw offload (TOE) functions are being used */
        priv->uses_rxfcb = 0;
 
+       if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX))
+               priv->uses_rxfcb = 1;
+
+       if (priv->hwts_rx_en)
+               priv->uses_rxfcb = 1;
+
+       if (priv->uses_rxfcb)
+               frame_size += GMAC_FCB_LEN;
+
+       frame_size += priv->padding;
+
+       frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
+                    INCREMENTAL_BUFFER_SIZE;
+
+       priv->rx_buffer_size = frame_size;
+}
+
+static void gfar_mac_rx_config(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 rctrl = 0;
+
        if (priv->rx_filer_enable) {
                rctrl |= RCTRL_FILREN;
                /* Program the RIR0 reg with the required distribution */
-               gfar_write(&regs->rir0, DEFAULT_RIR0);
+               if (priv->poll_mode == GFAR_SQ_POLLING)
+                       gfar_write(&regs->rir0, DEFAULT_2RXQ_RIR0);
+               else /* GFAR_MQ_POLLING */
+                       gfar_write(&regs->rir0, DEFAULT_8RXQ_RIR0);
        }
 
        /* Restore PROMISC mode */
-       if (ndev->flags & IFF_PROMISC)
+       if (priv->ndev->flags & IFF_PROMISC)
                rctrl |= RCTRL_PROM;
 
-       if (ndev->features & NETIF_F_RXCSUM) {
+       if (priv->ndev->features & NETIF_F_RXCSUM)
                rctrl |= RCTRL_CHECKSUMMING;
-               priv->uses_rxfcb = 1;
-       }
-
-       if (priv->extended_hash) {
-               rctrl |= RCTRL_EXTHASH;
 
-               gfar_clear_exact_match(ndev);
-               rctrl |= RCTRL_EMEN;
-       }
+       if (priv->extended_hash)
+               rctrl |= RCTRL_EXTHASH | RCTRL_EMEN;
 
        if (priv->padding) {
                rctrl &= ~RCTRL_PAL_MASK;
                rctrl |= RCTRL_PADDING(priv->padding);
        }
 
-       /* Insert receive time stamps into padding alignment bytes */
-       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) {
-               rctrl &= ~RCTRL_PAL_MASK;
-               rctrl |= RCTRL_PADDING(8);
-               priv->padding = 8;
-       }
-
        /* Enable HW time stamping if requested from user space */
-       if (priv->hwts_rx_en) {
+       if (priv->hwts_rx_en)
                rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE;
-               priv->uses_rxfcb = 1;
-       }
 
-       if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) {
+       if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
                rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
-               priv->uses_rxfcb = 1;
-       }
 
        /* Init rctrl based on our settings */
        gfar_write(&regs->rctrl, rctrl);
+}
+
+static void gfar_mac_tx_config(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 tctrl = 0;
 
-       if (ndev->features & NETIF_F_IP_CSUM)
+       if (priv->ndev->features & NETIF_F_IP_CSUM)
                tctrl |= TCTRL_INIT_CSUM;
 
        if (priv->prio_sched_en)
@@ -408,30 +411,51 @@ static void gfar_init_mac(struct net_device *ndev)
                gfar_write(&regs->tr47wt, DEFAULT_WRRS_WEIGHT);
        }
 
-       gfar_write(&regs->tctrl, tctrl);
+       if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_TX)
+               tctrl |= TCTRL_VLINS;
 
-       /* Set the extraction length and index */
-       attrs = ATTRELI_EL(priv->rx_stash_size) |
-               ATTRELI_EI(priv->rx_stash_index);
+       gfar_write(&regs->tctrl, tctrl);
+}
 
-       gfar_write(&regs->attreli, attrs);
+static void gfar_configure_coalescing(struct gfar_private *priv,
+                              unsigned long tx_mask, unsigned long rx_mask)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 __iomem *baddr;
 
-       /* Start with defaults, and add stashing or locking
-        * depending on the approprate variables
-        */
-       attrs = ATTR_INIT_SETTINGS;
+       if (priv->mode == MQ_MG_MODE) {
+               int i = 0;
 
-       if (priv->bd_stash_en)
-               attrs |= ATTR_BDSTASH;
+               baddr = &regs->txic0;
+               for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
+                       gfar_write(baddr + i, 0);
+                       if (likely(priv->tx_queue[i]->txcoalescing))
+                               gfar_write(baddr + i, priv->tx_queue[i]->txic);
+               }
 
-       if (priv->rx_stash_size != 0)
-               attrs |= ATTR_BUFSTASH;
+               baddr = &regs->rxic0;
+               for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
+                       gfar_write(baddr + i, 0);
+                       if (likely(priv->rx_queue[i]->rxcoalescing))
+                               gfar_write(baddr + i, priv->rx_queue[i]->rxic);
+               }
+       } else {
+               /* Backward compatible case -- even if we enable
+                * multiple queues, there's only single reg to program
+                */
+               gfar_write(&regs->txic, 0);
+               if (likely(priv->tx_queue[0]->txcoalescing))
+                       gfar_write(&regs->txic, priv->tx_queue[0]->txic);
 
-       gfar_write(&regs->attr, attrs);
+               gfar_write(&regs->rxic, 0);
+               if (unlikely(priv->rx_queue[0]->rxcoalescing))
+                       gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
+       }
+}
 
-       gfar_write(&regs->fifo_tx_thr, priv->fifo_threshold);
-       gfar_write(&regs->fifo_tx_starve, priv->fifo_starve);
-       gfar_write(&regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
+void gfar_configure_coalescing_all(struct gfar_private *priv)
+{
+       gfar_configure_coalescing(priv, 0xFF, 0xFF);
 }
 
 static struct net_device_stats *gfar_get_stats(struct net_device *dev)
@@ -479,12 +503,27 @@ static const struct net_device_ops gfar_netdev_ops = {
 #endif
 };
 
-void lock_rx_qs(struct gfar_private *priv)
+static void gfar_ints_disable(struct gfar_private *priv)
 {
        int i;
+       for (i = 0; i < priv->num_grps; i++) {
+               struct gfar __iomem *regs = priv->gfargrp[i].regs;
+               /* Clear IEVENT */
+               gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
 
-       for (i = 0; i < priv->num_rx_queues; i++)
-               spin_lock(&priv->rx_queue[i]->rxlock);
+               /* Initialize IMASK */
+               gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+       }
+}
+
+static void gfar_ints_enable(struct gfar_private *priv)
+{
+       int i;
+       for (i = 0; i < priv->num_grps; i++) {
+               struct gfar __iomem *regs = priv->gfargrp[i].regs;
+               /* Unmask the interrupts we look for */
+               gfar_write(&regs->imask, IMASK_DEFAULT);
+       }
 }
 
 void lock_tx_qs(struct gfar_private *priv)
@@ -495,23 +534,50 @@ void lock_tx_qs(struct gfar_private *priv)
                spin_lock(&priv->tx_queue[i]->txlock);
 }
 
-void unlock_rx_qs(struct gfar_private *priv)
+void unlock_tx_qs(struct gfar_private *priv)
 {
        int i;
 
-       for (i = 0; i < priv->num_rx_queues; i++)
-               spin_unlock(&priv->rx_queue[i]->rxlock);
+       for (i = 0; i < priv->num_tx_queues; i++)
+               spin_unlock(&priv->tx_queue[i]->txlock);
 }
 
-void unlock_tx_qs(struct gfar_private *priv)
+static int gfar_alloc_tx_queues(struct gfar_private *priv)
 {
        int i;
 
-       for (i = 0; i < priv->num_tx_queues; i++)
-               spin_unlock(&priv->tx_queue[i]->txlock);
+       for (i = 0; i < priv->num_tx_queues; i++) {
+               priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
+                                           GFP_KERNEL);
+               if (!priv->tx_queue[i])
+                       return -ENOMEM;
+
+               priv->tx_queue[i]->tx_skbuff = NULL;
+               priv->tx_queue[i]->qindex = i;
+               priv->tx_queue[i]->dev = priv->ndev;
+               spin_lock_init(&(priv->tx_queue[i]->txlock));
+       }
+       return 0;
 }
 
-static void free_tx_pointers(struct gfar_private *priv)
+static int gfar_alloc_rx_queues(struct gfar_private *priv)
+{
+       int i;
+
+       for (i = 0; i < priv->num_rx_queues; i++) {
+               priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
+                                           GFP_KERNEL);
+               if (!priv->rx_queue[i])
+                       return -ENOMEM;
+
+               priv->rx_queue[i]->rx_skbuff = NULL;
+               priv->rx_queue[i]->qindex = i;
+               priv->rx_queue[i]->dev = priv->ndev;
+       }
+       return 0;
+}
+
+static void gfar_free_tx_queues(struct gfar_private *priv)
 {
        int i;
 
@@ -519,7 +585,7 @@ static void free_tx_pointers(struct gfar_private *priv)
                kfree(priv->tx_queue[i]);
 }
 
-static void free_rx_pointers(struct gfar_private *priv)
+static void gfar_free_rx_queues(struct gfar_private *priv)
 {
        int i;
 
@@ -553,23 +619,26 @@ static void disable_napi(struct gfar_private *priv)
 {
        int i;
 
-       for (i = 0; i < priv->num_grps; i++)
-               napi_disable(&priv->gfargrp[i].napi);
+       for (i = 0; i < priv->num_grps; i++) {
+               napi_disable(&priv->gfargrp[i].napi_rx);
+               napi_disable(&priv->gfargrp[i].napi_tx);
+       }
 }
 
 static void enable_napi(struct gfar_private *priv)
 {
        int i;
 
-       for (i = 0; i < priv->num_grps; i++)
-               napi_enable(&priv->gfargrp[i].napi);
+       for (i = 0; i < priv->num_grps; i++) {
+               napi_enable(&priv->gfargrp[i].napi_rx);
+               napi_enable(&priv->gfargrp[i].napi_tx);
+       }
 }
 
 static int gfar_parse_group(struct device_node *np,
                            struct gfar_private *priv, const char *model)
 {
        struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps];
-       u32 *queue_mask;
        int i;
 
        for (i = 0; i < GFAR_NUM_IRQS; i++) {
@@ -598,16 +667,52 @@ static int gfar_parse_group(struct device_node *np,
        grp->priv = priv;
        spin_lock_init(&grp->grplock);
        if (priv->mode == MQ_MG_MODE) {
-               queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
-               grp->rx_bit_map = queue_mask ?
-                       *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
-               queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
-               grp->tx_bit_map = queue_mask ?
-                       *queue_mask : (DEFAULT_MAPPING >> priv->num_grps);
+               u32 *rxq_mask, *txq_mask;
+               rxq_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL);
+               txq_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL);
+
+               if (priv->poll_mode == GFAR_SQ_POLLING) {
+                       /* One Q per interrupt group: Q0 to G0, Q1 to G1 */
+                       grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
+                       grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps);
+               } else { /* GFAR_MQ_POLLING */
+                       grp->rx_bit_map = rxq_mask ?
+                       *rxq_mask : (DEFAULT_MAPPING >> priv->num_grps);
+                       grp->tx_bit_map = txq_mask ?
+                       *txq_mask : (DEFAULT_MAPPING >> priv->num_grps);
+               }
        } else {
                grp->rx_bit_map = 0xFF;
                grp->tx_bit_map = 0xFF;
        }
+
+       /* bit_map's MSB is q0 (from q0 to q7) but, for_each_set_bit parses
+        * right to left, so we need to revert the 8 bits to get the q index
+        */
+       grp->rx_bit_map = bitrev8(grp->rx_bit_map);
+       grp->tx_bit_map = bitrev8(grp->tx_bit_map);
+
+       /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
+        * also assign queues to groups
+        */
+       for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) {
+               if (!grp->rx_queue)
+                       grp->rx_queue = priv->rx_queue[i];
+               grp->num_rx_queues++;
+               grp->rstat |= (RSTAT_CLEAR_RHALT >> i);
+               priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
+               priv->rx_queue[i]->grp = grp;
+       }
+
+       for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) {
+               if (!grp->tx_queue)
+                       grp->tx_queue = priv->tx_queue[i];
+               grp->num_tx_queues++;
+               grp->tstat |= (TSTAT_CLEAR_THALT >> i);
+               priv->tqueue |= (TQUEUE_EN0 >> i);
+               priv->tx_queue[i]->grp = grp;
+       }
+
        priv->num_grps++;
 
        return 0;
@@ -628,13 +733,45 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        const u32 *stash_idx;
        unsigned int num_tx_qs, num_rx_qs;
        u32 *tx_queues, *rx_queues;
+       unsigned short mode, poll_mode;
 
        if (!np || !of_device_is_available(np))
                return -ENODEV;
 
-       /* parse the num of tx and rx queues */
+       if (of_device_is_compatible(np, "fsl,etsec2")) {
+               mode = MQ_MG_MODE;
+               poll_mode = GFAR_SQ_POLLING;
+       } else {
+               mode = SQ_SG_MODE;
+               poll_mode = GFAR_SQ_POLLING;
+       }
+
+       /* parse the num of HW tx and rx queues */
        tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL);
-       num_tx_qs = tx_queues ? *tx_queues : 1;
+       rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
+
+       if (mode == SQ_SG_MODE) {
+               num_tx_qs = 1;
+               num_rx_qs = 1;
+       } else { /* MQ_MG_MODE */
+               /* get the actual number of supported groups */
+               unsigned int num_grps = of_get_available_child_count(np);
+
+               if (num_grps == 0 || num_grps > MAXGROUPS) {
+                       dev_err(&ofdev->dev, "Invalid # of int groups(%d)\n",
+                               num_grps);
+                       pr_err("Cannot do alloc_etherdev, aborting\n");
+                       return -EINVAL;
+               }
+
+               if (poll_mode == GFAR_SQ_POLLING) {
+                       num_tx_qs = num_grps; /* one txq per int group */
+                       num_rx_qs = num_grps; /* one rxq per int group */
+               } else { /* GFAR_MQ_POLLING */
+                       num_tx_qs = tx_queues ? *tx_queues : 1;
+                       num_rx_qs = rx_queues ? *rx_queues : 1;
+               }
+       }
 
        if (num_tx_qs > MAX_TX_QS) {
                pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n",
@@ -643,9 +780,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                return -EINVAL;
        }
 
-       rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL);
-       num_rx_qs = rx_queues ? *rx_queues : 1;
-
        if (num_rx_qs > MAX_RX_QS) {
                pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n",
                       num_rx_qs, MAX_RX_QS);
@@ -661,10 +795,20 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
        priv = netdev_priv(dev);
        priv->ndev = dev;
 
+       priv->mode = mode;
+       priv->poll_mode = poll_mode;
+
        priv->num_tx_queues = num_tx_qs;
        netif_set_real_num_rx_queues(dev, num_rx_qs);
        priv->num_rx_queues = num_rx_qs;
-       priv->num_grps = 0x0;
+
+       err = gfar_alloc_tx_queues(priv);
+       if (err)
+               goto tx_alloc_failed;
+
+       err = gfar_alloc_rx_queues(priv);
+       if (err)
+               goto rx_alloc_failed;
 
        /* Init Rx queue filer rule set linked list */
        INIT_LIST_HEAD(&priv->rx_list.list);
@@ -677,52 +821,18 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                priv->gfargrp[i].regs = NULL;
 
        /* Parse and initialize group specific information */
-       if (of_device_is_compatible(np, "fsl,etsec2")) {
-               priv->mode = MQ_MG_MODE;
+       if (priv->mode == MQ_MG_MODE) {
                for_each_child_of_node(np, child) {
                        err = gfar_parse_group(child, priv, model);
                        if (err)
                                goto err_grp_init;
                }
-       } else {
-               priv->mode = SQ_SG_MODE;
+       } else { /* SQ_SG_MODE */
                err = gfar_parse_group(np, priv, model);
                if (err)
                        goto err_grp_init;
        }
 
-       for (i = 0; i < priv->num_tx_queues; i++)
-               priv->tx_queue[i] = NULL;
-       for (i = 0; i < priv->num_rx_queues; i++)
-               priv->rx_queue[i] = NULL;
-
-       for (i = 0; i < priv->num_tx_queues; i++) {
-               priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
-                                           GFP_KERNEL);
-               if (!priv->tx_queue[i]) {
-                       err = -ENOMEM;
-                       goto tx_alloc_failed;
-               }
-               priv->tx_queue[i]->tx_skbuff = NULL;
-               priv->tx_queue[i]->qindex = i;
-               priv->tx_queue[i]->dev = dev;
-               spin_lock_init(&(priv->tx_queue[i]->txlock));
-       }
-
-       for (i = 0; i < priv->num_rx_queues; i++) {
-               priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
-                                           GFP_KERNEL);
-               if (!priv->rx_queue[i]) {
-                       err = -ENOMEM;
-                       goto rx_alloc_failed;
-               }
-               priv->rx_queue[i]->rx_skbuff = NULL;
-               priv->rx_queue[i]->qindex = i;
-               priv->rx_queue[i]->dev = dev;
-               spin_lock_init(&(priv->rx_queue[i]->rxlock));
-       }
-
-
        stash = of_get_property(np, "bd-stash", NULL);
 
        if (stash) {
@@ -749,17 +859,16 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
                memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
 
        if (model && !strcasecmp(model, "TSEC"))
-               priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+               priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
                                     FSL_GIANFAR_DEV_HAS_COALESCE |
                                     FSL_GIANFAR_DEV_HAS_RMON |
                                     FSL_GIANFAR_DEV_HAS_MULTI_INTR;
 
        if (model && !strcasecmp(model, "eTSEC"))
-               priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
+               priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT |
                                     FSL_GIANFAR_DEV_HAS_COALESCE |
                                     FSL_GIANFAR_DEV_HAS_RMON |
                                     FSL_GIANFAR_DEV_HAS_MULTI_INTR |
-                                    FSL_GIANFAR_DEV_HAS_PADDING |
                                     FSL_GIANFAR_DEV_HAS_CSUM |
                                     FSL_GIANFAR_DEV_HAS_VLAN |
                                     FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
@@ -784,12 +893,12 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
 
        return 0;
 
-rx_alloc_failed:
-       free_rx_pointers(priv);
-tx_alloc_failed:
-       free_tx_pointers(priv);
 err_grp_init:
        unmap_group_regs(priv);
+rx_alloc_failed:
+       gfar_free_rx_queues(priv);
+tx_alloc_failed:
+       gfar_free_tx_queues(priv);
        free_gfar_dev(priv);
        return err;
 }
@@ -822,18 +931,16 @@ static int gfar_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr)
        switch (config.rx_filter) {
        case HWTSTAMP_FILTER_NONE:
                if (priv->hwts_rx_en) {
-                       stop_gfar(netdev);
                        priv->hwts_rx_en = 0;
-                       startup_gfar(netdev);
+                       reset_gfar(netdev);
                }
                break;
        default:
                if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER))
                        return -ERANGE;
                if (!priv->hwts_rx_en) {
-                       stop_gfar(netdev);
                        priv->hwts_rx_en = 1;
-                       startup_gfar(netdev);
+                       reset_gfar(netdev);
                }
                config.rx_filter = HWTSTAMP_FILTER_ALL;
                break;
@@ -875,19 +982,6 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return phy_mii_ioctl(priv->phydev, rq, cmd);
 }
 
-static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs)
-{
-       unsigned int new_bit_map = 0x0;
-       int mask = 0x1 << (max_qs - 1), i;
-
-       for (i = 0; i < max_qs; i++) {
-               if (bit_map & mask)
-                       new_bit_map = new_bit_map + (1 << i);
-               mask = mask >> 0x1;
-       }
-       return new_bit_map;
-}
-
 static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar,
                                   u32 class)
 {
@@ -995,14 +1089,185 @@ static void gfar_detect_errata(struct gfar_private *priv)
        /* no plans to fix */
        priv->errata |= GFAR_ERRATA_A002;
 
-       if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2))
-               __gfar_detect_errata_85xx(priv);
-       else /* non-mpc85xx parts, i.e. e300 core based */
-               __gfar_detect_errata_83xx(priv);
+       if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2))
+               __gfar_detect_errata_85xx(priv);
+       else /* non-mpc85xx parts, i.e. e300 core based */
+               __gfar_detect_errata_83xx(priv);
+
+       if (priv->errata)
+               dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
+                        priv->errata);
+}
+
+void gfar_mac_reset(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 tempval;
+
+       /* Reset MAC layer */
+       gfar_write(&regs->maccfg1, MACCFG1_SOFT_RESET);
+
+       /* We need to delay at least 3 TX clocks */
+       udelay(3);
+
+       /* the soft reset bit is not self-resetting, so we need to
+        * clear it before resuming normal operation
+        */
+       gfar_write(&regs->maccfg1, 0);
+
+       udelay(3);
+
+       /* Compute rx_buff_size based on config flags */
+       gfar_rx_buff_size_config(priv);
+
+       /* Initialize the max receive frame/buffer lengths */
+       gfar_write(&regs->maxfrm, priv->rx_buffer_size);
+       gfar_write(&regs->mrblr, priv->rx_buffer_size);
+
+       /* Initialize the Minimum Frame Length Register */
+       gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
+
+       /* Initialize MACCFG2. */
+       tempval = MACCFG2_INIT_SETTINGS;
+
+       /* If the mtu is larger than the max size for standard
+        * ethernet frames (ie, a jumbo frame), then set maccfg2
+        * to allow huge frames, and to check the length
+        */
+       if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
+           gfar_has_errata(priv, GFAR_ERRATA_74))
+               tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
+
+       gfar_write(&regs->maccfg2, tempval);
+
+       /* Clear mac addr hash registers */
+       gfar_write(&regs->igaddr0, 0);
+       gfar_write(&regs->igaddr1, 0);
+       gfar_write(&regs->igaddr2, 0);
+       gfar_write(&regs->igaddr3, 0);
+       gfar_write(&regs->igaddr4, 0);
+       gfar_write(&regs->igaddr5, 0);
+       gfar_write(&regs->igaddr6, 0);
+       gfar_write(&regs->igaddr7, 0);
+
+       gfar_write(&regs->gaddr0, 0);
+       gfar_write(&regs->gaddr1, 0);
+       gfar_write(&regs->gaddr2, 0);
+       gfar_write(&regs->gaddr3, 0);
+       gfar_write(&regs->gaddr4, 0);
+       gfar_write(&regs->gaddr5, 0);
+       gfar_write(&regs->gaddr6, 0);
+       gfar_write(&regs->gaddr7, 0);
+
+       if (priv->extended_hash)
+               gfar_clear_exact_match(priv->ndev);
+
+       gfar_mac_rx_config(priv);
+
+       gfar_mac_tx_config(priv);
+
+       gfar_set_mac_address(priv->ndev);
+
+       gfar_set_multi(priv->ndev);
+
+       /* clear ievent and imask before configuring coalescing */
+       gfar_ints_disable(priv);
+
+       /* Configure the coalescing support */
+       gfar_configure_coalescing_all(priv);
+}
+
+static void gfar_hw_init(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 attrs;
+
+       /* Stop the DMA engine now, in case it was running before
+        * (The firmware could have used it, and left it running).
+        */
+       gfar_halt(priv);
+
+       gfar_mac_reset(priv);
+
+       /* Zero out the rmon mib registers if it has them */
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+               memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib));
+
+               /* Mask off the CAM interrupts */
+               gfar_write(&regs->rmon.cam1, 0xffffffff);
+               gfar_write(&regs->rmon.cam2, 0xffffffff);
+       }
+
+       /* Initialize ECNTRL */
+       gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
+
+       /* Set the extraction length and index */
+       attrs = ATTRELI_EL(priv->rx_stash_size) |
+               ATTRELI_EI(priv->rx_stash_index);
+
+       gfar_write(&regs->attreli, attrs);
+
+       /* Start with defaults, and add stashing
+        * depending on driver parameters
+        */
+       attrs = ATTR_INIT_SETTINGS;
+
+       if (priv->bd_stash_en)
+               attrs |= ATTR_BDSTASH;
+
+       if (priv->rx_stash_size != 0)
+               attrs |= ATTR_BUFSTASH;
+
+       gfar_write(&regs->attr, attrs);
+
+       /* FIFO configs */
+       gfar_write(&regs->fifo_tx_thr, DEFAULT_FIFO_TX_THR);
+       gfar_write(&regs->fifo_tx_starve, DEFAULT_FIFO_TX_STARVE);
+       gfar_write(&regs->fifo_tx_starve_shutoff, DEFAULT_FIFO_TX_STARVE_OFF);
+
+       /* Program the interrupt steering regs, only for MG devices */
+       if (priv->num_grps > 1)
+               gfar_write_isrg(priv);
+}
+
+static void __init gfar_init_addr_hash_table(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+               priv->extended_hash = 1;
+               priv->hash_width = 9;
+
+               priv->hash_regs[0] = &regs->igaddr0;
+               priv->hash_regs[1] = &regs->igaddr1;
+               priv->hash_regs[2] = &regs->igaddr2;
+               priv->hash_regs[3] = &regs->igaddr3;
+               priv->hash_regs[4] = &regs->igaddr4;
+               priv->hash_regs[5] = &regs->igaddr5;
+               priv->hash_regs[6] = &regs->igaddr6;
+               priv->hash_regs[7] = &regs->igaddr7;
+               priv->hash_regs[8] = &regs->gaddr0;
+               priv->hash_regs[9] = &regs->gaddr1;
+               priv->hash_regs[10] = &regs->gaddr2;
+               priv->hash_regs[11] = &regs->gaddr3;
+               priv->hash_regs[12] = &regs->gaddr4;
+               priv->hash_regs[13] = &regs->gaddr5;
+               priv->hash_regs[14] = &regs->gaddr6;
+               priv->hash_regs[15] = &regs->gaddr7;
+
+       } else {
+               priv->extended_hash = 0;
+               priv->hash_width = 8;
 
-       if (priv->errata)
-               dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
-                        priv->errata);
+               priv->hash_regs[0] = &regs->gaddr0;
+               priv->hash_regs[1] = &regs->gaddr1;
+               priv->hash_regs[2] = &regs->gaddr2;
+               priv->hash_regs[3] = &regs->gaddr3;
+               priv->hash_regs[4] = &regs->gaddr4;
+               priv->hash_regs[5] = &regs->gaddr5;
+               priv->hash_regs[6] = &regs->gaddr6;
+               priv->hash_regs[7] = &regs->gaddr7;
+       }
 }
 
 /* Set up the ethernet device structure, private data,
@@ -1010,14 +1275,9 @@ static void gfar_detect_errata(struct gfar_private *priv)
  */
 static int gfar_probe(struct platform_device *ofdev)
 {
-       u32 tempval;
        struct net_device *dev = NULL;
        struct gfar_private *priv = NULL;
-       struct gfar __iomem *regs = NULL;
-       int err = 0, i, grp_idx = 0;
-       u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0;
-       u32 isrg = 0;
-       u32 __iomem *baddr;
+       int err = 0, i;
 
        err = gfar_of_init(ofdev, &dev);
 
@@ -1034,42 +1294,11 @@ static int gfar_probe(struct platform_device *ofdev)
        INIT_WORK(&priv->reset_task, gfar_reset_task);
 
        platform_set_drvdata(ofdev, priv);
-       regs = priv->gfargrp[0].regs;
 
        gfar_detect_errata(priv);
 
-       /* Stop the DMA engine now, in case it was running before
-        * (The firmware could have used it, and left it running).
-        */
-       gfar_halt(dev);
-
-       /* Reset MAC layer */
-       gfar_write(&regs->maccfg1, MACCFG1_SOFT_RESET);
-
-       /* We need to delay at least 3 TX clocks */
-       udelay(2);
-
-       tempval = 0;
-       if (!priv->pause_aneg_en && priv->tx_pause_en)
-               tempval |= MACCFG1_TX_FLOW;
-       if (!priv->pause_aneg_en && priv->rx_pause_en)
-               tempval |= MACCFG1_RX_FLOW;
-       /* the soft reset bit is not self-resetting, so we need to
-        * clear it before resuming normal operation
-        */
-       gfar_write(&regs->maccfg1, tempval);
-
-       /* Initialize MACCFG2. */
-       tempval = MACCFG2_INIT_SETTINGS;
-       if (gfar_has_errata(priv, GFAR_ERRATA_74))
-               tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
-       gfar_write(&regs->maccfg2, tempval);
-
-       /* Initialize ECNTRL */
-       gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
-
        /* Set the dev->base_addr to the gfar reg region */
-       dev->base_addr = (unsigned long) regs;
+       dev->base_addr = (unsigned long) priv->gfargrp[0].regs;
 
        /* Fill in the dev structure */
        dev->watchdog_timeo = TX_TIMEOUT;
@@ -1078,13 +1307,19 @@ static int gfar_probe(struct platform_device *ofdev)
        dev->ethtool_ops = &gfar_ethtool_ops;
 
        /* Register for napi ...We are registering NAPI for each grp */
-       if (priv->mode == SQ_SG_MODE)
-               netif_napi_add(dev, &priv->gfargrp[0].napi, gfar_poll_sq,
-                              GFAR_DEV_WEIGHT);
-       else
-               for (i = 0; i < priv->num_grps; i++)
-                       netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll,
-                                      GFAR_DEV_WEIGHT);
+       for (i = 0; i < priv->num_grps; i++) {
+               if (priv->poll_mode == GFAR_SQ_POLLING) {
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
+                                      gfar_poll_rx_sq, GFAR_DEV_WEIGHT);
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_tx,
+                                      gfar_poll_tx_sq, 2);
+               } else {
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_rx,
+                                      gfar_poll_rx, GFAR_DEV_WEIGHT);
+                       netif_napi_add(dev, &priv->gfargrp[i].napi_tx,
+                                      gfar_poll_tx, 2);
+               }
+       }
 
        if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
                dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
@@ -1099,103 +1334,16 @@ static int gfar_probe(struct platform_device *ofdev)
                dev->features |= NETIF_F_HW_VLAN_CTAG_RX;
        }
 
-       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
-               priv->extended_hash = 1;
-               priv->hash_width = 9;
-
-               priv->hash_regs[0] = &regs->igaddr0;
-               priv->hash_regs[1] = &regs->igaddr1;
-               priv->hash_regs[2] = &regs->igaddr2;
-               priv->hash_regs[3] = &regs->igaddr3;
-               priv->hash_regs[4] = &regs->igaddr4;
-               priv->hash_regs[5] = &regs->igaddr5;
-               priv->hash_regs[6] = &regs->igaddr6;
-               priv->hash_regs[7] = &regs->igaddr7;
-               priv->hash_regs[8] = &regs->gaddr0;
-               priv->hash_regs[9] = &regs->gaddr1;
-               priv->hash_regs[10] = &regs->gaddr2;
-               priv->hash_regs[11] = &regs->gaddr3;
-               priv->hash_regs[12] = &regs->gaddr4;
-               priv->hash_regs[13] = &regs->gaddr5;
-               priv->hash_regs[14] = &regs->gaddr6;
-               priv->hash_regs[15] = &regs->gaddr7;
-
-       } else {
-               priv->extended_hash = 0;
-               priv->hash_width = 8;
-
-               priv->hash_regs[0] = &regs->gaddr0;
-               priv->hash_regs[1] = &regs->gaddr1;
-               priv->hash_regs[2] = &regs->gaddr2;
-               priv->hash_regs[3] = &regs->gaddr3;
-               priv->hash_regs[4] = &regs->gaddr4;
-               priv->hash_regs[5] = &regs->gaddr5;
-               priv->hash_regs[6] = &regs->gaddr6;
-               priv->hash_regs[7] = &regs->gaddr7;
-       }
+       gfar_init_addr_hash_table(priv);
 
-       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
-               priv->padding = DEFAULT_PADDING;
-       else
-               priv->padding = 0;
+       /* Insert receive time stamps into padding alignment bytes */
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
+               priv->padding = 8;
 
        if (dev->features & NETIF_F_IP_CSUM ||
            priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
                dev->needed_headroom = GMAC_FCB_LEN;
 
-       /* Program the isrg regs only if number of grps > 1 */
-       if (priv->num_grps > 1) {
-               baddr = &regs->isrg0;
-               for (i = 0; i < priv->num_grps; i++) {
-                       isrg |= (priv->gfargrp[i].rx_bit_map << ISRG_SHIFT_RX);
-                       isrg |= (priv->gfargrp[i].tx_bit_map << ISRG_SHIFT_TX);
-                       gfar_write(baddr, isrg);
-                       baddr++;
-                       isrg = 0x0;
-               }
-       }
-
-       /* Need to reverse the bit maps as  bit_map's MSB is q0
-        * but, for_each_set_bit parses from right to left, which
-        * basically reverses the queue numbers
-        */
-       for (i = 0; i< priv->num_grps; i++) {
-               priv->gfargrp[i].tx_bit_map =
-                       reverse_bitmap(priv->gfargrp[i].tx_bit_map, MAX_TX_QS);
-               priv->gfargrp[i].rx_bit_map =
-                       reverse_bitmap(priv->gfargrp[i].rx_bit_map, MAX_RX_QS);
-       }
-
-       /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values,
-        * also assign queues to groups
-        */
-       for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
-               priv->gfargrp[grp_idx].num_rx_queues = 0x0;
-
-               for_each_set_bit(i, &priv->gfargrp[grp_idx].rx_bit_map,
-                                priv->num_rx_queues) {
-                       priv->gfargrp[grp_idx].num_rx_queues++;
-                       priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx];
-                       rstat = rstat | (RSTAT_CLEAR_RHALT >> i);
-                       rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i);
-               }
-               priv->gfargrp[grp_idx].num_tx_queues = 0x0;
-
-               for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map,
-                                priv->num_tx_queues) {
-                       priv->gfargrp[grp_idx].num_tx_queues++;
-                       priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx];
-                       tstat = tstat | (TSTAT_CLEAR_THALT >> i);
-                       tqueue = tqueue | (TQUEUE_EN0 >> i);
-               }
-               priv->gfargrp[grp_idx].rstat = rstat;
-               priv->gfargrp[grp_idx].tstat = tstat;
-               rstat = tstat =0;
-       }
-
-       gfar_write(&regs->rqueue, rqueue);
-       gfar_write(&regs->tqueue, tqueue);
-
        priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
 
        /* Initializing some of the rx/tx queue level parameters */
@@ -1220,8 +1368,9 @@ static int gfar_probe(struct platform_device *ofdev)
        if (priv->num_tx_queues == 1)
                priv->prio_sched_en = 1;
 
-       /* Carrier starts down, phylib will bring it up */
-       netif_carrier_off(dev);
+       set_bit(GFAR_DOWN, &priv->state);
+
+       gfar_hw_init(priv);
 
        err = register_netdev(dev);
 
@@ -1230,6 +1379,9 @@ static int gfar_probe(struct platform_device *ofdev)
                goto register_fail;
        }
 
+       /* Carrier starts down, phylib will bring it up */
+       netif_carrier_off(dev);
+
        device_init_wakeup(&dev->dev,
                           priv->device_flags &
                           FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
@@ -1251,9 +1403,6 @@ static int gfar_probe(struct platform_device *ofdev)
        /* Initialize the filer table */
        gfar_init_filer_table(priv);
 
-       /* Create all the sysfs files */
-       gfar_init_sysfs(dev);
-
        /* Print out the device info */
        netdev_info(dev, "mac: %pM\n", dev->dev_addr);
 
@@ -1272,8 +1421,8 @@ static int gfar_probe(struct platform_device *ofdev)
 
 register_fail:
        unmap_group_regs(priv);
-       free_tx_pointers(priv);
-       free_rx_pointers(priv);
+       gfar_free_rx_queues(priv);
+       gfar_free_tx_queues(priv);
        if (priv->phy_node)
                of_node_put(priv->phy_node);
        if (priv->tbi_node)
@@ -1293,6 +1442,8 @@ static int gfar_remove(struct platform_device *ofdev)
 
        unregister_netdev(priv->ndev);
        unmap_group_regs(priv);
+       gfar_free_rx_queues(priv);
+       gfar_free_tx_queues(priv);
        free_gfar_dev(priv);
 
        return 0;
@@ -1318,9 +1469,8 @@ static int gfar_suspend(struct device *dev)
 
                local_irq_save(flags);
                lock_tx_qs(priv);
-               lock_rx_qs(priv);
 
-               gfar_halt_nodisable(ndev);
+               gfar_halt_nodisable(priv);
 
                /* Disable Tx, and Rx if wake-on-LAN is disabled. */
                tempval = gfar_read(&regs->maccfg1);
@@ -1332,7 +1482,6 @@ static int gfar_suspend(struct device *dev)
 
                gfar_write(&regs->maccfg1, tempval);
 
-               unlock_rx_qs(priv);
                unlock_tx_qs(priv);
                local_irq_restore(flags);
 
@@ -1378,15 +1527,13 @@ static int gfar_resume(struct device *dev)
         */
        local_irq_save(flags);
        lock_tx_qs(priv);
-       lock_rx_qs(priv);
 
        tempval = gfar_read(&regs->maccfg2);
        tempval &= ~MACCFG2_MPEN;
        gfar_write(&regs->maccfg2, tempval);
 
-       gfar_start(ndev);
+       gfar_start(priv);
 
-       unlock_rx_qs(priv);
        unlock_tx_qs(priv);
        local_irq_restore(flags);
 
@@ -1413,10 +1560,11 @@ static int gfar_restore(struct device *dev)
                return -ENOMEM;
        }
 
-       init_registers(ndev);
-       gfar_set_mac_address(ndev);
-       gfar_init_mac(ndev);
-       gfar_start(ndev);
+       gfar_mac_reset(priv);
+
+       gfar_init_tx_rx_base(priv);
+
+       gfar_start(priv);
 
        priv->oldlink = 0;
        priv->oldspeed = 0;
@@ -1574,57 +1722,6 @@ static void gfar_configure_serdes(struct net_device *dev)
                  BMCR_SPEED1000);
 }
 
-static void init_registers(struct net_device *dev)
-{
-       struct gfar_private *priv = netdev_priv(dev);
-       struct gfar __iomem *regs = NULL;
-       int i;
-
-       for (i = 0; i < priv->num_grps; i++) {
-               regs = priv->gfargrp[i].regs;
-               /* Clear IEVENT */
-               gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
-
-               /* Initialize IMASK */
-               gfar_write(&regs->imask, IMASK_INIT_CLEAR);
-       }
-
-       regs = priv->gfargrp[0].regs;
-       /* Init hash registers to zero */
-       gfar_write(&regs->igaddr0, 0);
-       gfar_write(&regs->igaddr1, 0);
-       gfar_write(&regs->igaddr2, 0);
-       gfar_write(&regs->igaddr3, 0);
-       gfar_write(&regs->igaddr4, 0);
-       gfar_write(&regs->igaddr5, 0);
-       gfar_write(&regs->igaddr6, 0);
-       gfar_write(&regs->igaddr7, 0);
-
-       gfar_write(&regs->gaddr0, 0);
-       gfar_write(&regs->gaddr1, 0);
-       gfar_write(&regs->gaddr2, 0);
-       gfar_write(&regs->gaddr3, 0);
-       gfar_write(&regs->gaddr4, 0);
-       gfar_write(&regs->gaddr5, 0);
-       gfar_write(&regs->gaddr6, 0);
-       gfar_write(&regs->gaddr7, 0);
-
-       /* Zero out the rmon mib registers if it has them */
-       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
-               memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib));
-
-               /* Mask off the CAM interrupts */
-               gfar_write(&regs->rmon.cam1, 0xffffffff);
-               gfar_write(&regs->rmon.cam2, 0xffffffff);
-       }
-
-       /* Initialize the max receive buffer length */
-       gfar_write(&regs->mrblr, priv->rx_buffer_size);
-
-       /* Initialize the Minimum Frame Length Register */
-       gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
-}
-
 static int __gfar_is_rx_idle(struct gfar_private *priv)
 {
        u32 res;
@@ -1648,23 +1745,13 @@ static int __gfar_is_rx_idle(struct gfar_private *priv)
 }
 
 /* Halt the receive and transmit queues */
-static void gfar_halt_nodisable(struct net_device *dev)
+static void gfar_halt_nodisable(struct gfar_private *priv)
 {
-       struct gfar_private *priv = netdev_priv(dev);
-       struct gfar __iomem *regs = NULL;
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 tempval;
-       int i;
-
-       for (i = 0; i < priv->num_grps; i++) {
-               regs = priv->gfargrp[i].regs;
-               /* Mask all interrupts */
-               gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
-               /* Clear all interrupts */
-               gfar_write(&regs->ievent, IEVENT_INIT_CLEAR);
-       }
+       gfar_ints_disable(priv);
 
-       regs = priv->gfargrp[0].regs;
        /* Stop the DMA, and wait for it to stop */
        tempval = gfar_read(&regs->dmactrl);
        if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) !=
@@ -1685,56 +1772,41 @@ static void gfar_halt_nodisable(struct net_device *dev)
 }
 
 /* Halt the receive and transmit queues */
-void gfar_halt(struct net_device *dev)
+void gfar_halt(struct gfar_private *priv)
 {
-       struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 tempval;
 
-       gfar_halt_nodisable(dev);
+       /* Dissable the Rx/Tx hw queues */
+       gfar_write(&regs->rqueue, 0);
+       gfar_write(&regs->tqueue, 0);
 
-       /* Disable Rx and Tx */
+       mdelay(10);
+
+       gfar_halt_nodisable(priv);
+
+       /* Disable Rx/Tx DMA */
        tempval = gfar_read(&regs->maccfg1);
        tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
        gfar_write(&regs->maccfg1, tempval);
 }
 
-static void free_grp_irqs(struct gfar_priv_grp *grp)
-{
-       free_irq(gfar_irq(grp, TX)->irq, grp);
-       free_irq(gfar_irq(grp, RX)->irq, grp);
-       free_irq(gfar_irq(grp, ER)->irq, grp);
-}
-
 void stop_gfar(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int i;
-
-       phy_stop(priv->phydev);
 
+       netif_tx_stop_all_queues(dev);
 
-       /* Lock it down */
-       local_irq_save(flags);
-       lock_tx_qs(priv);
-       lock_rx_qs(priv);
+       smp_mb__before_clear_bit();
+       set_bit(GFAR_DOWN, &priv->state);
+       smp_mb__after_clear_bit();
 
-       gfar_halt(dev);
+       disable_napi(priv);
 
-       unlock_rx_qs(priv);
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
+       /* disable ints and gracefully shut down Rx/Tx DMA */
+       gfar_halt(priv);
 
-       /* Free the IRQs */
-       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
-               for (i = 0; i < priv->num_grps; i++)
-                       free_grp_irqs(&priv->gfargrp[i]);
-       } else {
-               for (i = 0; i < priv->num_grps; i++)
-                       free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
-                                &priv->gfargrp[i]);
-       }
+       phy_stop(priv->phydev);
 
        free_skb_resources(priv);
 }
@@ -1825,17 +1897,15 @@ static void free_skb_resources(struct gfar_private *priv)
                          priv->tx_queue[0]->tx_bd_dma_base);
 }
 
-void gfar_start(struct net_device *dev)
+void gfar_start(struct gfar_private *priv)
 {
-       struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
        u32 tempval;
        int i = 0;
 
-       /* Enable Rx and Tx in MACCFG1 */
-       tempval = gfar_read(&regs->maccfg1);
-       tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
-       gfar_write(&regs->maccfg1, tempval);
+       /* Enable Rx/Tx hw queues */
+       gfar_write(&regs->rqueue, priv->rqueue);
+       gfar_write(&regs->tqueue, priv->tqueue);
 
        /* Initialize DMACTRL to have WWR and WOP */
        tempval = gfar_read(&regs->dmactrl);
@@ -1852,52 +1922,23 @@ void gfar_start(struct net_device *dev)
                /* Clear THLT/RHLT, so that the DMA starts polling now */
                gfar_write(&regs->tstat, priv->gfargrp[i].tstat);
                gfar_write(&regs->rstat, priv->gfargrp[i].rstat);
-               /* Unmask the interrupts we look for */
-               gfar_write(&regs->imask, IMASK_DEFAULT);
-       }
-
-       dev->trans_start = jiffies; /* prevent tx timeout */
-}
-
-static void gfar_configure_coalescing(struct gfar_private *priv,
-                              unsigned long tx_mask, unsigned long rx_mask)
-{
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       u32 __iomem *baddr;
-
-       if (priv->mode == MQ_MG_MODE) {
-               int i = 0;
-
-               baddr = &regs->txic0;
-               for_each_set_bit(i, &tx_mask, priv->num_tx_queues) {
-                       gfar_write(baddr + i, 0);
-                       if (likely(priv->tx_queue[i]->txcoalescing))
-                               gfar_write(baddr + i, priv->tx_queue[i]->txic);
-               }
-
-               baddr = &regs->rxic0;
-               for_each_set_bit(i, &rx_mask, priv->num_rx_queues) {
-                       gfar_write(baddr + i, 0);
-                       if (likely(priv->rx_queue[i]->rxcoalescing))
-                               gfar_write(baddr + i, priv->rx_queue[i]->rxic);
-               }
-       } else {
-               /* Backward compatible case -- even if we enable
-                * multiple queues, there's only single reg to program
-                */
-               gfar_write(&regs->txic, 0);
-               if (likely(priv->tx_queue[0]->txcoalescing))
-                       gfar_write(&regs->txic, priv->tx_queue[0]->txic);
-
-               gfar_write(&regs->rxic, 0);
-               if (unlikely(priv->rx_queue[0]->rxcoalescing))
-                       gfar_write(&regs->rxic, priv->rx_queue[0]->rxic);
        }
+
+       /* Enable Rx/Tx DMA */
+       tempval = gfar_read(&regs->maccfg1);
+       tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+       gfar_write(&regs->maccfg1, tempval);
+
+       gfar_ints_enable(priv);
+
+       priv->ndev->trans_start = jiffies; /* prevent tx timeout */
 }
 
-void gfar_configure_coalescing_all(struct gfar_private *priv)
+static void free_grp_irqs(struct gfar_priv_grp *grp)
 {
-       gfar_configure_coalescing(priv, 0xFF, 0xFF);
+       free_irq(gfar_irq(grp, TX)->irq, grp);
+       free_irq(gfar_irq(grp, RX)->irq, grp);
+       free_irq(gfar_irq(grp, ER)->irq, grp);
 }
 
 static int register_grp_irqs(struct gfar_priv_grp *grp)
@@ -1956,46 +1997,65 @@ err_irq_fail:
 
 }
 
-/* Bring the controller up and running */
-int startup_gfar(struct net_device *ndev)
+static void gfar_free_irq(struct gfar_private *priv)
 {
-       struct gfar_private *priv = netdev_priv(ndev);
-       struct gfar __iomem *regs = NULL;
-       int err, i, j;
+       int i;
 
-       for (i = 0; i < priv->num_grps; i++) {
-               regs= priv->gfargrp[i].regs;
-               gfar_write(&regs->imask, IMASK_INIT_CLEAR);
+       /* Free the IRQs */
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
+               for (i = 0; i < priv->num_grps; i++)
+                       free_grp_irqs(&priv->gfargrp[i]);
+       } else {
+               for (i = 0; i < priv->num_grps; i++)
+                       free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq,
+                                &priv->gfargrp[i]);
        }
+}
 
-       regs= priv->gfargrp[0].regs;
-       err = gfar_alloc_skb_resources(ndev);
-       if (err)
-               return err;
-
-       gfar_init_mac(ndev);
+static int gfar_request_irq(struct gfar_private *priv)
+{
+       int err, i, j;
 
        for (i = 0; i < priv->num_grps; i++) {
                err = register_grp_irqs(&priv->gfargrp[i]);
                if (err) {
                        for (j = 0; j < i; j++)
                                free_grp_irqs(&priv->gfargrp[j]);
-                       goto irq_fail;
+                       return err;
                }
        }
 
-       /* Start the controller */
-       gfar_start(ndev);
+       return 0;
+}
+
+/* Bring the controller up and running */
+int startup_gfar(struct net_device *ndev)
+{
+       struct gfar_private *priv = netdev_priv(ndev);
+       int err;
+
+       gfar_mac_reset(priv);
+
+       err = gfar_alloc_skb_resources(ndev);
+       if (err)
+               return err;
+
+       gfar_init_tx_rx_base(priv);
+
+       smp_mb__before_clear_bit();
+       clear_bit(GFAR_DOWN, &priv->state);
+       smp_mb__after_clear_bit();
+
+       /* Start Rx/Tx DMA and enable the interrupts */
+       gfar_start(priv);
 
        phy_start(priv->phydev);
 
-       gfar_configure_coalescing_all(priv);
+       enable_napi(priv);
 
-       return 0;
+       netif_tx_wake_all_queues(ndev);
 
-irq_fail:
-       free_skb_resources(priv);
-       return err;
+       return 0;
 }
 
 /* Called when something needs to use the ethernet device
@@ -2006,27 +2066,17 @@ static int gfar_enet_open(struct net_device *dev)
        struct gfar_private *priv = netdev_priv(dev);
        int err;
 
-       enable_napi(priv);
-
-       /* Initialize a bunch of registers */
-       init_registers(dev);
-
-       gfar_set_mac_address(dev);
-
        err = init_phy(dev);
+       if (err)
+               return err;
 
-       if (err) {
-               disable_napi(priv);
+       err = gfar_request_irq(priv);
+       if (err)
                return err;
-       }
 
        err = startup_gfar(dev);
-       if (err) {
-               disable_napi(priv);
+       if (err)
                return err;
-       }
-
-       netif_tx_start_all_queues(dev);
 
        device_set_wakeup_enable(&dev->dev, priv->wol_en);
 
@@ -2152,13 +2202,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                skb_new = skb_realloc_headroom(skb, fcb_len);
                if (!skb_new) {
                        dev->stats.tx_errors++;
-                       kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        return NETDEV_TX_OK;
                }
 
                if (skb->sk)
                        skb_set_owner_w(skb_new, skb->sk);
-               consume_skb(skb);
+               dev_consume_skb_any(skb);
                skb = skb_new;
        }
 
@@ -2351,8 +2401,6 @@ static int gfar_close(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
 
-       disable_napi(priv);
-
        cancel_work_sync(&priv->reset_task);
        stop_gfar(dev);
 
@@ -2360,7 +2408,7 @@ static int gfar_close(struct net_device *dev)
        phy_disconnect(priv->phydev);
        priv->phydev = NULL;
 
-       netif_tx_stop_all_queues(dev);
+       gfar_free_irq(priv);
 
        return 0;
 }
@@ -2373,77 +2421,9 @@ static int gfar_set_mac_address(struct net_device *dev)
        return 0;
 }
 
-/* Check if rx parser should be activated */
-void gfar_check_rx_parser_mode(struct gfar_private *priv)
-{
-       struct gfar __iomem *regs;
-       u32 tempval;
-
-       regs = priv->gfargrp[0].regs;
-
-       tempval = gfar_read(&regs->rctrl);
-       /* If parse is no longer required, then disable parser */
-       if (tempval & RCTRL_REQ_PARSER) {
-               tempval |= RCTRL_PRSDEP_INIT;
-               priv->uses_rxfcb = 1;
-       } else {
-               tempval &= ~RCTRL_PRSDEP_INIT;
-               priv->uses_rxfcb = 0;
-       }
-       gfar_write(&regs->rctrl, tempval);
-}
-
-/* Enables and disables VLAN insertion/extraction */
-void gfar_vlan_mode(struct net_device *dev, netdev_features_t features)
-{
-       struct gfar_private *priv = netdev_priv(dev);
-       struct gfar __iomem *regs = NULL;
-       unsigned long flags;
-       u32 tempval;
-
-       regs = priv->gfargrp[0].regs;
-       local_irq_save(flags);
-       lock_rx_qs(priv);
-
-       if (features & NETIF_F_HW_VLAN_CTAG_TX) {
-               /* Enable VLAN tag insertion */
-               tempval = gfar_read(&regs->tctrl);
-               tempval |= TCTRL_VLINS;
-               gfar_write(&regs->tctrl, tempval);
-       } else {
-               /* Disable VLAN tag insertion */
-               tempval = gfar_read(&regs->tctrl);
-               tempval &= ~TCTRL_VLINS;
-               gfar_write(&regs->tctrl, tempval);
-       }
-
-       if (features & NETIF_F_HW_VLAN_CTAG_RX) {
-               /* Enable VLAN tag extraction */
-               tempval = gfar_read(&regs->rctrl);
-               tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT);
-               gfar_write(&regs->rctrl, tempval);
-               priv->uses_rxfcb = 1;
-       } else {
-               /* Disable VLAN tag extraction */
-               tempval = gfar_read(&regs->rctrl);
-               tempval &= ~RCTRL_VLEX;
-               gfar_write(&regs->rctrl, tempval);
-
-               gfar_check_rx_parser_mode(priv);
-       }
-
-       gfar_change_mtu(dev, dev->mtu);
-
-       unlock_rx_qs(priv);
-       local_irq_restore(flags);
-}
-
 static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 {
-       int tempsize, tempval;
        struct gfar_private *priv = netdev_priv(dev);
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       int oldsize = priv->rx_buffer_size;
        int frame_size = new_mtu + ETH_HLEN;
 
        if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
@@ -2451,45 +2431,33 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
                return -EINVAL;
        }
 
-       if (priv->uses_rxfcb)
-               frame_size += GMAC_FCB_LEN;
-
-       frame_size += priv->padding;
-
-       tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) +
-                  INCREMENTAL_BUFFER_SIZE;
+       while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+               cpu_relax();
 
-       /* Only stop and start the controller if it isn't already
-        * stopped, and we changed something
-        */
-       if ((oldsize != tempsize) && (dev->flags & IFF_UP))
+       if (dev->flags & IFF_UP)
                stop_gfar(dev);
 
-       priv->rx_buffer_size = tempsize;
-
        dev->mtu = new_mtu;
 
-       gfar_write(&regs->mrblr, priv->rx_buffer_size);
-       gfar_write(&regs->maxfrm, priv->rx_buffer_size);
+       if (dev->flags & IFF_UP)
+               startup_gfar(dev);
 
-       /* If the mtu is larger than the max size for standard
-        * ethernet frames (ie, a jumbo frame), then set maccfg2
-        * to allow huge frames, and to check the length
-        */
-       tempval = gfar_read(&regs->maccfg2);
+       clear_bit_unlock(GFAR_RESETTING, &priv->state);
 
-       if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
-           gfar_has_errata(priv, GFAR_ERRATA_74))
-               tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
-       else
-               tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
+       return 0;
+}
 
-       gfar_write(&regs->maccfg2, tempval);
+void reset_gfar(struct net_device *ndev)
+{
+       struct gfar_private *priv = netdev_priv(ndev);
 
-       if ((oldsize != tempsize) && (dev->flags & IFF_UP))
-               startup_gfar(dev);
+       while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+               cpu_relax();
 
-       return 0;
+       stop_gfar(ndev);
+       startup_gfar(ndev);
+
+       clear_bit_unlock(GFAR_RESETTING, &priv->state);
 }
 
 /* gfar_reset_task gets scheduled when a packet has not been
@@ -2501,16 +2469,7 @@ static void gfar_reset_task(struct work_struct *work)
 {
        struct gfar_private *priv = container_of(work, struct gfar_private,
                                                 reset_task);
-       struct net_device *dev = priv->ndev;
-
-       if (dev->flags & IFF_UP) {
-               netif_tx_stop_all_queues(dev);
-               stop_gfar(dev);
-               startup_gfar(dev);
-               netif_tx_start_all_queues(dev);
-       }
-
-       netif_tx_schedule_all(dev);
+       reset_gfar(priv->ndev);
 }
 
 static void gfar_timeout(struct net_device *dev)
@@ -2623,8 +2582,10 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        }
 
        /* If we freed a buffer, we can restart transmission, if necessary */
-       if (netif_tx_queue_stopped(txq) && tx_queue->num_txbdfree)
-               netif_wake_subqueue(dev, tqi);
+       if (tx_queue->num_txbdfree &&
+           netif_tx_queue_stopped(txq) &&
+           !(test_bit(GFAR_DOWN, &priv->state)))
+               netif_wake_subqueue(priv->ndev, tqi);
 
        /* Update dirty indicators */
        tx_queue->skb_dirtytx = skb_dirtytx;
@@ -2633,31 +2594,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue)
        netdev_tx_completed_queue(txq, howmany, bytes_sent);
 }
 
-static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&gfargrp->grplock, flags);
-       if (napi_schedule_prep(&gfargrp->napi)) {
-               gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED);
-               __napi_schedule(&gfargrp->napi);
-       } else {
-               /* Clear IEVENT, so interrupts aren't called again
-                * because of the packets that have already arrived.
-                */
-               gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK);
-       }
-       spin_unlock_irqrestore(&gfargrp->grplock, flags);
-
-}
-
-/* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *grp_id)
-{
-       gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
-       return IRQ_HANDLED;
-}
-
 static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp,
                           struct sk_buff *skb)
 {
@@ -2728,7 +2664,48 @@ static inline void count_errors(unsigned short status, struct net_device *dev)
 
 irqreturn_t gfar_receive(int irq, void *grp_id)
 {
-       gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id);
+       struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
+       unsigned long flags;
+       u32 imask;
+
+       if (likely(napi_schedule_prep(&grp->napi_rx))) {
+               spin_lock_irqsave(&grp->grplock, flags);
+               imask = gfar_read(&grp->regs->imask);
+               imask &= IMASK_RX_DISABLED;
+               gfar_write(&grp->regs->imask, imask);
+               spin_unlock_irqrestore(&grp->grplock, flags);
+               __napi_schedule(&grp->napi_rx);
+       } else {
+               /* Clear IEVENT, so interrupts aren't called again
+                * because of the packets that have already arrived.
+                */
+               gfar_write(&grp->regs->ievent, IEVENT_RX_MASK);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* Interrupt Handler for Transmit complete */
+static irqreturn_t gfar_transmit(int irq, void *grp_id)
+{
+       struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id;
+       unsigned long flags;
+       u32 imask;
+
+       if (likely(napi_schedule_prep(&grp->napi_tx))) {
+               spin_lock_irqsave(&grp->grplock, flags);
+               imask = gfar_read(&grp->regs->imask);
+               imask &= IMASK_TX_DISABLED;
+               gfar_write(&grp->regs->imask, imask);
+               spin_unlock_irqrestore(&grp->grplock, flags);
+               __napi_schedule(&grp->napi_tx);
+       } else {
+               /* Clear IEVENT, so interrupts aren't called again
+                * because of the packets that have already arrived.
+                */
+               gfar_write(&grp->regs->ievent, IEVENT_TX_MASK);
+       }
+
        return IRQ_HANDLED;
 }
 
@@ -2852,7 +2829,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
                                rx_queue->stats.rx_bytes += pkt_len;
                                skb_record_rx_queue(skb, rx_queue->qindex);
                                gfar_process_frame(dev, skb, amount_pull,
-                                                  &rx_queue->grp->napi);
+                                                  &rx_queue->grp->napi_rx);
 
                        } else {
                                netif_warn(priv, rx_err, dev, "Missing skb!\n");
@@ -2881,66 +2858,81 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
        return howmany;
 }
 
-static int gfar_poll_sq(struct napi_struct *napi, int budget)
+static int gfar_poll_rx_sq(struct napi_struct *napi, int budget)
 {
        struct gfar_priv_grp *gfargrp =
-               container_of(napi, struct gfar_priv_grp, napi);
+               container_of(napi, struct gfar_priv_grp, napi_rx);
        struct gfar __iomem *regs = gfargrp->regs;
-       struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0];
-       struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0];
+       struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue;
        int work_done = 0;
 
        /* Clear IEVENT, so interrupts aren't called again
         * because of the packets that have already arrived
         */
-       gfar_write(&regs->ievent, IEVENT_RTX_MASK);
-
-       /* run Tx cleanup to completion */
-       if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
-               gfar_clean_tx_ring(tx_queue);
+       gfar_write(&regs->ievent, IEVENT_RX_MASK);
 
        work_done = gfar_clean_rx_ring(rx_queue, budget);
 
        if (work_done < budget) {
+               u32 imask;
                napi_complete(napi);
                /* Clear the halt bit in RSTAT */
                gfar_write(&regs->rstat, gfargrp->rstat);
 
-               gfar_write(&regs->imask, IMASK_DEFAULT);
-
-               /* If we are coalescing interrupts, update the timer
-                * Otherwise, clear it
-                */
-               gfar_write(&regs->txic, 0);
-               if (likely(tx_queue->txcoalescing))
-                       gfar_write(&regs->txic, tx_queue->txic);
-
-               gfar_write(&regs->rxic, 0);
-               if (unlikely(rx_queue->rxcoalescing))
-                       gfar_write(&regs->rxic, rx_queue->rxic);
+               spin_lock_irq(&gfargrp->grplock);
+               imask = gfar_read(&regs->imask);
+               imask |= IMASK_RX_DEFAULT;
+               gfar_write(&regs->imask, imask);
+               spin_unlock_irq(&gfargrp->grplock);
        }
 
        return work_done;
 }
 
-static int gfar_poll(struct napi_struct *napi, int budget)
+static int gfar_poll_tx_sq(struct napi_struct *napi, int budget)
+{
+       struct gfar_priv_grp *gfargrp =
+               container_of(napi, struct gfar_priv_grp, napi_tx);
+       struct gfar __iomem *regs = gfargrp->regs;
+       struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue;
+       u32 imask;
+
+       /* Clear IEVENT, so interrupts aren't called again
+        * because of the packets that have already arrived
+        */
+       gfar_write(&regs->ievent, IEVENT_TX_MASK);
+
+       /* run Tx cleanup to completion */
+       if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx])
+               gfar_clean_tx_ring(tx_queue);
+
+       napi_complete(napi);
+
+       spin_lock_irq(&gfargrp->grplock);
+       imask = gfar_read(&regs->imask);
+       imask |= IMASK_TX_DEFAULT;
+       gfar_write(&regs->imask, imask);
+       spin_unlock_irq(&gfargrp->grplock);
+
+       return 0;
+}
+
+static int gfar_poll_rx(struct napi_struct *napi, int budget)
 {
        struct gfar_priv_grp *gfargrp =
-               container_of(napi, struct gfar_priv_grp, napi);
+               container_of(napi, struct gfar_priv_grp, napi_rx);
        struct gfar_private *priv = gfargrp->priv;
        struct gfar __iomem *regs = gfargrp->regs;
-       struct gfar_priv_tx_q *tx_queue = NULL;
        struct gfar_priv_rx_q *rx_queue = NULL;
        int work_done = 0, work_done_per_q = 0;
        int i, budget_per_q = 0;
-       int has_tx_work = 0;
        unsigned long rstat_rxf;
        int num_act_queues;
 
        /* Clear IEVENT, so interrupts aren't called again
         * because of the packets that have already arrived
         */
-       gfar_write(&regs->ievent, IEVENT_RTX_MASK);
+       gfar_write(&regs->ievent, IEVENT_RX_MASK);
 
        rstat_rxf = gfar_read(&regs->rstat) & RSTAT_RXF_MASK;
 
@@ -2948,15 +2940,6 @@ static int gfar_poll(struct napi_struct *napi, int budget)
        if (num_act_queues)
                budget_per_q = budget/num_act_queues;
 
-       for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
-               tx_queue = priv->tx_queue[i];
-               /* run Tx cleanup to completion */
-               if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
-                       gfar_clean_tx_ring(tx_queue);
-                       has_tx_work = 1;
-               }
-       }
-
        for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) {
                /* skip queue if not active */
                if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i)))
@@ -2979,25 +2962,62 @@ static int gfar_poll(struct napi_struct *napi, int budget)
                }
        }
 
-       if (!num_act_queues && !has_tx_work) {
-
+       if (!num_act_queues) {
+               u32 imask;
                napi_complete(napi);
 
                /* Clear the halt bit in RSTAT */
                gfar_write(&regs->rstat, gfargrp->rstat);
 
-               gfar_write(&regs->imask, IMASK_DEFAULT);
-
-               /* If we are coalescing interrupts, update the timer
-                * Otherwise, clear it
-                */
-               gfar_configure_coalescing(priv, gfargrp->rx_bit_map,
-                                         gfargrp->tx_bit_map);
+               spin_lock_irq(&gfargrp->grplock);
+               imask = gfar_read(&regs->imask);
+               imask |= IMASK_RX_DEFAULT;
+               gfar_write(&regs->imask, imask);
+               spin_unlock_irq(&gfargrp->grplock);
        }
 
        return work_done;
 }
 
+static int gfar_poll_tx(struct napi_struct *napi, int budget)
+{
+       struct gfar_priv_grp *gfargrp =
+               container_of(napi, struct gfar_priv_grp, napi_tx);
+       struct gfar_private *priv = gfargrp->priv;
+       struct gfar __iomem *regs = gfargrp->regs;
+       struct gfar_priv_tx_q *tx_queue = NULL;
+       int has_tx_work = 0;
+       int i;
+
+       /* Clear IEVENT, so interrupts aren't called again
+        * because of the packets that have already arrived
+        */
+       gfar_write(&regs->ievent, IEVENT_TX_MASK);
+
+       for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) {
+               tx_queue = priv->tx_queue[i];
+               /* run Tx cleanup to completion */
+               if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) {
+                       gfar_clean_tx_ring(tx_queue);
+                       has_tx_work = 1;
+               }
+       }
+
+       if (!has_tx_work) {
+               u32 imask;
+               napi_complete(napi);
+
+               spin_lock_irq(&gfargrp->grplock);
+               imask = gfar_read(&regs->imask);
+               imask |= IMASK_TX_DEFAULT;
+               gfar_write(&regs->imask, imask);
+               spin_unlock_irq(&gfargrp->grplock);
+       }
+
+       return 0;
+}
+
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /* Polling 'interrupt' - used by things like netconsole to send skbs
  * without having to re-enable interrupts. It's not called while
@@ -3101,12 +3121,11 @@ static void adjust_link(struct net_device *dev)
 {
        struct gfar_private *priv = netdev_priv(dev);
        struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned long flags;
        struct phy_device *phydev = priv->phydev;
        int new_state = 0;
 
-       local_irq_save(flags);
-       lock_tx_qs(priv);
+       if (test_bit(GFAR_RESETTING, &priv->state))
+               return;
 
        if (phydev->link) {
                u32 tempval1 = gfar_read(&regs->maccfg1);
@@ -3178,8 +3197,6 @@ static void adjust_link(struct net_device *dev)
 
        if (new_state && netif_msg_link(priv))
                phy_print_status(phydev);
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
 }
 
 /* Update the hash table based on the current list of multicast
index 52bb2b0195cccf3e2749e39d37700bf0186aba4d..84632c569f2c3ba43225c2a9a4f773dd24ea1580 100644 (file)
@@ -9,7 +9,7 @@
  * Maintainer: Kumar Gala
  * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
  *
- * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc.
+ * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc.
  *
  * 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
@@ -377,8 +377,11 @@ extern const char gfar_driver_version[];
                IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
                IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
                | IMASK_PERR)
-#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \
-                          & IMASK_DEFAULT)
+#define IMASK_RX_DEFAULT (IMASK_RXFEN0 | IMASK_BSY)
+#define IMASK_TX_DEFAULT (IMASK_TXFEN | IMASK_TXBEN)
+
+#define IMASK_RX_DISABLED ((~(IMASK_RX_DEFAULT)) & IMASK_DEFAULT)
+#define IMASK_TX_DISABLED ((~(IMASK_TX_DEFAULT)) & IMASK_DEFAULT)
 
 /* Fifo management */
 #define FIFO_TX_THR_MASK       0x01ff
@@ -409,7 +412,9 @@ extern const char gfar_driver_version[];
 
 /* This default RIR value directly corresponds
  * to the 3-bit hash value generated */
-#define DEFAULT_RIR0   0x05397700
+#define DEFAULT_8RXQ_RIR0      0x05397700
+/* Map even hash values to Q0, and odd ones to Q1 */
+#define DEFAULT_2RXQ_RIR0      0x04104100
 
 /* RQFCR register bits */
 #define RQFCR_GPI              0x80000000
@@ -880,7 +885,6 @@ struct gfar {
 #define FSL_GIANFAR_DEV_HAS_CSUM               0x00000010
 #define FSL_GIANFAR_DEV_HAS_VLAN               0x00000020
 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH      0x00000040
-#define FSL_GIANFAR_DEV_HAS_PADDING            0x00000080
 #define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET       0x00000100
 #define FSL_GIANFAR_DEV_HAS_BD_STASHING                0x00000200
 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING       0x00000400
@@ -892,8 +896,8 @@ struct gfar {
 #define DEFAULT_MAPPING        0xFF
 #endif
 
-#define ISRG_SHIFT_TX  0x10
-#define ISRG_SHIFT_RX  0x18
+#define ISRG_RR0       0x80000000
+#define ISRG_TR0       0x00800000
 
 /* The same driver can operate in two modes */
 /* SQ_SG_MODE: Single Queue Single Group Mode
@@ -905,6 +909,22 @@ enum {
        MQ_MG_MODE
 };
 
+/* GFAR_SQ_POLLING: Single Queue NAPI polling mode
+ *     The driver supports a single pair of RX/Tx queues
+ *     per interrupt group (Rx/Tx int line). MQ_MG mode
+ *     devices have 2 interrupt groups, so the device will
+ *     have a total of 2 Tx and 2 Rx queues in this case.
+ * GFAR_MQ_POLLING: Multi Queue NAPI polling mode
+ *     The driver supports all the 8 Rx and Tx HW queues
+ *     each queue mapped by the Device Tree to one of
+ *     the 2 interrupt groups. This mode implies significant
+ *     processing overhead (CPU and controller level).
+ */
+enum gfar_poll_mode {
+       GFAR_SQ_POLLING = 0,
+       GFAR_MQ_POLLING
+};
+
 /*
  * Per TX queue stats
  */
@@ -966,7 +986,6 @@ struct rx_q_stats {
 
 /**
  *     struct gfar_priv_rx_q - per rx queue structure
- *     @rxlock: per queue rx spin lock
  *     @rx_skbuff: skb pointers
  *     @skb_currx: currently use skb pointer
  *     @rx_bd_base: First rx buffer descriptor
@@ -979,8 +998,7 @@ struct rx_q_stats {
  */
 
 struct gfar_priv_rx_q {
-       spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES)));
-       struct  sk_buff ** rx_skbuff;
+       struct  sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES);
        dma_addr_t rx_bd_dma_base;
        struct  rxbd8 *rx_bd_base;
        struct  rxbd8 *cur_rx;
@@ -1016,17 +1034,20 @@ struct gfar_irqinfo {
  */
 
 struct gfar_priv_grp {
-       spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES)));
-       struct  napi_struct napi;
-       struct gfar_private *priv;
+       spinlock_t grplock __aligned(SMP_CACHE_BYTES);
+       struct  napi_struct napi_rx;
+       struct  napi_struct napi_tx;
        struct gfar __iomem *regs;
-       unsigned int rstat;
-       unsigned long num_rx_queues;
-       unsigned long rx_bit_map;
-       /* cacheline 3 */
+       struct gfar_priv_tx_q *tx_queue;
+       struct gfar_priv_rx_q *rx_queue;
        unsigned int tstat;
+       unsigned int rstat;
+
+       struct gfar_private *priv;
        unsigned long num_tx_queues;
        unsigned long tx_bit_map;
+       unsigned long num_rx_queues;
+       unsigned long rx_bit_map;
 
        struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS];
 };
@@ -1041,6 +1062,11 @@ enum gfar_errata {
        GFAR_ERRATA_12          = 0x08, /* a.k.a errata eTSEC49 */
 };
 
+enum gfar_dev_state {
+       GFAR_DOWN = 1,
+       GFAR_RESETTING
+};
+
 /* Struct stolen almost completely (and shamelessly) from the FCC enet source
  * (Ok, that's not so true anymore, but there is a family resemblance)
  * The GFAR buffer descriptors track the ring buffers.  The rx_bd_base
@@ -1051,8 +1077,6 @@ enum gfar_errata {
  * the buffer descriptor determines the actual condition.
  */
 struct gfar_private {
-       unsigned int num_rx_queues;
-
        struct device *dev;
        struct net_device *ndev;
        enum gfar_errata errata;
@@ -1060,6 +1084,7 @@ struct gfar_private {
 
        u16 uses_rxfcb;
        u16 padding;
+       u32 device_flags;
 
        /* HW time stamping enabled flag */
        int hwts_rx_en;
@@ -1069,10 +1094,12 @@ struct gfar_private {
        struct gfar_priv_rx_q *rx_queue[MAX_RX_QS];
        struct gfar_priv_grp gfargrp[MAXGROUPS];
 
-       u32 device_flags;
+       unsigned long state;
 
-       unsigned int mode;
+       unsigned short mode;
+       unsigned short poll_mode;
        unsigned int num_tx_queues;
+       unsigned int num_rx_queues;
        unsigned int num_grps;
 
        /* Network Statistics */
@@ -1113,6 +1140,9 @@ struct gfar_private {
        unsigned int total_tx_ring_size;
        unsigned int total_rx_ring_size;
 
+       u32 rqueue;
+       u32 tqueue;
+
        /* RX per device parameters */
        unsigned int rx_stash_size;
        unsigned int rx_stash_index;
@@ -1127,11 +1157,6 @@ struct gfar_private {
        u32 __iomem *hash_regs[16];
        int hash_width;
 
-       /* global parameters */
-       unsigned int fifo_threshold;
-       unsigned int fifo_starve;
-       unsigned int fifo_starve_off;
-
        /*Filer table*/
        unsigned int ftp_rqfpr[MAX_FILER_IDX + 1];
        unsigned int ftp_rqfcr[MAX_FILER_IDX + 1];
@@ -1176,21 +1201,42 @@ static inline void gfar_read_filer(struct gfar_private *priv,
        *fpr = gfar_read(&regs->rqfpr);
 }
 
-void lock_rx_qs(struct gfar_private *priv);
-void lock_tx_qs(struct gfar_private *priv);
-void unlock_rx_qs(struct gfar_private *priv);
-void unlock_tx_qs(struct gfar_private *priv);
+static inline void gfar_write_isrg(struct gfar_private *priv)
+{
+       struct gfar __iomem *regs = priv->gfargrp[0].regs;
+       u32 __iomem *baddr = &regs->isrg0;
+       u32 isrg = 0;
+       int grp_idx, i;
+
+       for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) {
+               struct gfar_priv_grp *grp = &priv->gfargrp[grp_idx];
+
+               for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) {
+                       isrg |= (ISRG_RR0 >> i);
+               }
+
+               for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) {
+                       isrg |= (ISRG_TR0 >> i);
+               }
+
+               gfar_write(baddr, isrg);
+
+               baddr++;
+               isrg = 0;
+       }
+}
+
 irqreturn_t gfar_receive(int irq, void *dev_id);
 int startup_gfar(struct net_device *dev);
 void stop_gfar(struct net_device *dev);
-void gfar_halt(struct net_device *dev);
+void reset_gfar(struct net_device *dev);
+void gfar_mac_reset(struct gfar_private *priv);
+void gfar_halt(struct gfar_private *priv);
+void gfar_start(struct gfar_private *priv);
 void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, int enable,
                   u32 regnum, u32 read);
 void gfar_configure_coalescing_all(struct gfar_private *priv);
-void gfar_init_sysfs(struct net_device *dev);
 int gfar_set_features(struct net_device *dev, netdev_features_t features);
-void gfar_check_rx_parser_mode(struct gfar_private *priv);
-void gfar_vlan_mode(struct net_device *dev, netdev_features_t features);
 
 extern const struct ethtool_ops gfar_ethtool_ops;
 
index 63d234419cc1febaab1a9f143a607c19790289a6..891dbee6e6c14d2394cc2dff00092f448faf3dc2 100644 (file)
 
 #include "gianfar.h"
 
-extern void gfar_start(struct net_device *dev);
-extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue,
-                             int rx_work_limit);
-
 #define GFAR_MAX_COAL_USECS 0xffff
 #define GFAR_MAX_COAL_FRAMES 0xff
 static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
@@ -364,25 +360,11 @@ static int gfar_scoalesce(struct net_device *dev,
                          struct ethtool_coalesce *cvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       int i = 0;
+       int i, err = 0;
 
        if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
                return -EOPNOTSUPP;
 
-       /* Set up rx coalescing */
-       /* As of now, we will enable/disable coalescing for all
-        * queues together in case of eTSEC2, this will be modified
-        * along with the ethtool interface
-        */
-       if ((cvals->rx_coalesce_usecs == 0) ||
-           (cvals->rx_max_coalesced_frames == 0)) {
-               for (i = 0; i < priv->num_rx_queues; i++)
-                       priv->rx_queue[i]->rxcoalescing = 0;
-       } else {
-               for (i = 0; i < priv->num_rx_queues; i++)
-                       priv->rx_queue[i]->rxcoalescing = 1;
-       }
-
        if (NULL == priv->phydev)
                return -ENODEV;
 
@@ -399,6 +381,32 @@ static int gfar_scoalesce(struct net_device *dev,
                return -EINVAL;
        }
 
+       /* Check the bounds of the values */
+       if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
+               netdev_info(dev, "Coalescing is limited to %d microseconds\n",
+                           GFAR_MAX_COAL_USECS);
+               return -EINVAL;
+       }
+
+       if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
+               netdev_info(dev, "Coalescing is limited to %d frames\n",
+                           GFAR_MAX_COAL_FRAMES);
+               return -EINVAL;
+       }
+
+       while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+               cpu_relax();
+
+       /* Set up rx coalescing */
+       if ((cvals->rx_coalesce_usecs == 0) ||
+           (cvals->rx_max_coalesced_frames == 0)) {
+               for (i = 0; i < priv->num_rx_queues; i++)
+                       priv->rx_queue[i]->rxcoalescing = 0;
+       } else {
+               for (i = 0; i < priv->num_rx_queues; i++)
+                       priv->rx_queue[i]->rxcoalescing = 1;
+       }
+
        for (i = 0; i < priv->num_rx_queues; i++) {
                priv->rx_queue[i]->rxic = mk_ic_value(
                        cvals->rx_max_coalesced_frames,
@@ -415,28 +423,22 @@ static int gfar_scoalesce(struct net_device *dev,
                        priv->tx_queue[i]->txcoalescing = 1;
        }
 
-       /* Check the bounds of the values */
-       if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) {
-               netdev_info(dev, "Coalescing is limited to %d microseconds\n",
-                           GFAR_MAX_COAL_USECS);
-               return -EINVAL;
-       }
-
-       if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) {
-               netdev_info(dev, "Coalescing is limited to %d frames\n",
-                           GFAR_MAX_COAL_FRAMES);
-               return -EINVAL;
-       }
-
        for (i = 0; i < priv->num_tx_queues; i++) {
                priv->tx_queue[i]->txic = mk_ic_value(
                        cvals->tx_max_coalesced_frames,
                        gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs));
        }
 
-       gfar_configure_coalescing_all(priv);
+       if (dev->flags & IFF_UP) {
+               stop_gfar(dev);
+               err = startup_gfar(dev);
+       } else {
+               gfar_mac_reset(priv);
+       }
+
+       clear_bit_unlock(GFAR_RESETTING, &priv->state);
 
-       return 0;
+       return err;
 }
 
 /* Fills in rvals with the current ring parameters.  Currently,
@@ -467,15 +469,13 @@ static void gfar_gringparam(struct net_device *dev,
 }
 
 /* Change the current ring parameters, stopping the controller if
- * necessary so that we don't mess things up while we're in
- * motion.  We wait for the ring to be clean before reallocating
- * the rings.
+ * necessary so that we don't mess things up while we're in motion.
  */
 static int gfar_sringparam(struct net_device *dev,
                           struct ethtool_ringparam *rvals)
 {
        struct gfar_private *priv = netdev_priv(dev);
-       int err = 0, i = 0;
+       int err = 0, i;
 
        if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE)
                return -EINVAL;
@@ -493,44 +493,25 @@ static int gfar_sringparam(struct net_device *dev,
                return -EINVAL;
        }
 
+       while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+               cpu_relax();
 
-       if (dev->flags & IFF_UP) {
-               unsigned long flags;
-
-               /* Halt TX and RX, and process the frames which
-                * have already been received
-                */
-               local_irq_save(flags);
-               lock_tx_qs(priv);
-               lock_rx_qs(priv);
-
-               gfar_halt(dev);
-
-               unlock_rx_qs(priv);
-               unlock_tx_qs(priv);
-               local_irq_restore(flags);
-
-               for (i = 0; i < priv->num_rx_queues; i++)
-                       gfar_clean_rx_ring(priv->rx_queue[i],
-                                          priv->rx_queue[i]->rx_ring_size);
-
-               /* Now we take down the rings to rebuild them */
+       if (dev->flags & IFF_UP)
                stop_gfar(dev);
-       }
 
-       /* Change the size */
-       for (i = 0; i < priv->num_rx_queues; i++) {
+       /* Change the sizes */
+       for (i = 0; i < priv->num_rx_queues; i++)
                priv->rx_queue[i]->rx_ring_size = rvals->rx_pending;
+
+       for (i = 0; i < priv->num_tx_queues; i++)
                priv->tx_queue[i]->tx_ring_size = rvals->tx_pending;
-               priv->tx_queue[i]->num_txbdfree =
-                       priv->tx_queue[i]->tx_ring_size;
-       }
 
        /* Rebuild the rings with the new size */
-       if (dev->flags & IFF_UP) {
+       if (dev->flags & IFF_UP)
                err = startup_gfar(dev);
-               netif_tx_wake_all_queues(dev);
-       }
+
+       clear_bit_unlock(GFAR_RESETTING, &priv->state);
+
        return err;
 }
 
@@ -608,43 +589,29 @@ static int gfar_spauseparam(struct net_device *dev,
 
 int gfar_set_features(struct net_device *dev, netdev_features_t features)
 {
-       struct gfar_private *priv = netdev_priv(dev);
-       unsigned long flags;
-       int err = 0, i = 0;
        netdev_features_t changed = dev->features ^ features;
+       struct gfar_private *priv = netdev_priv(dev);
+       int err = 0;
 
-       if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX))
-               gfar_vlan_mode(dev, features);
-
-       if (!(changed & NETIF_F_RXCSUM))
+       if (!(changed & (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+                        NETIF_F_RXCSUM)))
                return 0;
 
-       if (dev->flags & IFF_UP) {
-               /* Halt TX and RX, and process the frames which
-                * have already been received
-                */
-               local_irq_save(flags);
-               lock_tx_qs(priv);
-               lock_rx_qs(priv);
-
-               gfar_halt(dev);
+       while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state))
+               cpu_relax();
 
-               unlock_tx_qs(priv);
-               unlock_rx_qs(priv);
-               local_irq_restore(flags);
-
-               for (i = 0; i < priv->num_rx_queues; i++)
-                       gfar_clean_rx_ring(priv->rx_queue[i],
-                                          priv->rx_queue[i]->rx_ring_size);
+       dev->features = features;
 
+       if (dev->flags & IFF_UP) {
                /* Now we take down the rings to rebuild them */
                stop_gfar(dev);
-
-               dev->features = features;
-
                err = startup_gfar(dev);
-               netif_tx_wake_all_queues(dev);
+       } else {
+               gfar_mac_reset(priv);
        }
+
+       clear_bit_unlock(GFAR_RESETTING, &priv->state);
+
        return err;
 }
 
@@ -1610,9 +1577,6 @@ static int gfar_write_filer_table(struct gfar_private *priv,
        if (tab->index > MAX_FILER_IDX - 1)
                return -EBUSY;
 
-       /* Avoid inconsistent filer table to be processed */
-       lock_rx_qs(priv);
-
        /* Fill regular entries */
        for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl);
             i++)
@@ -1625,8 +1589,6 @@ static int gfar_write_filer_table(struct gfar_private *priv,
         */
        gfar_write_filer(priv, i, 0x20, 0x0);
 
-       unlock_rx_qs(priv);
-
        return 0;
 }
 
@@ -1831,6 +1793,9 @@ static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
        struct gfar_private *priv = netdev_priv(dev);
        int ret = 0;
 
+       if (test_bit(GFAR_RESETTING, &priv->state))
+               return -EBUSY;
+
        mutex_lock(&priv->rx_queue_access);
 
        switch (cmd->cmd) {
index abc28da2704210e6a7143bc140b22a5c500d33ce..bb568006f37df605e808d1d6c7195a09b6e8d48f 100644 (file)
@@ -414,6 +414,7 @@ static struct ptp_clock_info ptp_gianfar_caps = {
        .n_alarm        = 0,
        .n_ext_ts       = N_EXT_TS,
        .n_per_out      = 0,
+       .n_pins         = 0,
        .pps            = 1,
        .adjfreq        = ptp_gianfar_adjfreq,
        .adjtime        = ptp_gianfar_adjtime,
diff --git a/drivers/net/ethernet/freescale/gianfar_sysfs.c b/drivers/net/ethernet/freescale/gianfar_sysfs.c
deleted file mode 100644 (file)
index e02dd13..0000000
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * drivers/net/ethernet/freescale/gianfar_sysfs.c
- *
- * Gianfar Ethernet Driver
- * This driver is designed for the non-CPM ethernet controllers
- * on the 85xx and 83xx family of integrated processors
- * Based on 8260_io/fcc_enet.c
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala (galak@kernel.crashing.org)
- * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
- *
- * Copyright 2002-2009 Freescale Semiconductor, Inc.
- *
- * 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.
- *
- * Sysfs file creation and management
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#include <asm/uaccess.h>
-#include <linux/module.h>
-
-#include "gianfar.h"
-
-static ssize_t gfar_show_bd_stash(struct device *dev,
-                                 struct device_attribute *attr, char *buf)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
-       return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off");
-}
-
-static ssize_t gfar_set_bd_stash(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t count)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       int new_setting = 0;
-       u32 temp;
-       unsigned long flags;
-
-       if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING))
-               return count;
-
-
-       /* Find out the new setting */
-       if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
-               new_setting = 1;
-       else if (!strncmp("off", buf, count - 1) ||
-                !strncmp("0", buf, count - 1))
-               new_setting = 0;
-       else
-               return count;
-
-
-       local_irq_save(flags);
-       lock_rx_qs(priv);
-
-       /* Set the new stashing value */
-       priv->bd_stash_en = new_setting;
-
-       temp = gfar_read(&regs->attr);
-
-       if (new_setting)
-               temp |= ATTR_BDSTASH;
-       else
-               temp &= ~(ATTR_BDSTASH);
-
-       gfar_write(&regs->attr, temp);
-
-       unlock_rx_qs(priv);
-       local_irq_restore(flags);
-
-       return count;
-}
-
-static DEVICE_ATTR(bd_stash, 0644, gfar_show_bd_stash, gfar_set_bd_stash);
-
-static ssize_t gfar_show_rx_stash_size(struct device *dev,
-                                      struct device_attribute *attr, char *buf)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
-       return sprintf(buf, "%d\n", priv->rx_stash_size);
-}
-
-static ssize_t gfar_set_rx_stash_size(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t count)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned int length = simple_strtoul(buf, NULL, 0);
-       u32 temp;
-       unsigned long flags;
-
-       if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
-               return count;
-
-       local_irq_save(flags);
-       lock_rx_qs(priv);
-
-       if (length > priv->rx_buffer_size)
-               goto out;
-
-       if (length == priv->rx_stash_size)
-               goto out;
-
-       priv->rx_stash_size = length;
-
-       temp = gfar_read(&regs->attreli);
-       temp &= ~ATTRELI_EL_MASK;
-       temp |= ATTRELI_EL(length);
-       gfar_write(&regs->attreli, temp);
-
-       /* Turn stashing on/off as appropriate */
-       temp = gfar_read(&regs->attr);
-
-       if (length)
-               temp |= ATTR_BUFSTASH;
-       else
-               temp &= ~(ATTR_BUFSTASH);
-
-       gfar_write(&regs->attr, temp);
-
-out:
-       unlock_rx_qs(priv);
-       local_irq_restore(flags);
-
-       return count;
-}
-
-static DEVICE_ATTR(rx_stash_size, 0644, gfar_show_rx_stash_size,
-                  gfar_set_rx_stash_size);
-
-/* Stashing will only be enabled when rx_stash_size != 0 */
-static ssize_t gfar_show_rx_stash_index(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
-       return sprintf(buf, "%d\n", priv->rx_stash_index);
-}
-
-static ssize_t gfar_set_rx_stash_index(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned short index = simple_strtoul(buf, NULL, 0);
-       u32 temp;
-       unsigned long flags;
-
-       if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING))
-               return count;
-
-       local_irq_save(flags);
-       lock_rx_qs(priv);
-
-       if (index > priv->rx_stash_size)
-               goto out;
-
-       if (index == priv->rx_stash_index)
-               goto out;
-
-       priv->rx_stash_index = index;
-
-       temp = gfar_read(&regs->attreli);
-       temp &= ~ATTRELI_EI_MASK;
-       temp |= ATTRELI_EI(index);
-       gfar_write(&regs->attreli, temp);
-
-out:
-       unlock_rx_qs(priv);
-       local_irq_restore(flags);
-
-       return count;
-}
-
-static DEVICE_ATTR(rx_stash_index, 0644, gfar_show_rx_stash_index,
-                  gfar_set_rx_stash_index);
-
-static ssize_t gfar_show_fifo_threshold(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
-       return sprintf(buf, "%d\n", priv->fifo_threshold);
-}
-
-static ssize_t gfar_set_fifo_threshold(struct device *dev,
-                                      struct device_attribute *attr,
-                                      const char *buf, size_t count)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned int length = simple_strtoul(buf, NULL, 0);
-       u32 temp;
-       unsigned long flags;
-
-       if (length > GFAR_MAX_FIFO_THRESHOLD)
-               return count;
-
-       local_irq_save(flags);
-       lock_tx_qs(priv);
-
-       priv->fifo_threshold = length;
-
-       temp = gfar_read(&regs->fifo_tx_thr);
-       temp &= ~FIFO_TX_THR_MASK;
-       temp |= length;
-       gfar_write(&regs->fifo_tx_thr, temp);
-
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
-
-       return count;
-}
-
-static DEVICE_ATTR(fifo_threshold, 0644, gfar_show_fifo_threshold,
-                  gfar_set_fifo_threshold);
-
-static ssize_t gfar_show_fifo_starve(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
-       return sprintf(buf, "%d\n", priv->fifo_starve);
-}
-
-static ssize_t gfar_set_fifo_starve(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned int num = simple_strtoul(buf, NULL, 0);
-       u32 temp;
-       unsigned long flags;
-
-       if (num > GFAR_MAX_FIFO_STARVE)
-               return count;
-
-       local_irq_save(flags);
-       lock_tx_qs(priv);
-
-       priv->fifo_starve = num;
-
-       temp = gfar_read(&regs->fifo_tx_starve);
-       temp &= ~FIFO_TX_STARVE_MASK;
-       temp |= num;
-       gfar_write(&regs->fifo_tx_starve, temp);
-
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
-
-       return count;
-}
-
-static DEVICE_ATTR(fifo_starve, 0644, gfar_show_fifo_starve,
-                  gfar_set_fifo_starve);
-
-static ssize_t gfar_show_fifo_starve_off(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-
-       return sprintf(buf, "%d\n", priv->fifo_starve_off);
-}
-
-static ssize_t gfar_set_fifo_starve_off(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count)
-{
-       struct gfar_private *priv = netdev_priv(to_net_dev(dev));
-       struct gfar __iomem *regs = priv->gfargrp[0].regs;
-       unsigned int num = simple_strtoul(buf, NULL, 0);
-       u32 temp;
-       unsigned long flags;
-
-       if (num > GFAR_MAX_FIFO_STARVE_OFF)
-               return count;
-
-       local_irq_save(flags);
-       lock_tx_qs(priv);
-
-       priv->fifo_starve_off = num;
-
-       temp = gfar_read(&regs->fifo_tx_starve_shutoff);
-       temp &= ~FIFO_TX_STARVE_OFF_MASK;
-       temp |= num;
-       gfar_write(&regs->fifo_tx_starve_shutoff, temp);
-
-       unlock_tx_qs(priv);
-       local_irq_restore(flags);
-
-       return count;
-}
-
-static DEVICE_ATTR(fifo_starve_off, 0644, gfar_show_fifo_starve_off,
-                  gfar_set_fifo_starve_off);
-
-void gfar_init_sysfs(struct net_device *dev)
-{
-       struct gfar_private *priv = netdev_priv(dev);
-       int rc;
-
-       /* Initialize the default values */
-       priv->fifo_threshold = DEFAULT_FIFO_TX_THR;
-       priv->fifo_starve = DEFAULT_FIFO_TX_STARVE;
-       priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF;
-
-       /* Create our sysfs files */
-       rc = device_create_file(&dev->dev, &dev_attr_bd_stash);
-       rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_size);
-       rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_index);
-       rc |= device_create_file(&dev->dev, &dev_attr_fifo_threshold);
-       rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve);
-       rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off);
-       if (rc)
-               dev_err(&dev->dev, "Error creating gianfar sysfs files\n");
-}
index 72291a8904a90118f88913af0e3c453d9ce3ffff..c8299c31b21f9f5c52dc380f9b867597c1b8bcdf 100644 (file)
@@ -3261,7 +3261,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
 
                dev->stats.tx_packets++;
 
-               dev_kfree_skb(skb);
+               dev_consume_skb_any(skb);
 
                ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
                ugeth->skb_dirtytx[txQ] =
index 17fca323c1431047046b03511aac4b52aaf91135..c984998b34a02dfe4095be9479a71eb0326a1fbb 100644 (file)
@@ -993,7 +993,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                       dev->name));
                dev->stats.tx_dropped++;
 
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        } else {
                if (++lp->next_tx_cmd == TX_RING_SIZE)
                        lp->next_tx_cmd = 0;
index 7628e0fd84554fd56eca5f4181f2ff31c85eca0d..538903bf13bce736161a96af324a2b9ebc9aecd9 100644 (file)
@@ -490,7 +490,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
                skb_arr[index] = skb;
                tmp_addr = ehea_map_vaddr(skb->data);
                if (tmp_addr == -1) {
-                       dev_kfree_skb(skb);
+                       dev_consume_skb_any(skb);
                        q_skba->os_skbs = fill_wqes - i;
                        ret = 0;
                        break;
@@ -856,7 +856,7 @@ static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
 
                        index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
                        skb = pr->sq_skba.arr[index];
-                       dev_kfree_skb(skb);
+                       dev_consume_skb_any(skb);
                        pr->sq_skba.arr[index] = NULL;
                }
 
@@ -2044,7 +2044,7 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
                skb_copy_bits(skb, 0, imm_data, skb->len);
 
        swqe->immediate_data_length = skb->len;
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 }
 
 static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
index 4be9715904616b3f9c1ff2a3bc38d55b58135e58..c9127562bd22cb51114249d35264bcbb679dcc3d 100644 (file)
@@ -522,10 +522,21 @@ retry:
        return rc;
 }
 
+static u64 ibmveth_encode_mac_addr(u8 *mac)
+{
+       int i;
+       u64 encoded = 0;
+
+       for (i = 0; i < ETH_ALEN; i++)
+               encoded = (encoded << 8) | mac[i];
+
+       return encoded;
+}
+
 static int ibmveth_open(struct net_device *netdev)
 {
        struct ibmveth_adapter *adapter = netdev_priv(netdev);
-       u64 mac_address = 0;
+       u64 mac_address;
        int rxq_entries = 1;
        unsigned long lpar_rc;
        int rc;
@@ -579,8 +590,7 @@ static int ibmveth_open(struct net_device *netdev)
        adapter->rx_queue.num_slots = rxq_entries;
        adapter->rx_queue.toggle = 1;
 
-       memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
-       mac_address = mac_address >> 16;
+       mac_address = ibmveth_encode_mac_addr(netdev->dev_addr);
 
        rxq_desc.fields.flags_len = IBMVETH_BUF_VALID |
                                        adapter->rx_queue.queue_len;
@@ -1034,7 +1044,7 @@ retry_bounce:
                               DMA_TO_DEVICE);
 
 out:
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
        return NETDEV_TX_OK;
 
 map_failed_frags:
@@ -1062,7 +1072,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)
        unsigned long lpar_rc;
 
 restart_poll:
-       do {
+       while (frames_processed < budget) {
                if (!ibmveth_rxq_pending_buffer(adapter))
                        break;
 
@@ -1111,7 +1121,7 @@ restart_poll:
                        netdev->stats.rx_bytes += length;
                        frames_processed++;
                }
-       } while (frames_processed < budget);
+       }
 
        ibmveth_replenish_task(adapter);
 
@@ -1183,8 +1193,8 @@ static void ibmveth_set_multicast_list(struct net_device *netdev)
                /* add the addresses to the filter table */
                netdev_for_each_mc_addr(ha, netdev) {
                        /* add the multicast address to the filter table */
-                       unsigned long mcast_addr = 0;
-                       memcpy(((char *)&mcast_addr)+2, ha->addr, ETH_ALEN);
+                       u64 mcast_addr;
+                       mcast_addr = ibmveth_encode_mac_addr(ha->addr);
                        lpar_rc = h_multicast_ctrl(adapter->vdev->unit_address,
                                                   IbmVethMcastAddFilter,
                                                   mcast_addr);
@@ -1372,9 +1382,6 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
 
-       adapter->mac_addr = 0;
-       memcpy(&adapter->mac_addr, mac_addr_p, ETH_ALEN);
-
        netdev->irq = dev->irq;
        netdev->netdev_ops = &ibmveth_netdev_ops;
        netdev->ethtool_ops = &netdev_ethtool_ops;
@@ -1383,7 +1390,7 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        netdev->features |= netdev->hw_features;
 
-       memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
+       memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);
 
        for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                struct kobject *kobj = &adapter->rx_buff_pool[i].kobj;
index 451ba7949e152a66ee87e661e90722496792dfb8..1f37499d43981d260c61cdc1c089d7328a7942c9 100644 (file)
@@ -138,7 +138,6 @@ struct ibmveth_adapter {
     struct napi_struct napi;
     struct net_device_stats stats;
     unsigned int mcastFilterSize;
-    unsigned long mac_addr;
     void * buffer_list_addr;
     void * filter_list_addr;
     dma_addr_t buffer_list_dma;
index cbaba4442d4b226d18691059a4e122029040ff0a..b56461ce674c7832152cdab4c0b4c3b27789d9a4 100644 (file)
@@ -1778,9 +1778,9 @@ static int e100_xmit_prepare(struct nic *nic, struct cb *cb,
         * testing, ie sending frames with bad CRC.
         */
        if (unlikely(skb->no_fcs))
-               cb->command |= __constant_cpu_to_le16(cb_tx_nc);
+               cb->command |= cpu_to_le16(cb_tx_nc);
        else
-               cb->command &= ~__constant_cpu_to_le16(cb_tx_nc);
+               cb->command &= ~cpu_to_le16(cb_tx_nc);
 
        /* interrupt every 16 packets regardless of delay */
        if ((nic->cbs_avail & ~15) == nic->cbs_avail)
@@ -3034,7 +3034,7 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake)
                *enable_wake = false;
        }
 
-       pci_disable_device(pdev);
+       pci_clear_master(pdev);
 }
 
 static int __e100_power_off(struct pci_dev *pdev, bool wake)
index ff2d806eaef71bc2a7a861a8971c228cd6856e2a..a5f6b11d6992e63aa9af8da9f52540697455b2d1 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* 80003ES2LAN Gigabit Ethernet Controller (Copper)
  * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
index 90d363b2d2802c238cda0b1e792a21ac5afb2562..535a9430976df7653671e23d62adc1140973579e 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_80003ES2LAN_H_
 #define _E1000E_80003ES2LAN_H_
index 8fed74e3fa53da73ff781a215ac26714911a015f..e0aa7f1efb08ceb50d9049128dcbdb66f442b17d 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* 82571EB Gigabit Ethernet Controller
  * 82571EB Gigabit Ethernet Controller (Copper)
index 08e24dc3dc0e9d49c7742fed7b829826e2cea095..2e758f796d6099bc3dfb05107ea3a6ebc81dec09 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_82571_H_
 #define _E1000E_82571_H_
index c2dcfcc10857fc17608194c0a4c09140f6606143..106de493373ce6c73e85e7e2be6f6e8c3e61df0c 100644 (file)
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel PRO/1000 Linux driver
-# Copyright(c) 1999 - 2013 Intel Corporation.
+# Copyright(c) 1999 - 2014 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -12,9 +12,8 @@
 # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 # more details.
 #
-# You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # The full GNU General Public License is included in this distribution in
 # the file called "COPYING".
index 351c94a0cf74944b95c278c69709257216af64ef..d18e89212575626b880a173f08af119be2bdd20a 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000_DEFINES_H_
 #define _E1000_DEFINES_H_
 
 /* Definitions for power management and wakeup registers */
 /* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_APME         0x00000001      /* APM Enable */
+#define E1000_WUC_PME_EN       0x00000002      /* PME Enable */
+#define E1000_WUC_PME_STATUS   0x00000004      /* PME Status */
+#define E1000_WUC_APMPME       0x00000008      /* Assert PME on APM Wakeup */
+#define E1000_WUC_PHY_WAKE     0x00000100      /* if PHY supports wakeup */
 
 /* Wake Up Filter Control */
 #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
index 0150f7fc893d4ae6985096f17e5a4678f39fc3b3..1471c5464a89e72d87aa571d4a1b15d791a3f015 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* Linux PRO/1000 Ethernet Driver main header file */
 
@@ -269,6 +262,7 @@ struct e1000_adapter {
        u32 tx_head_addr;
        u32 tx_fifo_size;
        u32 tx_dma_failed;
+       u32 tx_hwtstamp_timeouts;
 
        /* Rx */
        bool (*clean_rx) (struct e1000_ring *ring, int *work_done,
@@ -333,7 +327,6 @@ struct e1000_adapter {
        struct work_struct update_phy_task;
        struct work_struct print_hang_task;
 
-       bool idle_check;
        int phy_hang_count;
 
        u16 tx_ring_count;
@@ -342,6 +335,7 @@ struct e1000_adapter {
        struct hwtstamp_config hwtstamp_config;
        struct delayed_work systim_overflow_work;
        struct sk_buff *tx_hwtstamp_skb;
+       unsigned long tx_hwtstamp_start;
        struct work_struct tx_hwtstamp_work;
        spinlock_t systim_lock; /* protects SYSTIML/H regsters */
        struct cyclecounter cc;
@@ -476,7 +470,7 @@ void e1000e_check_options(struct e1000_adapter *adapter);
 void e1000e_set_ethtool_ops(struct net_device *netdev);
 
 int e1000e_up(struct e1000_adapter *adapter);
-void e1000e_down(struct e1000_adapter *adapter);
+void e1000e_down(struct e1000_adapter *adapter, bool reset);
 void e1000e_reinit_locked(struct e1000_adapter *adapter);
 void e1000e_reset(struct e1000_adapter *adapter);
 void e1000e_power_up_phy(struct e1000_adapter *adapter);
index d14c8f53384cd415c3933015c02bf9d2a369ba11..cad250bc1b99fc81d51fb8956eee74c9acc3bc7e 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* ethtool support for e1000 */
 
@@ -111,6 +104,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = {
        E1000_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
        E1000_STAT("uncorr_ecc_errors", uncorr_errors),
        E1000_STAT("corr_ecc_errors", corr_errors),
+       E1000_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
 };
 
 #define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
@@ -332,7 +326,7 @@ static int e1000_set_settings(struct net_device *netdev,
 
        /* reset the link */
        if (netif_running(adapter->netdev)) {
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
                e1000e_up(adapter);
        } else {
                e1000e_reset(adapter);
@@ -380,7 +374,7 @@ static int e1000_set_pauseparam(struct net_device *netdev,
        if (adapter->fc_autoneg == AUTONEG_ENABLE) {
                hw->fc.requested_mode = e1000_fc_default;
                if (netif_running(adapter->netdev)) {
-                       e1000e_down(adapter);
+                       e1000e_down(adapter, true);
                        e1000e_up(adapter);
                } else {
                        e1000e_reset(adapter);
@@ -726,7 +720,7 @@ static int e1000_set_ringparam(struct net_device *netdev,
 
        pm_runtime_get_sync(netdev->dev.parent);
 
-       e1000e_down(adapter);
+       e1000e_down(adapter, true);
 
        /* We can't just free everything and then setup again, because the
         * ISRs in MSI-X mode get passed pointers to the Tx and Rx ring
@@ -924,15 +918,21 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                }
                if (mac->type == e1000_pch2lan) {
                        /* SHRAH[0,1,2] different than previous */
-                       if (i == 7)
+                       if (i == 1)
                                mask &= 0xFFF4FFFF;
                        /* SHRAH[3] different than SHRAH[0,1,2] */
-                       if (i == 10)
+                       if (i == 4)
                                mask |= (1 << 30);
+                       /* RAR[1-6] owned by management engine - skipping */
+                       if (i > 0)
+                               i += 6;
                }
 
                REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
                                       0xFFFFFFFF);
+               /* reset index to actual value */
+               if ((mac->type == e1000_pch2lan) && (i > 6))
+                       i -= 6;
        }
 
        for (i = 0; i < mac->mta_reg_count; i++)
index b7f38435d1fdb90336dd0c9511d78c7cd273e8d7..6b3de5f39a97862e2f5742b14a24530ba6ecc33f 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000_HW_H_
 #define _E1000_HW_H_
@@ -655,12 +648,20 @@ struct e1000_shadow_ram {
 
 #define E1000_ICH8_SHADOW_RAM_WORDS            2048
 
+/* I218 PHY Ultra Low Power (ULP) states */
+enum e1000_ulp_state {
+       e1000_ulp_state_unknown,
+       e1000_ulp_state_off,
+       e1000_ulp_state_on,
+};
+
 struct e1000_dev_spec_ich8lan {
        bool kmrn_lock_loss_workaround_enabled;
        struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
        bool nvm_k1_enabled;
        bool eee_disable;
        u16 eee_lp_ability;
+       enum e1000_ulp_state ulp_state;
 };
 
 struct e1000_hw {
index 42f0f6717511c21bb0f16edbeee050cc4878db96..9866f264f55e33a8e564757730ada0d6ab7c6a92 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* 82562G 10/100 Network Connection
  * 82562G-2 10/100 Network Connection
  * 82578DC Gigabit Network Connection
  * 82579LM Gigabit Network Connection
  * 82579V Gigabit Network Connection
+ * Ethernet Connection I217-LM
+ * Ethernet Connection I217-V
+ * Ethernet Connection I218-V
+ * Ethernet Connection I218-LM
+ * Ethernet Connection (2) I218-LM
+ * Ethernet Connection (2) I218-V
+ * Ethernet Connection (3) I218-LM
+ * Ethernet Connection (3) I218-V
  */
 
 #include "e1000.h"
@@ -142,7 +143,9 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
 static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
 static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
 static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force);
 static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
+static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -238,6 +241,47 @@ out:
        return true;
 }
 
+/**
+ *  e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
+ *  @hw: pointer to the HW structure
+ *
+ *  Toggling the LANPHYPC pin value fully power-cycles the PHY and is
+ *  used to reset the PHY to a quiescent state when necessary.
+ **/
+static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
+{
+       u32 mac_reg;
+
+       /* Set Phy Config Counter to 50msec */
+       mac_reg = er32(FEXTNVM3);
+       mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
+       mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
+       ew32(FEXTNVM3, mac_reg);
+
+       /* Toggle LANPHYPC Value bit */
+       mac_reg = er32(CTRL);
+       mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
+       mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
+       ew32(CTRL, mac_reg);
+       e1e_flush();
+       usleep_range(10, 20);
+       mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+       ew32(CTRL, mac_reg);
+       e1e_flush();
+
+       if (hw->mac.type < e1000_pch_lpt) {
+               msleep(50);
+       } else {
+               u16 count = 20;
+
+               do {
+                       usleep_range(5000, 10000);
+               } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--);
+
+               msleep(30);
+       }
+}
+
 /**
  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
  *  @hw: pointer to the HW structure
@@ -247,6 +291,7 @@ out:
  **/
 static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 {
+       struct e1000_adapter *adapter = hw->adapter;
        u32 mac_reg, fwsm = er32(FWSM);
        s32 ret_val;
 
@@ -255,6 +300,12 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
         */
        e1000_gate_hw_phy_config_ich8lan(hw, true);
 
+       /* It is not possible to be certain of the current state of ULP
+        * so forcibly disable it.
+        */
+       hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
+       e1000_disable_ulp_lpt_lp(hw, true);
+
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val) {
                e_dbg("Failed to initialize PHY flow\n");
@@ -300,33 +351,9 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                        break;
                }
 
-               e_dbg("Toggling LANPHYPC\n");
-
-               /* Set Phy Config Counter to 50msec */
-               mac_reg = er32(FEXTNVM3);
-               mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
-               mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
-               ew32(FEXTNVM3, mac_reg);
-
                /* Toggle LANPHYPC Value bit */
-               mac_reg = er32(CTRL);
-               mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
-               mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
-               ew32(CTRL, mac_reg);
-               e1e_flush();
-               usleep_range(10, 20);
-               mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
-               ew32(CTRL, mac_reg);
-               e1e_flush();
-               if (hw->mac.type < e1000_pch_lpt) {
-                       msleep(50);
-               } else {
-                       u16 count = 20;
-                       do {
-                               usleep_range(5000, 10000);
-                       } while (!(er32(CTRL_EXT) &
-                                  E1000_CTRL_EXT_LPCD) && count--);
-                       usleep_range(30000, 60000);
+               e1000_toggle_lanphypc_pch_lpt(hw);
+               if (hw->mac.type >= e1000_pch_lpt) {
                        if (e1000_phy_is_accessible_pchlan(hw))
                                break;
 
@@ -349,12 +376,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
 
        hw->phy.ops.release(hw);
        if (!ret_val) {
+
+               /* Check to see if able to reset PHY.  Print error if not */
+               if (hw->phy.ops.check_reset_block(hw)) {
+                       e_err("Reset blocked by ME\n");
+                       goto out;
+               }
+
                /* Reset the PHY before any access to it.  Doing so, ensures
                 * that the PHY is in a known good state before we read/write
                 * PHY registers.  The generic reset is sufficient here,
                 * because we haven't determined the PHY type yet.
                 */
                ret_val = e1000e_phy_hw_reset_generic(hw);
+               if (ret_val)
+                       goto out;
+
+               /* On a successful reset, possibly need to wait for the PHY
+                * to quiesce to an accessible state before returning control
+                * to the calling function.  If the PHY does not quiesce, then
+                * return E1000E_BLK_PHY_RESET, as this is the condition that
+                *  the PHY is in.
+                */
+               ret_val = hw->phy.ops.check_reset_block(hw);
+               if (ret_val)
+                       e_err("ME blocked access to PHY after reset\n");
        }
 
 out:
@@ -724,8 +770,14 @@ s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data)
  *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
  *  the link and the EEE capabilities of the link partner.  The LPI Control
  *  register bits will remain set only if/when link is up.
+ *
+ *  EEE LPI must not be asserted earlier than one second after link is up.
+ *  On 82579, EEE LPI should not be enabled until such time otherwise there
+ *  can be link issues with some switches.  Other devices can have EEE LPI
+ *  enabled immediately upon link up since they have a timer in hardware which
+ *  prevents LPI from being asserted too early.
  **/
-static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
 {
        struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
        s32 ret_val;
@@ -978,6 +1030,253 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
        return 0;
 }
 
+/**
+ *  e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
+ *  @hw: pointer to the HW structure
+ *  @to_sx: boolean indicating a system power state transition to Sx
+ *
+ *  When link is down, configure ULP mode to significantly reduce the power
+ *  to the PHY.  If on a Manageability Engine (ME) enabled system, tell the
+ *  ME firmware to start the ULP configuration.  If not on an ME enabled
+ *  system, configure the ULP mode by software.
+ */
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
+{
+       u32 mac_reg;
+       s32 ret_val = 0;
+       u16 phy_reg;
+
+       if ((hw->mac.type < e1000_pch_lpt) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+           (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
+               return 0;
+
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+               /* Request ME configure ULP mode in the PHY */
+               mac_reg = er32(H2ME);
+               mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
+               ew32(H2ME, mac_reg);
+
+               goto out;
+       }
+
+       if (!to_sx) {
+               int i = 0;
+
+               /* Poll up to 5 seconds for Cable Disconnected indication */
+               while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
+                       /* Bail if link is re-acquired */
+                       if (er32(STATUS) & E1000_STATUS_LU)
+                               return -E1000_ERR_PHY;
+
+                       if (i++ == 100)
+                               break;
+
+                       msleep(50);
+               }
+               e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n",
+                     (er32(FEXT) &
+                      E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50);
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+
+       /* Force SMBus mode in PHY */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
+       e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+       /* Force SMBus mode in MAC */
+       mac_reg = er32(CTRL_EXT);
+       mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+       ew32(CTRL_EXT, mac_reg);
+
+       /* Set Inband ULP Exit, Reset to SMBus mode and
+        * Disable SMBus Release on PERST# in PHY
+        */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
+                   I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+       if (to_sx) {
+               if (er32(WUFC) & E1000_WUFC_LNKC)
+                       phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
+
+               phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
+       } else {
+               phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
+       }
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Set Disable SMBus Release on PERST# in MAC */
+       mac_reg = er32(FEXTNVM7);
+       mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
+       ew32(FEXTNVM7, mac_reg);
+
+       /* Commit ULP changes in PHY by starting auto ULP configuration */
+       phy_reg |= I218_ULP_CONFIG1_START;
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+release:
+       hw->phy.ops.release(hw);
+out:
+       if (ret_val)
+               e_dbg("Error in ULP enable flow: %d\n", ret_val);
+       else
+               hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
+
+       return ret_val;
+}
+
+/**
+ *  e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
+ *  @hw: pointer to the HW structure
+ *  @force: boolean indicating whether or not to force disabling ULP
+ *
+ *  Un-configure ULP mode when link is up, the system is transitioned from
+ *  Sx or the driver is unloaded.  If on a Manageability Engine (ME) enabled
+ *  system, poll for an indication from ME that ULP has been un-configured.
+ *  If not on an ME enabled system, un-configure the ULP mode by software.
+ *
+ *  During nominal operation, this function is called when link is acquired
+ *  to disable ULP mode (force=false); otherwise, for example when unloading
+ *  the driver or during Sx->S0 transitions, this is called with force=true
+ *  to forcibly disable ULP.
+ */
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
+{
+       s32 ret_val = 0;
+       u32 mac_reg;
+       u16 phy_reg;
+       int i = 0;
+
+       if ((hw->mac.type < e1000_pch_lpt) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+           (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
+               return 0;
+
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+               if (force) {
+                       /* Request ME un-configure ULP mode in the PHY */
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ULP;
+                       mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
+                       ew32(H2ME, mac_reg);
+               }
+
+               /* Poll up to 100msec for ME to clear ULP_CFG_DONE */
+               while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
+                       if (i++ == 10) {
+                               ret_val = -E1000_ERR_PHY;
+                               goto out;
+                       }
+
+                       usleep_range(10000, 20000);
+               }
+               e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
+
+               if (force) {
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
+                       ew32(H2ME, mac_reg);
+               } else {
+                       /* Clear H2ME.ULP after ME ULP configuration */
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ULP;
+                       ew32(H2ME, mac_reg);
+               }
+
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+
+       if (force)
+               /* Toggle LANPHYPC Value bit */
+               e1000_toggle_lanphypc_pch_lpt(hw);
+
+       /* Unforce SMBus mode in PHY */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+       if (ret_val) {
+               /* The MAC might be in PCIe mode, so temporarily force to
+                * SMBus mode in order to access the PHY.
+                */
+               mac_reg = er32(CTRL_EXT);
+               mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+               ew32(CTRL_EXT, mac_reg);
+
+               msleep(50);
+
+               ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
+                                                      &phy_reg);
+               if (ret_val)
+                       goto release;
+       }
+       phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+       e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+       /* Unforce SMBus mode in MAC */
+       mac_reg = er32(CTRL_EXT);
+       mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+       ew32(CTRL_EXT, mac_reg);
+
+       /* When ULP mode was previously entered, K1 was disabled by the
+        * hardware.  Re-Enable K1 in the PHY when exiting ULP.
+        */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= HV_PM_CTRL_K1_ENABLE;
+       e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
+
+       /* Clear ULP enabled configuration */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg &= ~(I218_ULP_CONFIG1_IND |
+                    I218_ULP_CONFIG1_STICKY_ULP |
+                    I218_ULP_CONFIG1_RESET_TO_SMBUS |
+                    I218_ULP_CONFIG1_WOL_HOST |
+                    I218_ULP_CONFIG1_INBAND_EXIT |
+                    I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Commit ULP changes by starting auto ULP configuration */
+       phy_reg |= I218_ULP_CONFIG1_START;
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Clear Disable SMBus Release on PERST# in MAC */
+       mac_reg = er32(FEXTNVM7);
+       mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
+       ew32(FEXTNVM7, mac_reg);
+
+release:
+       hw->phy.ops.release(hw);
+       if (force) {
+               e1000_phy_hw_reset(hw);
+               msleep(50);
+       }
+out:
+       if (ret_val)
+               e_dbg("Error in ULP disable flow: %d\n", ret_val);
+       else
+               hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
+
+       return ret_val;
+}
+
 /**
  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
  *  @hw: pointer to the HW structure
@@ -1106,9 +1405,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
        e1000e_check_downshift(hw);
 
        /* Enable/Disable EEE after link up */
-       ret_val = e1000_set_eee_pchlan(hw);
-       if (ret_val)
-               return ret_val;
+       if (hw->phy.type > e1000_phy_82579) {
+               ret_val = e1000_set_eee_pchlan(hw);
+               if (ret_val)
+                       return ret_val;
+       }
 
        /* If we are forcing speed/duplex, then we simply return since
         * we have already determined whether we have link or not.
@@ -1374,7 +1675,7 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
        /* RAR[1-6] are owned by manageability.  Skip those and program the
         * next address into the SHRA register array.
         */
-       if (index < (u32)(hw->mac.rar_entry_count - 6)) {
+       if (index < (u32)(hw->mac.rar_entry_count)) {
                s32 ret_val;
 
                ret_val = e1000_acquire_swflag_ich8lan(hw);
@@ -1484,11 +1785,13 @@ out:
  **/
 static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
 {
-       u32 fwsm;
+       bool blocked = false;
+       int i = 0;
 
-       fwsm = er32(FWSM);
-
-       return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
+       while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
+              (i++ < 10))
+               usleep_range(10000, 20000);
+       return blocked ? E1000_BLK_PHY_RESET : 0;
 }
 
 /**
index 217090df33e788d46603f1c0369a2cf4e8041719..bead50f9187b527291596da67351339b64482707 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_ICH8LAN_H_
 #define _E1000E_ICH8LAN_H_
 
 #define E1000_FWSM_WLOCK_MAC_MASK      0x0380
 #define E1000_FWSM_WLOCK_MAC_SHIFT     7
+#define E1000_FWSM_ULP_CFG_DONE                0x00000400      /* Low power cfg done */
 
 /* Shared Receive Address Registers */
 #define E1000_SHRAL_PCH_LPT(_i)                (0x05408 + ((_i) * 8))
 #define E1000_SHRAH_PCH_LPT(_i)                (0x0540C + ((_i) * 8))
 
+#define E1000_H2ME             0x05B50 /* Host to ME */
+#define E1000_H2ME_ULP         0x00000800      /* ULP Indication Bit */
+#define E1000_H2ME_ENFORCE_SETTINGS    0x00001000      /* Enforce Settings */
+
 #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
                                 (ID_LED_OFF1_OFF2 <<  8) | \
                                 (ID_LED_OFF1_ON2  <<  4) | \
@@ -82,6 +80,9 @@
 
 #define E1000_ICH8_LAN_INIT_TIMEOUT    1500
 
+/* FEXT register bit definition */
+#define E1000_FEXT_PHY_CABLE_DISCONNECTED      0x00000004
+
 #define E1000_FEXTNVM_SW_CONFIG                1
 #define E1000_FEXTNVM_SW_CONFIG_ICH8M  (1 << 27)       /* different on ICH8M */
 
 #define E1000_FEXTNVM6_REQ_PLL_CLK     0x00000100
 #define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION       0x00000200
 
+#define E1000_FEXTNVM7_DISABLE_SMB_PERST       0x00000020
+
 #define PCIE_ICH8_SNOOP_ALL    PCIE_NO_SNOOP_ALL
 
 #define E1000_ICH_RAR_ENTRIES  7
-#define E1000_PCH2_RAR_ENTRIES 11      /* RAR[0-6], SHRA[0-3] */
+#define E1000_PCH2_RAR_ENTRIES 5       /* RAR[0], SHRA[0-3] */
 #define E1000_PCH_LPT_RAR_ENTRIES      12      /* RAR[0], SHRA[0-10] */
 
 #define PHY_PAGE_SHIFT         5
 #define CV_SMB_CTRL            PHY_REG(769, 23)
 #define CV_SMB_CTRL_FORCE_SMBUS        0x0001
 
+/* I218 Ultra Low Power Configuration 1 Register */
+#define I218_ULP_CONFIG1               PHY_REG(779, 16)
+#define I218_ULP_CONFIG1_START         0x0001  /* Start auto ULP config */
+#define I218_ULP_CONFIG1_IND           0x0004  /* Pwr up from ULP indication */
+#define I218_ULP_CONFIG1_STICKY_ULP    0x0010  /* Set sticky ULP mode */
+#define I218_ULP_CONFIG1_INBAND_EXIT   0x0020  /* Inband on ULP exit */
+#define I218_ULP_CONFIG1_WOL_HOST      0x0040  /* WoL Host on ULP exit */
+#define I218_ULP_CONFIG1_RESET_TO_SMBUS        0x0100  /* Reset to SMBus mode */
+#define I218_ULP_CONFIG1_DISABLE_SMB_PERST     0x1000  /* Disable on PERST# */
+
 /* SMBus Address Phy Register */
 #define HV_SMB_ADDR            PHY_REG(768, 26)
 #define HV_SMB_ADDR_MASK       0x007F
 /* PHY Power Management Control */
 #define HV_PM_CTRL             PHY_REG(770, 17)
 #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
+#define HV_PM_CTRL_K1_ENABLE           0x4000
 
 #define SW_FLAG_TIMEOUT                1000    /* SW Semaphore flag timeout in ms */
 
@@ -268,4 +282,6 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
 s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
 s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
 s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data);
+s32 e1000_set_eee_pchlan(struct e1000_hw *hw);
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx);
 #endif /* _E1000E_ICH8LAN_H_ */
index 2480c1091873864991d9342b6ce15df61b07c000..baa0a466d1d05ca533999b9ffcac3846a476ab5f 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index a61fee404ebeddf31b8ad636582fb740552e2c7c..4e81c2825b7a1ca60b9a870ce61737e29d4e7972 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_MAC_H_
 #define _E1000E_MAC_H_
index e4b0f1ef92f6fdcc95b193910c7a7947e0063dbd..cb37ff1f1321991c34f17b80d820e9d923d0d3aa 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index 326897c29ea81e5f319e2cad932f6870a8e69fe9..a8c27f98f7b05e15d9548ba78df62c1c351ac91d 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_MANAGE_H_
 #define _E1000E_MANAGE_H_
index 6d91933c4cdd3873990ba36100dd5ae7f21a7782..f1cce5928e201be7086fcfc6d3269a33960c5f2f 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
@@ -885,7 +878,7 @@ static inline void e1000_rx_hash(struct net_device *netdev, __le32 rss,
                                 struct sk_buff *skb)
 {
        if (netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rss);
+               skb_set_hash(skb, le32_to_cpu(rss), PKT_HASH_TYPE_L3);
 }
 
 /**
@@ -1097,8 +1090,14 @@ static void e1000_print_hw_hang(struct work_struct *work)
                adapter->tx_hang_recheck = true;
                return;
        }
-       /* Real hang detected */
        adapter->tx_hang_recheck = false;
+
+       if (er32(TDH(0)) == er32(TDT(0))) {
+               e_dbg("false hang detected, ignoring\n");
+               return;
+       }
+
+       /* Real hang detected */
        netif_stop_queue(netdev);
 
        e1e_rphy(hw, MII_BMSR, &phy_status);
@@ -1128,6 +1127,8 @@ static void e1000_print_hw_hang(struct work_struct *work)
              eop, jiffies, eop_desc->upper.fields.status, er32(STATUS),
              phy_status, phy_1000t_status, phy_ext_status, pci_status);
 
+       e1000e_dump(adapter);
+
        /* Suggest workaround for known h/w issue */
        if ((hw->mac.type == e1000_pchlan) && (er32(CTRL) & E1000_CTRL_TFCE))
                e_err("Try turning off Tx pause (flow control) via ethtool\n");
@@ -1147,9 +1148,6 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
                                                     tx_hwtstamp_work);
        struct e1000_hw *hw = &adapter->hw;
 
-       if (!adapter->tx_hwtstamp_skb)
-               return;
-
        if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
                struct skb_shared_hwtstamps shhwtstamps;
                u64 txstmp;
@@ -1162,6 +1160,12 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work)
                skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
                dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
                adapter->tx_hwtstamp_skb = NULL;
+       } else if (time_after(jiffies, adapter->tx_hwtstamp_start
+                             + adapter->tx_timeout_factor * HZ)) {
+               dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+               adapter->tx_hwtstamp_skb = NULL;
+               adapter->tx_hwtstamp_timeouts++;
+               e_warn("clearing Tx timestamp hang");
        } else {
                /* reschedule to check later */
                schedule_work(&adapter->tx_hwtstamp_work);
@@ -1701,7 +1705,7 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)
        adapter->flags2 &= ~FLAG2_IS_DISCARDING;
 
        writel(0, rx_ring->head);
-       if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
                e1000e_update_rdt_wa(rx_ring, 0);
        else
                writel(0, rx_ring->tail);
@@ -2038,13 +2042,16 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
                                                               msix_entry),
                                                        GFP_KERNEL);
                        if (adapter->msix_entries) {
+                               struct e1000_adapter *a = adapter;
+
                                for (i = 0; i < adapter->num_vectors; i++)
                                        adapter->msix_entries[i].entry = i;
 
-                               err = pci_enable_msix(adapter->pdev,
-                                                     adapter->msix_entries,
-                                                     adapter->num_vectors);
-                               if (err == 0)
+                               err = pci_enable_msix_range(a->pdev,
+                                                           a->msix_entries,
+                                                           a->num_vectors,
+                                                           a->num_vectors);
+                               if (err > 0)
                                        return;
                        }
                        /* MSI-X failed, so fall through and try MSI */
@@ -2402,7 +2409,7 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring)
        tx_ring->next_to_clean = 0;
 
        writel(0, tx_ring->head);
-       if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+       if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
                e1000e_update_tdt_wa(tx_ring, 0);
        else
                writel(0, tx_ring->tail);
@@ -2894,7 +2901,7 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        struct e1000_ring *tx_ring = adapter->tx_ring;
        u64 tdba;
-       u32 tdlen, tarc;
+       u32 tdlen, tctl, tarc;
 
        /* Setup the HW Tx Head and Tail descriptor pointers */
        tdba = tx_ring->dma;
@@ -2931,6 +2938,12 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
        /* erratum work around: set txdctl the same for both queues */
        ew32(TXDCTL(1), er32(TXDCTL(0)));
 
+       /* Program the Transmit Control Register */
+       tctl = er32(TCTL);
+       tctl &= ~E1000_TCTL_CT;
+       tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+               (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
        if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
                tarc = er32(TARC(0));
                /* set the speed mode bit, we'll clear it if we're not at
@@ -2961,6 +2974,8 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
        /* enable Report Status bit */
        adapter->txd_cmd |= E1000_TXD_CMD_RS;
 
+       ew32(TCTL, tctl);
+
        hw->mac.ops.config_collision_dist(hw);
 }
 
@@ -3331,6 +3346,9 @@ static void e1000e_set_rx_mode(struct net_device *netdev)
        struct e1000_hw *hw = &adapter->hw;
        u32 rctl;
 
+       if (pm_runtime_suspended(netdev->dev.parent))
+               return;
+
        /* Check for Promiscuous and All Multicast modes */
        rctl = er32(RCTL);
 
@@ -3691,10 +3709,6 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter)
  */
 static void e1000_power_down_phy(struct e1000_adapter *adapter)
 {
-       /* WoL is enabled */
-       if (adapter->wol)
-               return;
-
        if (adapter->hw.phy.ops.power_down)
                adapter->hw.phy.ops.power_down(&adapter->hw);
 }
@@ -3911,10 +3925,8 @@ void e1000e_reset(struct e1000_adapter *adapter)
        }
 
        if (!netif_running(adapter->netdev) &&
-           !test_bit(__E1000_TESTING, &adapter->state)) {
+           !test_bit(__E1000_TESTING, &adapter->state))
                e1000_power_down_phy(adapter);
-               return;
-       }
 
        e1000_get_phy_info(hw);
 
@@ -3981,7 +3993,12 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter)
 
 static void e1000e_update_stats(struct e1000_adapter *adapter);
 
-void e1000e_down(struct e1000_adapter *adapter)
+/**
+ * e1000e_down - quiesce the device and optionally reset the hardware
+ * @adapter: board private structure
+ * @reset: boolean flag to reset the hardware or not
+ */
+void e1000e_down(struct e1000_adapter *adapter, bool reset)
 {
        struct net_device *netdev = adapter->netdev;
        struct e1000_hw *hw = &adapter->hw;
@@ -4035,12 +4052,8 @@ void e1000e_down(struct e1000_adapter *adapter)
            e1000_lv_jumbo_workaround_ich8lan(hw, false))
                e_dbg("failed to disable jumbo frame workaround mode\n");
 
-       if (!pci_channel_offline(adapter->pdev))
+       if (reset && !pci_channel_offline(adapter->pdev))
                e1000e_reset(adapter);
-
-       /* TODO: for power management, we could drop the link and
-        * pci_disable_device here.
-        */
 }
 
 void e1000e_reinit_locked(struct e1000_adapter *adapter)
@@ -4048,7 +4061,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
        might_sleep();
        while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
                usleep_range(1000, 2000);
-       e1000e_down(adapter);
+       e1000e_down(adapter, true);
        e1000e_up(adapter);
        clear_bit(__E1000_RESETTING, &adapter->state);
 }
@@ -4326,7 +4339,6 @@ static int e1000_open(struct net_device *netdev)
        adapter->tx_hang_recheck = false;
        netif_start_queue(netdev);
 
-       adapter->idle_check = true;
        hw->mac.get_link_status = true;
        pm_runtime_put(&pdev->dev);
 
@@ -4376,14 +4388,15 @@ static int e1000_close(struct net_device *netdev)
        pm_runtime_get_sync(&pdev->dev);
 
        if (!test_bit(__E1000_DOWN, &adapter->state)) {
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
                e1000_free_irq(adapter);
+
+               /* Link status message must follow this format */
+               pr_info("%s NIC Link is Down\n", adapter->netdev->name);
        }
 
        napi_disable(&adapter->napi);
 
-       e1000_power_down_phy(adapter);
-
        e1000e_free_tx_resources(adapter->tx_ring);
        e1000e_free_rx_resources(adapter->rx_ring);
 
@@ -4460,11 +4473,16 @@ static void e1000e_update_phy_task(struct work_struct *work)
        struct e1000_adapter *adapter = container_of(work,
                                                     struct e1000_adapter,
                                                     update_phy_task);
+       struct e1000_hw *hw = &adapter->hw;
 
        if (test_bit(__E1000_DOWN, &adapter->state))
                return;
 
-       e1000_get_phy_info(&adapter->hw);
+       e1000_get_phy_info(hw);
+
+       /* Enable EEE on 82579 after link up */
+       if (hw->phy.type == e1000_phy_82579)
+               e1000_set_eee_pchlan(hw);
 }
 
 /**
@@ -4799,6 +4817,7 @@ static void e1000e_check_82574_phy_workaround(struct e1000_adapter *adapter)
 
        if (adapter->phy_hang_count > 1) {
                adapter->phy_hang_count = 0;
+               e_dbg("PHY appears hung - resetting\n");
                schedule_work(&adapter->reset_task);
        }
 }
@@ -4957,15 +4976,11 @@ static void e1000_watchdog_task(struct work_struct *work)
                                mod_timer(&adapter->phy_info_timer,
                                          round_jiffies(jiffies + 2 * HZ));
 
-                       /* The link is lost so the controller stops DMA.
-                        * If there is queued Tx work that cannot be done
-                        * or if on an 8000ES2LAN which requires a Rx packet
-                        * buffer work-around on link down event, reset the
-                        * controller to flush the Tx/Rx packet buffers.
-                        * (Do the reset outside of interrupt context).
+                       /* 8000ES2LAN requires a Rx packet buffer work-around
+                        * on link down event; reset the controller to flush
+                        * the Rx packet buffer.
                         */
-                       if ((adapter->flags & FLAG_RX_NEEDS_RESTART) ||
-                           (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+                       if (adapter->flags & FLAG_RX_NEEDS_RESTART)
                                adapter->flags |= FLAG_RESTART_NOW;
                        else
                                pm_schedule_suspend(netdev->dev.parent,
@@ -4988,6 +5003,15 @@ link_up:
        adapter->gotc_old = adapter->stats.gotc;
        spin_unlock(&adapter->stats64_lock);
 
+       /* If the link is lost the controller stops DMA, but
+        * if there is queued Tx work it cannot be done.  So
+        * reset the controller to flush the Tx packet buffers.
+        */
+       if (!netif_carrier_ok(netdev) &&
+           (e1000_desc_unused(tx_ring) + 1 < tx_ring->count))
+               adapter->flags |= FLAG_RESTART_NOW;
+
+       /* If reset is necessary, do it outside of interrupt context. */
        if (adapter->flags & FLAG_RESTART_NOW) {
                schedule_work(&adapter->reset_task);
                /* return immediately since reset is imminent */
@@ -5546,6 +5570,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
                        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                        tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
                        adapter->tx_hwtstamp_skb = skb_get(skb);
+                       adapter->tx_hwtstamp_start = jiffies;
                        schedule_work(&adapter->tx_hwtstamp_work);
                } else {
                        skb_tx_timestamp(skb);
@@ -5684,8 +5709,11 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        adapter->max_frame_size = max_frame;
        e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
+
+       pm_runtime_get_sync(netdev->dev.parent);
+
        if (netif_running(netdev))
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
 
        /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
         * means we reserve 2 more, this pushes us to allocate from the next
@@ -5711,6 +5739,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
        else
                e1000e_reset(adapter);
 
+       pm_runtime_put_sync(netdev->dev.parent);
+
        clear_bit(__E1000_RESETTING, &adapter->state);
 
        return 0;
@@ -5852,7 +5882,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u32 i, mac_reg;
+       u32 i, mac_reg, wuc;
        u16 phy_reg, wuc_enable;
        int retval;
 
@@ -5899,13 +5929,18 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
                phy_reg |= BM_RCTL_RFCE;
        hw->phy.ops.write_reg_page(&adapter->hw, BM_RCTL, phy_reg);
 
+       wuc = E1000_WUC_PME_EN;
+       if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC))
+               wuc |= E1000_WUC_APME;
+
        /* enable PHY wakeup in MAC register */
        ew32(WUFC, wufc);
-       ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN);
+       ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME |
+                  E1000_WUC_PME_STATUS | wuc));
 
        /* configure and enable PHY wakeup in PHY registers */
        hw->phy.ops.write_reg_page(&adapter->hw, BM_WUFC, wufc);
-       hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, E1000_WUC_PME_EN);
+       hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, wuc);
 
        /* activate PHY wakeup */
        wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
@@ -5918,15 +5953,10 @@ release:
        return retval;
 }
 
-static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+static int e1000e_pm_freeze(struct device *dev)
 {
-       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
-       struct e1000_hw *hw = &adapter->hw;
-       u32 ctrl, ctrl_ext, rctl, status;
-       /* Runtime suspend should only enable wakeup for link changes */
-       u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
-       int retval = 0;
 
        netif_device_detach(netdev);
 
@@ -5937,11 +5967,29 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
                        usleep_range(10000, 20000);
 
                WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
-               e1000e_down(adapter);
+
+               /* Quiesce the device without resetting the hardware */
+               e1000e_down(adapter, false);
                e1000_free_irq(adapter);
        }
        e1000e_reset_interrupt_capability(adapter);
 
+       /* Allow time for pending master requests to run */
+       e1000e_disable_pcie_master(&adapter->hw);
+
+       return 0;
+}
+
+static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ctrl, ctrl_ext, rctl, status;
+       /* Runtime suspend should only enable wakeup for link changes */
+       u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol;
+       int retval = 0;
+
        status = er32(STATUS);
        if (status & E1000_STATUS_LU)
                wufc &= ~E1000_WUFC_LNKC;
@@ -5972,12 +6020,12 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
                        ew32(CTRL_EXT, ctrl_ext);
                }
 
+               if (!runtime)
+                       e1000e_power_up_phy(adapter);
+
                if (adapter->flags & FLAG_IS_ICH)
                        e1000_suspend_workarounds_ich8lan(&adapter->hw);
 
-               /* Allow time for pending master requests to run */
-               e1000e_disable_pcie_master(&adapter->hw);
-
                if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) {
                        /* enable wakeup by the PHY */
                        retval = e1000_init_phy_wakeup(adapter, wufc);
@@ -5991,10 +6039,23 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
        } else {
                ew32(WUC, 0);
                ew32(WUFC, 0);
+
+               e1000_power_down_phy(adapter);
        }
 
-       if (adapter->hw.phy.type == e1000_phy_igp_3)
+       if (adapter->hw.phy.type == e1000_phy_igp_3) {
                e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+       } else if (hw->mac.type == e1000_pch_lpt) {
+               if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
+                       /* ULP does not support wake from unicast, multicast
+                        * or broadcast.
+                        */
+                       retval = e1000_enable_ulp_lpt_lp(hw, !runtime);
+
+               if (retval)
+                       return retval;
+       }
+
 
        /* Release control of h/w to f/w.  If f/w is AMT enabled, this
         * would have already happened in close and is redundant.
@@ -6102,18 +6163,12 @@ static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 }
 
 #ifdef CONFIG_PM
-static bool e1000e_pm_ready(struct e1000_adapter *adapter)
-{
-       return !!adapter->tx_ring->buffer_info;
-}
-
 static int __e1000_resume(struct pci_dev *pdev)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        u16 aspm_disable_flag = 0;
-       u32 err;
 
        if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S)
                aspm_disable_flag = PCIE_LINK_STATE_L0S;
@@ -6124,13 +6179,6 @@ static int __e1000_resume(struct pci_dev *pdev)
 
        pci_set_master(pdev);
 
-       e1000e_set_interrupt_capability(adapter);
-       if (netif_running(netdev)) {
-               err = e1000_request_irq(adapter);
-               if (err)
-                       return err;
-       }
-
        if (hw->mac.type >= e1000_pch2lan)
                e1000_resume_workarounds_pchlan(&adapter->hw);
 
@@ -6169,11 +6217,6 @@ static int __e1000_resume(struct pci_dev *pdev)
 
        e1000_init_manageability_pt(adapter);
 
-       if (netif_running(netdev))
-               e1000e_up(adapter);
-
-       netif_device_attach(netdev);
-
        /* If the controller has AMT, do not set DRV_LOAD until the interface
         * is up.  For all other cases, let the f/w know that the h/w is now
         * under the control of the driver.
@@ -6184,75 +6227,111 @@ static int __e1000_resume(struct pci_dev *pdev)
        return 0;
 }
 
+static int e1000e_pm_thaw(struct device *dev)
+{
+       struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       e1000e_set_interrupt_capability(adapter);
+       if (netif_running(netdev)) {
+               u32 err = e1000_request_irq(adapter);
+
+               if (err)
+                       return err;
+
+               e1000e_up(adapter);
+       }
+
+       netif_device_attach(netdev);
+
+       return 0;
+}
+
 #ifdef CONFIG_PM_SLEEP
-static int e1000_suspend(struct device *dev)
+static int e1000e_pm_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
 
+       e1000e_pm_freeze(dev);
+
        return __e1000_shutdown(pdev, false);
 }
 
-static int e1000_resume(struct device *dev)
+static int e1000e_pm_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
-       struct net_device *netdev = pci_get_drvdata(pdev);
-       struct e1000_adapter *adapter = netdev_priv(netdev);
+       int rc;
 
-       if (e1000e_pm_ready(adapter))
-               adapter->idle_check = true;
+       rc = __e1000_resume(pdev);
+       if (rc)
+               return rc;
 
-       return __e1000_resume(pdev);
+       return e1000e_pm_thaw(dev);
 }
 #endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_RUNTIME
-static int e1000_runtime_suspend(struct device *dev)
+static int e1000e_pm_runtime_idle(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (!e1000e_pm_ready(adapter))
-               return 0;
+       if (!e1000e_has_link(adapter))
+               pm_schedule_suspend(dev, 5 * MSEC_PER_SEC);
 
-       return __e1000_shutdown(pdev, true);
+       return -EBUSY;
 }
 
-static int e1000_idle(struct device *dev)
+static int e1000e_pm_runtime_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
+       int rc;
 
-       if (!e1000e_pm_ready(adapter))
-               return 0;
+       rc = __e1000_resume(pdev);
+       if (rc)
+               return rc;
 
-       if (adapter->idle_check) {
-               adapter->idle_check = false;
-               if (!e1000e_has_link(adapter))
-                       pm_schedule_suspend(dev, MSEC_PER_SEC);
-       }
+       if (netdev->flags & IFF_UP)
+               rc = e1000e_up(adapter);
 
-       return -EBUSY;
+       return rc;
 }
 
-static int e1000_runtime_resume(struct device *dev)
+static int e1000e_pm_runtime_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct e1000_adapter *adapter = netdev_priv(netdev);
 
-       if (!e1000e_pm_ready(adapter))
-               return 0;
+       if (netdev->flags & IFF_UP) {
+               int count = E1000_CHECK_RESET_COUNT;
 
-       adapter->idle_check = !dev->power.runtime_auto;
-       return __e1000_resume(pdev);
+               while (test_bit(__E1000_RESETTING, &adapter->state) && count--)
+                       usleep_range(10000, 20000);
+
+               WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+
+               /* Down the device without resetting the hardware */
+               e1000e_down(adapter, false);
+       }
+
+       if (__e1000_shutdown(pdev, true)) {
+               e1000e_pm_runtime_resume(dev);
+               return -EBUSY;
+       }
+
+       return 0;
 }
 #endif /* CONFIG_PM_RUNTIME */
 #endif /* CONFIG_PM */
 
 static void e1000_shutdown(struct pci_dev *pdev)
 {
+       e1000e_pm_freeze(&pdev->dev);
+
        __e1000_shutdown(pdev, false);
 }
 
@@ -6338,7 +6417,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
                return PCI_ERS_RESULT_DISCONNECT;
 
        if (netif_running(netdev))
-               e1000e_down(adapter);
+               e1000e_down(adapter, true);
        pci_disable_device(pdev);
 
        /* Request a slot slot reset. */
@@ -6350,7 +6429,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
  * @pdev: Pointer to PCI device
  *
  * Restart the card from scratch, as if from a cold-boot. Implementation
- * resembles the first-half of the e1000_resume routine.
+ * resembles the first-half of the e1000e_pm_resume routine.
  */
 static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
 {
@@ -6397,7 +6476,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
  *
  * This callback is called when the error recovery driver tells us that
  * its OK to resume normal operation. Implementation resembles the
- * second-half of the e1000_resume routine.
+ * second-half of the e1000e_pm_resume routine.
  */
 static void e1000_io_resume(struct pci_dev *pdev)
 {
@@ -6902,9 +6981,6 @@ static void e1000_remove(struct pci_dev *pdev)
                }
        }
 
-       if (!(netdev->flags & IFF_UP))
-               e1000_power_down_phy(adapter);
-
        /* Don't lie to e1000_close() down the road. */
        if (!down)
                clear_bit(__E1000_DOWN, &adapter->state);
@@ -7026,9 +7102,16 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
 
 static const struct dev_pm_ops e1000_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume)
-       SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume,
-                          e1000_idle)
+#ifdef CONFIG_PM_SLEEP
+       .suspend        = e1000e_pm_suspend,
+       .resume         = e1000e_pm_resume,
+       .freeze         = e1000e_pm_freeze,
+       .thaw           = e1000e_pm_thaw,
+       .poweroff       = e1000e_pm_suspend,
+       .restore        = e1000e_pm_resume,
+#endif
+       SET_RUNTIME_PM_OPS(e1000e_pm_runtime_suspend, e1000e_pm_runtime_resume,
+                          e1000e_pm_runtime_idle)
 };
 
 /* PCI Device API Driver */
@@ -7055,7 +7138,7 @@ static int __init e1000_init_module(void)
        int ret;
        pr_info("Intel(R) PRO/1000 Network Driver - %s\n",
                e1000e_driver_version);
-       pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n");
+       pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n");
        ret = pci_register_driver(&e1000_driver);
 
        return ret;
index d70a03906ac0a0cecfb3f078fa584e376eae061a..a9a976f04bffe957e22b0852bd8918c6d6f63bd0 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index 45fc69561627d87b9d59dcbfb3a74b34f48e175d..342bf69efab545efcd460eaeb3d50198a22af408 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_NVM_H_
 #define _E1000E_NVM_H_
index c16bd75b6caa3f85f4f510da7fb56bafcd0f2b40..d0ac0f3249c886415d308c4a0cd376feda3d44db 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include <linux/netdevice.h>
 #include <linux/module.h>
@@ -381,6 +374,12 @@ void e1000e_check_options(struct e1000_adapter *adapter)
                                 "%s set to dynamic mode\n", opt.name);
                        adapter->itr = 20000;
                        break;
+               case 2:
+                       dev_info(&adapter->pdev->dev,
+                                "%s Invalid mode - setting default\n",
+                                opt.name);
+                       adapter->itr_setting = opt.def;
+                       /* fall-through */
                case 3:
                        dev_info(&adapter->pdev->dev,
                                 "%s set to dynamic conservative mode\n",
index 20e71f4ca4261f99694b04eccd3647906326239d..00b3fc98bf309bf3d371a984f0da7245caf07013 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #include "e1000.h"
 
index f4f71b9991e3733bc35d7b17381e4cae04a28113..3841bccf058c7aa0fe3b2f90e2c70c38e9b6f209 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_PHY_H_
 #define _E1000E_PHY_H_
index 065f8c80d4f2d751e2cd2763f3bd6d1e73b6ab9b..fb1a914a3ad4dc98cf4da0cfc0ad7271a8a12488 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 /* PTP 1588 Hardware Clock (PHC)
  * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb)
@@ -47,6 +40,7 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
                                                     ptp_clock_info);
        struct e1000_hw *hw = &adapter->hw;
        bool neg_adj = false;
+       unsigned long flags;
        u64 adjustment;
        u32 timinca, incvalue;
        s32 ret_val;
@@ -64,6 +58,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
        if (ret_val)
                return ret_val;
 
+       spin_lock_irqsave(&adapter->systim_lock, flags);
+
        incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK;
 
        adjustment = incvalue;
@@ -77,6 +73,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
 
        ew32(TIMINCA, timinca);
 
+       spin_unlock_irqrestore(&adapter->systim_lock, flags);
+
        return 0;
 }
 
@@ -191,6 +189,7 @@ static const struct ptp_clock_info e1000e_ptp_clock_info = {
        .n_alarm        = 0,
        .n_ext_ts       = 0,
        .n_per_out      = 0,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = e1000e_phc_adjfreq,
        .adjtime        = e1000e_phc_adjtime,
index a7e6a3e37257b34f200ba01c3525fd3269964943..ea235bbe50d3c3d32361f505cd98ddfcec5d9744 100644 (file)
@@ -1,30 +1,23 @@
-/*******************************************************************************
-
-  Intel PRO/1000 Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms and conditions of the GNU General Public License,
-  version 2, as published by the Free Software Foundation.
-
-  This program is distributed in the hope it will be useful, but WITHOUT
-  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-  more details.
-
-  You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
-
-  The full GNU General Public License is included in this distribution in
-  the file called "COPYING".
-
-  Contact Information:
-  Linux NICS <linux.nics@intel.com>
-  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
+/* Intel PRO/1000 Linux driver
+ * Copyright(c) 1999 - 2014 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * Linux NICS <linux.nics@intel.com>
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ */
 
 #ifndef _E1000E_REGS_H_
 #define _E1000E_REGS_H_
@@ -39,6 +32,7 @@
 #define E1000_SCTL     0x00024 /* SerDes Control - RW */
 #define E1000_FCAL     0x00028 /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C /* Future Extended - RW */
 #define E1000_FEXTNVM  0x00028 /* Future Extended NVM - RW */
 #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */
 #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */
index 72dae4d97b43e37690fe74818b818d3a9a1e14dc..beb7b4393a6c26fc46c917a798a6fd7bfaee28ea 100644 (file)
 
 #define I40E_NVM_VERSION_LO_SHIFT  0
 #define I40E_NVM_VERSION_LO_MASK   (0xff << I40E_NVM_VERSION_LO_SHIFT)
-#define I40E_NVM_VERSION_HI_SHIFT  8
-#define I40E_NVM_VERSION_HI_MASK   (0xff << I40E_NVM_VERSION_HI_SHIFT)
+#define I40E_NVM_VERSION_HI_SHIFT  12
+#define I40E_NVM_VERSION_HI_MASK   (0xf << I40E_NVM_VERSION_HI_SHIFT)
 
 /* The values in here are decimal coded as hex as is the case in the NVM map*/
 #define I40E_CURRENT_NVM_VERSION_HI 0x2
-#define I40E_CURRENT_NVM_VERSION_LO 0x30
+#define I40E_CURRENT_NVM_VERSION_LO 0x40
 
 /* magic for getting defines into strings */
 #define STRINGIFY(foo)  #foo
@@ -136,6 +136,7 @@ enum i40e_state_t {
        __I40E_EMP_RESET_REQUESTED,
        __I40E_FILTER_OVERFLOW_PROMISC,
        __I40E_SUSPENDED,
+       __I40E_BAD_EEPROM,
 };
 
 enum i40e_interrupt_policy {
@@ -152,8 +153,21 @@ struct i40e_lump_tracking {
 };
 
 #define I40E_DEFAULT_ATR_SAMPLE_RATE   20
-#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512
-struct i40e_fdir_data {
+#define I40E_FDIR_MAX_RAW_PACKET_SIZE  512
+#define I40E_FDIR_BUFFER_FULL_MARGIN   10
+#define I40E_FDIR_BUFFER_HEAD_ROOM     200
+
+struct i40e_fdir_filter {
+       struct hlist_node fdir_node;
+       /* filter ipnut set */
+       u8 flow_type;
+       u8 ip4_proto;
+       __be32 dst_ip[4];
+       __be32 src_ip[4];
+       __be16 src_port;
+       __be16 dst_port;
+       __be32 sctp_v_tag;
+       /* filter control */
        u16 q_index;
        u8  flex_off;
        u8  pctype;
@@ -162,7 +176,6 @@ struct i40e_fdir_data {
        u8  fd_status;
        u16 cnt_index;
        u32 fd_id;
-       u8  *raw_packet;
 };
 
 #define I40E_ETH_P_LLDP                        0x88cc
@@ -196,7 +209,7 @@ struct i40e_pf {
        bool fc_autoneg_status;
 
        u16 eeprom_version;
-       u16 num_vmdq_vsis;         /* num vmdq pools this pf has set up */
+       u16 num_vmdq_vsis;         /* num vmdq vsis this pf has set up */
        u16 num_vmdq_qps;          /* num queue pairs per vmdq pool */
        u16 num_vmdq_msix;         /* num queue vectors per vmdq pool */
        u16 num_req_vfs;           /* num vfs requested for this vf */
@@ -210,6 +223,9 @@ struct i40e_pf {
        u8 atr_sample_rate;
        bool wol_en;
 
+       struct hlist_head fdir_filter_list;
+       u16 fdir_pf_active_filters;
+
 #ifdef CONFIG_I40E_VXLAN
        __be16  vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
        u16 pending_vxlan_bitmap;
@@ -251,6 +267,9 @@ struct i40e_pf {
 #define I40E_FLAG_VXLAN_FILTER_SYNC            (u64)(1 << 27)
 #endif
 
+       /* tracks features that get auto disabled by errors */
+       u64 auto_disable_flags;
+
        bool stat_offsets_loaded;
        struct i40e_hw_port_stats stats;
        struct i40e_hw_port_stats stats_offsets;
@@ -477,10 +496,10 @@ static inline char *i40e_fw_version_str(struct i40e_hw *hw)
                 "f%d.%d a%d.%d n%02x.%02x e%08x",
                 hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
                 hw->aq.api_maj_ver, hw->aq.api_min_ver,
-                (hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
-                                               >> I40E_NVM_VERSION_HI_SHIFT,
-                (hw->nvm.version & I40E_NVM_VERSION_LO_MASK)
-                                               >> I40E_NVM_VERSION_LO_SHIFT,
+                (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >>
+                       I40E_NVM_VERSION_HI_SHIFT,
+                (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >>
+                       I40E_NVM_VERSION_LO_SHIFT,
                 hw->nvm.eetrack);
 
        return buf;
@@ -534,9 +553,13 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi);
 int i40e_fetch_switch_configuration(struct i40e_pf *pf,
                                    bool printconfig);
 
-int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
                             struct i40e_pf *pf, bool add);
-
+int i40e_add_del_fdir(struct i40e_vsi *vsi,
+                     struct i40e_fdir_filter *input, bool add);
+void i40e_fdir_check_and_reenable(struct i40e_pf *pf);
+int i40e_get_current_fd_count(struct i40e_pf *pf);
+bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features);
 void i40e_set_ethtool_ops(struct net_device *netdev);
 struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
                                        u8 *macaddr, s16 vlan,
@@ -575,6 +598,7 @@ void i40e_irq_dynamic_enable(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);
 int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+int i40e_vsi_open(struct i40e_vsi *vsi);
 void i40e_vlan_stripping_disable(struct i40e_vsi *vsi);
 int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid);
 int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid);
index a50e6b3479ae9c779475681634535f1c8181f309..ed3902bf249b3e4ceb047ed14762d6ea50b1a4c0 100644 (file)
@@ -647,9 +647,8 @@ static u16 i40e_clean_asq(struct i40e_hw *hw)
                        desc_cb = *desc;
                        cb_func(hw, &desc_cb);
                }
-               memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
-               memset((void *)details, 0,
-                      sizeof(struct i40e_asq_cmd_details));
+               memset(desc, 0, sizeof(*desc));
+               memset(details, 0, sizeof(*details));
                ntc++;
                if (ntc == asq->count)
                        ntc = 0;
index e7f38b57834d978a82c541df8bb26ffc3ce46937..bb948dd924743f2305491a4836897116bdbaac30 100644 (file)
@@ -162,6 +162,372 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw,
        return status;
 }
 
+/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT i40e_ptype_lookup[ptype].known
+ * THEN
+ *      Packet is unknown
+ * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ *      Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ *      Use the enum i40e_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+       {       PTYPE, \
+               1, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+               I40E_RX_PTYPE_##OUTER_FRAG, \
+               I40E_RX_PTYPE_TUNNEL_##T, \
+               I40E_RX_PTYPE_TUNNEL_END_##TE, \
+               I40E_RX_PTYPE_##TEF, \
+               I40E_RX_PTYPE_INNER_PROT_##I, \
+               I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
+
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
+               { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* shorter macros makes the table fit but are terse */
+#define I40E_RX_PTYPE_NOF              I40E_RX_PTYPE_NOT_FRAG
+#define I40E_RX_PTYPE_FRG              I40E_RX_PTYPE_FRAG
+#define I40E_RX_PTYPE_INNER_PROT_TS    I40E_RX_PTYPE_INNER_PROT_TIMESYNC
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = {
+       /* L2 Packet types */
+       I40E_PTT_UNUSED_ENTRY(0),
+       I40E_PTT(1,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(2,  L2, NONE, NOF, NONE, NONE, NOF, TS,   PAY2),
+       I40E_PTT(3,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(4),
+       I40E_PTT_UNUSED_ENTRY(5),
+       I40E_PTT(6,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(7,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(8),
+       I40E_PTT_UNUSED_ENTRY(9),
+       I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+       I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+       /* Non Tunneled IPv4 */
+       I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(25),
+       I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv4 */
+       I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(32),
+       I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv6 */
+       I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(39),
+       I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT */
+       I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> IPv4 */
+       I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(47),
+       I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> IPv6 */
+       I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(54),
+       I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC */
+       I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+       I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(62),
+       I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+       I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(69),
+       I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC/VLAN */
+       I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(77),
+       I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(84),
+       I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* Non Tunneled IPv6 */
+       I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY3),
+       I40E_PTT_UNUSED_ENTRY(91),
+       I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv4 */
+       I40E_PTT(95,  IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(96,  IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(97,  IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(98),
+       I40E_PTT(99,  IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv6 */
+       I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(105),
+       I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT */
+       I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> IPv4 */
+       I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(113),
+       I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> IPv6 */
+       I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(120),
+       I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC */
+       I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+       I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(128),
+       I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+       I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(135),
+       I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN */
+       I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(143),
+       I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(150),
+       I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* unused entries */
+       I40E_PTT_UNUSED_ENTRY(154),
+       I40E_PTT_UNUSED_ENTRY(155),
+       I40E_PTT_UNUSED_ENTRY(156),
+       I40E_PTT_UNUSED_ENTRY(157),
+       I40E_PTT_UNUSED_ENTRY(158),
+       I40E_PTT_UNUSED_ENTRY(159),
+
+       I40E_PTT_UNUSED_ENTRY(160),
+       I40E_PTT_UNUSED_ENTRY(161),
+       I40E_PTT_UNUSED_ENTRY(162),
+       I40E_PTT_UNUSED_ENTRY(163),
+       I40E_PTT_UNUSED_ENTRY(164),
+       I40E_PTT_UNUSED_ENTRY(165),
+       I40E_PTT_UNUSED_ENTRY(166),
+       I40E_PTT_UNUSED_ENTRY(167),
+       I40E_PTT_UNUSED_ENTRY(168),
+       I40E_PTT_UNUSED_ENTRY(169),
+
+       I40E_PTT_UNUSED_ENTRY(170),
+       I40E_PTT_UNUSED_ENTRY(171),
+       I40E_PTT_UNUSED_ENTRY(172),
+       I40E_PTT_UNUSED_ENTRY(173),
+       I40E_PTT_UNUSED_ENTRY(174),
+       I40E_PTT_UNUSED_ENTRY(175),
+       I40E_PTT_UNUSED_ENTRY(176),
+       I40E_PTT_UNUSED_ENTRY(177),
+       I40E_PTT_UNUSED_ENTRY(178),
+       I40E_PTT_UNUSED_ENTRY(179),
+
+       I40E_PTT_UNUSED_ENTRY(180),
+       I40E_PTT_UNUSED_ENTRY(181),
+       I40E_PTT_UNUSED_ENTRY(182),
+       I40E_PTT_UNUSED_ENTRY(183),
+       I40E_PTT_UNUSED_ENTRY(184),
+       I40E_PTT_UNUSED_ENTRY(185),
+       I40E_PTT_UNUSED_ENTRY(186),
+       I40E_PTT_UNUSED_ENTRY(187),
+       I40E_PTT_UNUSED_ENTRY(188),
+       I40E_PTT_UNUSED_ENTRY(189),
+
+       I40E_PTT_UNUSED_ENTRY(190),
+       I40E_PTT_UNUSED_ENTRY(191),
+       I40E_PTT_UNUSED_ENTRY(192),
+       I40E_PTT_UNUSED_ENTRY(193),
+       I40E_PTT_UNUSED_ENTRY(194),
+       I40E_PTT_UNUSED_ENTRY(195),
+       I40E_PTT_UNUSED_ENTRY(196),
+       I40E_PTT_UNUSED_ENTRY(197),
+       I40E_PTT_UNUSED_ENTRY(198),
+       I40E_PTT_UNUSED_ENTRY(199),
+
+       I40E_PTT_UNUSED_ENTRY(200),
+       I40E_PTT_UNUSED_ENTRY(201),
+       I40E_PTT_UNUSED_ENTRY(202),
+       I40E_PTT_UNUSED_ENTRY(203),
+       I40E_PTT_UNUSED_ENTRY(204),
+       I40E_PTT_UNUSED_ENTRY(205),
+       I40E_PTT_UNUSED_ENTRY(206),
+       I40E_PTT_UNUSED_ENTRY(207),
+       I40E_PTT_UNUSED_ENTRY(208),
+       I40E_PTT_UNUSED_ENTRY(209),
+
+       I40E_PTT_UNUSED_ENTRY(210),
+       I40E_PTT_UNUSED_ENTRY(211),
+       I40E_PTT_UNUSED_ENTRY(212),
+       I40E_PTT_UNUSED_ENTRY(213),
+       I40E_PTT_UNUSED_ENTRY(214),
+       I40E_PTT_UNUSED_ENTRY(215),
+       I40E_PTT_UNUSED_ENTRY(216),
+       I40E_PTT_UNUSED_ENTRY(217),
+       I40E_PTT_UNUSED_ENTRY(218),
+       I40E_PTT_UNUSED_ENTRY(219),
+
+       I40E_PTT_UNUSED_ENTRY(220),
+       I40E_PTT_UNUSED_ENTRY(221),
+       I40E_PTT_UNUSED_ENTRY(222),
+       I40E_PTT_UNUSED_ENTRY(223),
+       I40E_PTT_UNUSED_ENTRY(224),
+       I40E_PTT_UNUSED_ENTRY(225),
+       I40E_PTT_UNUSED_ENTRY(226),
+       I40E_PTT_UNUSED_ENTRY(227),
+       I40E_PTT_UNUSED_ENTRY(228),
+       I40E_PTT_UNUSED_ENTRY(229),
+
+       I40E_PTT_UNUSED_ENTRY(230),
+       I40E_PTT_UNUSED_ENTRY(231),
+       I40E_PTT_UNUSED_ENTRY(232),
+       I40E_PTT_UNUSED_ENTRY(233),
+       I40E_PTT_UNUSED_ENTRY(234),
+       I40E_PTT_UNUSED_ENTRY(235),
+       I40E_PTT_UNUSED_ENTRY(236),
+       I40E_PTT_UNUSED_ENTRY(237),
+       I40E_PTT_UNUSED_ENTRY(238),
+       I40E_PTT_UNUSED_ENTRY(239),
+
+       I40E_PTT_UNUSED_ENTRY(240),
+       I40E_PTT_UNUSED_ENTRY(241),
+       I40E_PTT_UNUSED_ENTRY(242),
+       I40E_PTT_UNUSED_ENTRY(243),
+       I40E_PTT_UNUSED_ENTRY(244),
+       I40E_PTT_UNUSED_ENTRY(245),
+       I40E_PTT_UNUSED_ENTRY(246),
+       I40E_PTT_UNUSED_ENTRY(247),
+       I40E_PTT_UNUSED_ENTRY(248),
+       I40E_PTT_UNUSED_ENTRY(249),
+
+       I40E_PTT_UNUSED_ENTRY(250),
+       I40E_PTT_UNUSED_ENTRY(251),
+       I40E_PTT_UNUSED_ENTRY(252),
+       I40E_PTT_UNUSED_ENTRY(253),
+       I40E_PTT_UNUSED_ENTRY(254),
+       I40E_PTT_UNUSED_ENTRY(255)
+};
+
+
 /**
  * i40e_init_shared_code - Initialize the shared code
  * @hw: pointer to hardware structure
index 50730141bb7b2ea9c726ed070d641579fc9a28bd..036570d76176cd211ef2ee22328aeecd96b7174a 100644 (file)
@@ -332,6 +332,7 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
        u16 type;
        u16 length;
        u16 typelength;
+       u16 offset = 0;
 
        if (!lldpmib || !dcbcfg)
                return I40E_ERR_PARAM;
@@ -339,15 +340,17 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
        /* set to the start of LLDPDU */
        lldpmib += ETH_HLEN;
        tlv = (struct i40e_lldp_org_tlv *)lldpmib;
-       while (tlv) {
+       while (1) {
                typelength = ntohs(tlv->typelength);
                type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
                             I40E_LLDP_TLV_TYPE_SHIFT);
                length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
                               I40E_LLDP_TLV_LEN_SHIFT);
+               offset += sizeof(typelength) + length;
 
-               if (type == I40E_TLV_TYPE_END)
-                       break;/* END TLV break out */
+               /* END TLV or beyond LLDPDU size */
+               if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
+                       break;
 
                switch (type) {
                case I40E_TLV_TYPE_ORG:
index da22c3fa2c004a23adb8545ee01058d3dd0b2e3f..3c37386fd138fdeb3941170e5789687d90385fd5 100644 (file)
@@ -1011,10 +1011,12 @@ static void i40e_dbg_dump_veb_all(struct i40e_pf *pf)
  **/
 static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable)
 {
-       if (enable)
+       if (enable) {
                pf->flags |= flag;
-       else
+       } else {
                pf->flags &= ~flag;
+               pf->auto_disable_flags |= flag;
+       }
        dev_info(&pf->pdev->dev, "requesting a pf reset\n");
        i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
 }
@@ -1467,19 +1469,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                 pf->msg_enable);
                }
        } else if (strncmp(cmd_buf, "pfr", 3) == 0) {
-               dev_info(&pf->pdev->dev, "forcing PFR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing PFR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "corer", 5) == 0) {
-               dev_info(&pf->pdev->dev, "forcing CoreR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing CoreR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "globr", 5) == 0) {
-               dev_info(&pf->pdev->dev, "forcing GlobR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing GlobR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "empr", 4) == 0) {
-               dev_info(&pf->pdev->dev, "forcing EMPR\n");
+               dev_info(&pf->pdev->dev, "debugfs: forcing EMPR\n");
                i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED));
 
        } else if (strncmp(cmd_buf, "read", 4) == 0) {
@@ -1663,28 +1665,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                desc = NULL;
        } else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
                   (strncmp(cmd_buf, "rem fd_filter", 13) == 0)) {
-               struct i40e_fdir_data fd_data;
+               struct i40e_fdir_filter fd_data;
                u16 packet_len, i, j = 0;
                char *asc_packet;
+               u8 *raw_packet;
                bool add = false;
                int ret;
 
-               asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+               if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+                       goto command_write_done;
+
+               if (strncmp(cmd_buf, "add", 3) == 0)
+                       add = true;
+
+               if (add && (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED))
+                       goto command_write_done;
+
+               asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
                                     GFP_KERNEL);
                if (!asc_packet)
                        goto command_write_done;
 
-               fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
-                                            GFP_KERNEL);
+               raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE,
+                                    GFP_KERNEL);
 
-               if (!fd_data.raw_packet) {
+               if (!raw_packet) {
                        kfree(asc_packet);
                        asc_packet = NULL;
                        goto command_write_done;
                }
 
-               if (strncmp(cmd_buf, "add", 3) == 0)
-                       add = true;
                cnt = sscanf(&cmd_buf[13],
                             "%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %511s",
                             &fd_data.q_index,
@@ -1698,36 +1708,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                 cnt);
                        kfree(asc_packet);
                        asc_packet = NULL;
-                       kfree(fd_data.raw_packet);
+                       kfree(raw_packet);
                        goto command_write_done;
                }
 
                /* fix packet length if user entered 0 */
                if (packet_len == 0)
-                       packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP;
+                       packet_len = I40E_FDIR_MAX_RAW_PACKET_SIZE;
 
                /* make sure to check the max as well */
                packet_len = min_t(u16,
-                                  packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+                                  packet_len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
 
                for (i = 0; i < packet_len; i++) {
                        sscanf(&asc_packet[j], "%2hhx ",
-                              &fd_data.raw_packet[i]);
+                              &raw_packet[i]);
                        j += 3;
                }
                dev_info(&pf->pdev->dev, "FD raw packet dump\n");
                print_hex_dump(KERN_INFO, "FD raw packet: ",
                               DUMP_PREFIX_OFFSET, 16, 1,
-                              fd_data.raw_packet, packet_len, true);
-               ret = i40e_program_fdir_filter(&fd_data, pf, add);
+                              raw_packet, packet_len, true);
+               ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add);
                if (!ret) {
                        dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
                } else {
                        dev_info(&pf->pdev->dev,
                                 "Filter command send failed %d\n", ret);
                }
-               kfree(fd_data.raw_packet);
-               fd_data.raw_packet = NULL;
+               kfree(raw_packet);
+               raw_packet = NULL;
                kfree(asc_packet);
                asc_packet = NULL;
        } else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) {
@@ -2077,9 +2087,13 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
                if (!vsi) {
                        dev_info(&pf->pdev->dev,
                                 "tx_timeout: VSI %d not found\n", vsi_seid);
-                       goto netdev_ops_write_done;
-               }
-               if (rtnl_trylock()) {
+               } else if (!vsi->netdev) {
+                       dev_info(&pf->pdev->dev, "tx_timeout: no netdev for VSI %d\n",
+                                vsi_seid);
+               } else if (test_bit(__I40E_DOWN, &vsi->state)) {
+                       dev_info(&pf->pdev->dev, "tx_timeout: VSI %d not UP\n",
+                                vsi_seid);
+               } else if (rtnl_trylock()) {
                        vsi->netdev->netdev_ops->ndo_tx_timeout(vsi->netdev);
                        rtnl_unlock();
                        dev_info(&pf->pdev->dev, "tx_timeout called\n");
@@ -2098,9 +2112,10 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
                if (!vsi) {
                        dev_info(&pf->pdev->dev,
                                 "change_mtu: VSI %d not found\n", vsi_seid);
-                       goto netdev_ops_write_done;
-               }
-               if (rtnl_trylock()) {
+               } else if (!vsi->netdev) {
+                       dev_info(&pf->pdev->dev, "change_mtu: no netdev for VSI %d\n",
+                                vsi_seid);
+               } else if (rtnl_trylock()) {
                        vsi->netdev->netdev_ops->ndo_change_mtu(vsi->netdev,
                                                                mtu);
                        rtnl_unlock();
@@ -2119,9 +2134,10 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
                if (!vsi) {
                        dev_info(&pf->pdev->dev,
                                 "set_rx_mode: VSI %d not found\n", vsi_seid);
-                       goto netdev_ops_write_done;
-               }
-               if (rtnl_trylock()) {
+               } else if (!vsi->netdev) {
+                       dev_info(&pf->pdev->dev, "set_rx_mode: no netdev for VSI %d\n",
+                                vsi_seid);
+               } else if (rtnl_trylock()) {
                        vsi->netdev->netdev_ops->ndo_set_rx_mode(vsi->netdev);
                        rtnl_unlock();
                        dev_info(&pf->pdev->dev, "set_rx_mode called\n");
@@ -2139,11 +2155,14 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
                if (!vsi) {
                        dev_info(&pf->pdev->dev, "napi: VSI %d not found\n",
                                 vsi_seid);
-                       goto netdev_ops_write_done;
+               } else if (!vsi->netdev) {
+                       dev_info(&pf->pdev->dev, "napi: no netdev for VSI %d\n",
+                                vsi_seid);
+               } else {
+                       for (i = 0; i < vsi->num_q_vectors; i++)
+                               napi_schedule(&vsi->q_vectors[i]->napi);
+                       dev_info(&pf->pdev->dev, "napi called\n");
                }
-               for (i = 0; i < vsi->num_q_vectors; i++)
-                       napi_schedule(&vsi->q_vectors[i]->napi);
-               dev_info(&pf->pdev->dev, "napi called\n");
        } else {
                dev_info(&pf->pdev->dev, "unknown command '%s'\n",
                         i40e_dbg_netdev_ops_buf);
index b1d7d8c5cb9b64a362a614f8a412698723582ae8..aa123f43fb8e34e802259e34f7e29d603b0a6de3 100644 (file)
@@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = {
        I40E_NETDEV_STAT(rx_crc_errors),
 };
 
+static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
+                                struct ethtool_rxnfc *cmd);
+
 /* These PF_STATs might look like duplicates of some NETDEV_STATs,
  * but they are separate.  This device supports Virtualization, and
  * as such might have several netdevs supporting VMDq and FCoE going
@@ -84,6 +87,7 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("illegal_bytes", stats.illegal_bytes),
        I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
        I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
+       I40E_PF_STAT("tx_timeout", tx_timeout_count),
        I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
        I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
        I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
@@ -110,6 +114,11 @@ static struct i40e_stats i40e_gstrings_stats[] = {
        I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
        I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
        I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+       /* LPI stats */
+       I40E_PF_STAT("tx_lpi_status", stats.tx_lpi_status),
+       I40E_PF_STAT("rx_lpi_status", stats.rx_lpi_status),
+       I40E_PF_STAT("tx_lpi_count", stats.tx_lpi_count),
+       I40E_PF_STAT("rx_lpi_count", stats.rx_lpi_count),
 };
 
 #define I40E_QUEUE_STATS_LEN(n) \
@@ -649,18 +658,18 @@ static void i40e_get_ethtool_stats(struct net_device *netdev,
 
                /* process Tx ring statistics */
                do {
-                       start = u64_stats_fetch_begin_bh(&tx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
                        data[i] = tx_ring->stats.packets;
                        data[i + 1] = tx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
 
                /* Rx ring is the 2nd half of the queue pair */
                rx_ring = &tx_ring[1];
                do {
-                       start = u64_stats_fetch_begin_bh(&rx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
                        data[i + 2] = rx_ring->stats.packets;
                        data[i + 3] = rx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
        }
        rcu_read_unlock();
        if (vsi == pf->vsi[pf->lan_vsi]) {
@@ -1111,6 +1120,84 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
        return 0;
 }
 
+/**
+ * i40e_get_ethtool_fdir_all - Populates the rule count of a command
+ * @pf: Pointer to the physical function struct
+ * @cmd: The command to get or set Rx flow classification rules
+ * @rule_locs: Array of used rule locations
+ *
+ * This function populates both the total and actual rule count of
+ * the ethtool flow classification command
+ *
+ * Returns 0 on success or -EMSGSIZE if entry not found
+ **/
+static int i40e_get_ethtool_fdir_all(struct i40e_pf *pf,
+                                    struct ethtool_rxnfc *cmd,
+                                    u32 *rule_locs)
+{
+       struct i40e_fdir_filter *rule;
+       struct hlist_node *node2;
+       int cnt = 0;
+
+       /* report total rule count */
+       cmd->data = pf->hw.fdir_shared_filter_count +
+                   pf->fdir_pf_filter_count;
+
+       hlist_for_each_entry_safe(rule, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               if (cnt == cmd->rule_cnt)
+                       return -EMSGSIZE;
+
+               rule_locs[cnt] = rule->fd_id;
+               cnt++;
+       }
+
+       cmd->rule_cnt = cnt;
+
+       return 0;
+}
+
+/**
+ * i40e_get_ethtool_fdir_entry - Look up a filter based on Rx flow
+ * @pf: Pointer to the physical function struct
+ * @cmd: The command to get or set Rx flow classification rules
+ *
+ * This function looks up a filter based on the Rx flow classification
+ * command and fills the flow spec info for it if found
+ *
+ * Returns 0 on success or -EINVAL if filter not found
+ **/
+static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf,
+                                      struct ethtool_rxnfc *cmd)
+{
+       struct ethtool_rx_flow_spec *fsp =
+                       (struct ethtool_rx_flow_spec *)&cmd->fs;
+       struct i40e_fdir_filter *rule = NULL;
+       struct hlist_node *node2;
+
+       /* report total rule count */
+       cmd->data = pf->hw.fdir_shared_filter_count +
+                   pf->fdir_pf_filter_count;
+
+       hlist_for_each_entry_safe(rule, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               if (fsp->location <= rule->fd_id)
+                       break;
+       }
+
+       if (!rule || fsp->location != rule->fd_id)
+               return -EINVAL;
+
+       fsp->flow_type = rule->flow_type;
+       fsp->h_u.tcp_ip4_spec.psrc = rule->src_port;
+       fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port;
+       fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0];
+       fsp->h_u.tcp_ip4_spec.ip4dst = rule->dst_ip[0];
+       fsp->ring_cookie = rule->q_index;
+
+       return 0;
+}
+
 /**
  * i40e_get_rxnfc - command to get RX flow classification rules
  * @netdev: network interface device structure
@@ -1135,15 +1222,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
                ret = i40e_get_rss_hash_opts(pf, cmd);
                break;
        case ETHTOOL_GRXCLSRLCNT:
-               cmd->rule_cnt = 10;
+               cmd->rule_cnt = pf->fdir_pf_active_filters;
                ret = 0;
                break;
        case ETHTOOL_GRXCLSRULE:
-               ret = 0;
+               ret = i40e_get_ethtool_fdir_entry(pf, cmd);
                break;
        case ETHTOOL_GRXCLSRLALL:
-               cmd->data = 500;
-               ret = 0;
+               ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs);
+               break;
        default:
                break;
        }
@@ -1274,289 +1361,182 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
        return 0;
 }
 
-#define IP_HEADER_OFFSET 14
-#define I40E_UDPIP_DUMMY_PACKET_LEN 42
 /**
- * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
+ * i40e_match_fdir_input_set - Match a new filter against an existing one
+ * @rule: The filter already added
+ * @input: The new filter to comapre against
  *
- * Returns 0 if the filters were successfully added or removed
+ * Returns true if the two input set match
  **/
-static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
-                                  struct i40e_fdir_data *fd_data,
-                                  struct ethtool_rx_flow_spec *fsp, bool add)
+static bool i40e_match_fdir_input_set(struct i40e_fdir_filter *rule,
+                                     struct i40e_fdir_filter *input)
 {
-       struct i40e_pf *pf = vsi->back;
-       struct udphdr *udp;
-       struct iphdr *ip;
-       bool err = false;
-       int ret;
-       int i;
-       char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-                        0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0, 0, 0, 0};
-
-       memcpy(fd_data->raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
-
-       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
-       udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
-             + sizeof(struct iphdr));
-
-       ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
-       ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
-       udp->source = fsp->h_u.tcp_ip4_spec.psrc;
-       udp->dest = fsp->h_u.tcp_ip4_spec.pdst;
-
-       for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
-            i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
-               fd_data->pctype = i;
-               ret = i40e_program_fdir_filter(fd_data, pf, add);
-
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-                       err = true;
-               } else {
-                       dev_info(&pf->pdev->dev,
-                                "Filter OK for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-               }
-       }
-
-       return err ? -EOPNOTSUPP : 0;
+       if ((rule->dst_ip[0] != input->dst_ip[0]) ||
+           (rule->src_ip[0] != input->src_ip[0]) ||
+           (rule->dst_port != input->dst_port) ||
+           (rule->src_port != input->src_port))
+               return false;
+       return true;
 }
 
-#define I40E_TCPIP_DUMMY_PACKET_LEN 54
 /**
- * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
+ * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry
+ * @vsi: Pointer to the targeted VSI
+ * @input: The filter to update or NULL to indicate deletion
+ * @sw_idx: Software index to the filter
+ * @cmd: The command to get or set Rx flow classification rules
  *
- * Returns 0 if the filters were successfully added or removed
+ * This function updates (or deletes) a Flow Director entry from
+ * the hlist of the corresponding PF
+ *
+ * Returns 0 on success
  **/
-static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
-                                  struct i40e_fdir_data *fd_data,
-                                  struct ethtool_rx_flow_spec *fsp, bool add)
+static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi,
+                                         struct i40e_fdir_filter *input,
+                                         u16 sw_idx,
+                                         struct ethtool_rxnfc *cmd)
 {
+       struct i40e_fdir_filter *rule, *parent;
        struct i40e_pf *pf = vsi->back;
-       struct tcphdr *tcp;
-       struct iphdr *ip;
-       bool err = false;
-       int ret;
-       /* Dummy packet */
-       char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-                        0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                        0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0};
-
-       memcpy(fd_data->raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
-
-       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
-       tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
-             + sizeof(struct iphdr));
-
-       ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
-       tcp->dest = fsp->h_u.tcp_ip4_spec.pdst;
-       ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
-       tcp->source = fsp->h_u.tcp_ip4_spec.psrc;
-
-       if (add) {
-               if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
-                       dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
-                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
-               }
-       }
+       struct hlist_node *node2;
+       int err = -EINVAL;
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
-       ret = i40e_program_fdir_filter(fd_data, pf, add);
+       parent = NULL;
+       rule = NULL;
 
-       if (ret) {
-               dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
-               err = true;
-       } else {
-               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
+       hlist_for_each_entry_safe(rule, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               /* hash found, or no matching entry */
+               if (rule->fd_id >= sw_idx)
+                       break;
+               parent = rule;
        }
 
-       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
-
-       ret = i40e_program_fdir_filter(fd_data, pf, add);
-       if (ret) {
-               dev_info(&pf->pdev->dev,
-                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                        fd_data->pctype, ret);
-               err = true;
-       } else {
-               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
-                         fd_data->pctype, ret);
+       /* if there is an old rule occupying our place remove it */
+       if (rule && (rule->fd_id == sw_idx)) {
+               if (input && !i40e_match_fdir_input_set(rule, input))
+                       err = i40e_add_del_fdir(vsi, rule, false);
+               else if (!input)
+                       err = i40e_add_del_fdir(vsi, rule, false);
+               hlist_del(&rule->fdir_node);
+               kfree(rule);
+               pf->fdir_pf_active_filters--;
        }
 
-       return err ? -EOPNOTSUPP : 0;
-}
+       /* If no input this was a delete, err should be 0 if a rule was
+        * successfully found and removed from the list else -EINVAL
+        */
+       if (!input)
+               return err;
 
-/**
- * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required from the FDir descriptor
- * @ethtool_rx_flow_spec: the flow spec
- * @add: true adds a filter, false removes it
- *
- * Returns 0 if the filters were successfully added or removed
- **/
-static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
-                                   struct i40e_fdir_data *fd_data,
-                                   struct ethtool_rx_flow_spec *fsp, bool add)
-{
-       return -EOPNOTSUPP;
+       /* initialize node and set software index */
+       INIT_HLIST_NODE(&input->fdir_node);
+
+       /* add filter to the list */
+       if (parent)
+               hlist_add_after(&parent->fdir_node, &input->fdir_node);
+       else
+               hlist_add_head(&input->fdir_node,
+                              &pf->fdir_filter_list);
+
+       /* update counts */
+       pf->fdir_pf_active_filters++;
+
+       return 0;
 }
 
-#define I40E_IP_DUMMY_PACKET_LEN 34
 /**
- * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
- * a specific flow spec
- * @vsi: pointer to the targeted VSI
- * @fd_data: the flow director data required for the FDir descriptor
- * @fsp: the ethtool flow spec
- * @add: true adds a filter, false removes it
+ * i40e_del_fdir_entry - Deletes a Flow Director filter entry
+ * @vsi: Pointer to the targeted VSI
+ * @cmd: The command to get or set Rx flow classification rules
  *
- * Returns 0 if the filters were successfully added or removed
- **/
-static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
-                                 struct i40e_fdir_data *fd_data,
-                                 struct ethtool_rx_flow_spec *fsp, bool add)
+ * The function removes a Flow Director filter entry from the
+ * hlist of the corresponding PF
+ *
+ * Returns 0 on success
+ */
+static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
+                              struct ethtool_rxnfc *cmd)
 {
+       struct ethtool_rx_flow_spec *fsp =
+               (struct ethtool_rx_flow_spec *)&cmd->fs;
        struct i40e_pf *pf = vsi->back;
-       struct iphdr *ip;
-       bool err = false;
-       int ret;
-       int i;
-       char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
-                        0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10,
-                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-       memcpy(fd_data->raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
-       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+       int ret = 0;
 
-       ip->saddr = fsp->h_u.usr_ip4_spec.ip4src;
-       ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst;
-       ip->protocol = fsp->h_u.usr_ip4_spec.proto;
+       ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd);
 
-       for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
-            i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
-               fd_data->pctype = i;
-               ret = i40e_program_fdir_filter(fd_data, pf, add);
-
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-                       err = true;
-               } else {
-                       dev_info(&pf->pdev->dev,
-                                "Filter OK for PCTYPE %d (ret = %d)\n",
-                                fd_data->pctype, ret);
-               }
-       }
-
-       return err ? -EOPNOTSUPP : 0;
+       i40e_fdir_check_and_reenable(pf);
+       return ret;
 }
 
 /**
- * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
- * a specific flow spec based on their protocol
+ * i40e_add_fdir_ethtool - Add/Remove Flow Director filters
  * @vsi: pointer to the targeted VSI
  * @cmd: command to get or set RX flow classification rules
- * @add: true adds a filter, false removes it
  *
- * Returns 0 if the filters were successfully added or removed
+ * Add Flow Director filters for a specific flow spec based on their
+ * protocol.  Returns 0 if the filters were successfully added.
  **/
-static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
-                       struct ethtool_rxnfc *cmd, bool add)
+static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
+                                struct ethtool_rxnfc *cmd)
 {
-       struct i40e_fdir_data fd_data;
-       int ret = -EINVAL;
+       struct ethtool_rx_flow_spec *fsp;
+       struct i40e_fdir_filter *input;
        struct i40e_pf *pf;
-       struct ethtool_rx_flow_spec *fsp =
-               (struct ethtool_rx_flow_spec *)&cmd->fs;
+       int ret = -EINVAL;
 
        if (!vsi)
                return -EINVAL;
 
        pf = vsi->back;
 
-       if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
-           (fsp->ring_cookie >= vsi->num_queue_pairs))
-               return -EINVAL;
+       if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               return -EOPNOTSUPP;
 
-       /* Populate the Flow Director that we have at the moment
-        * and allocate the raw packet buffer for the calling functions
-        */
-       fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
-                                    GFP_KERNEL);
+       if (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)
+               return -ENOSPC;
 
-       if (!fd_data.raw_packet) {
-               dev_info(&pf->pdev->dev, "Could not allocate memory\n");
-               return -ENOMEM;
+       fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+       if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort +
+                             pf->hw.func_caps.fd_filters_guaranteed)) {
+               return -EINVAL;
        }
 
-       fd_data.q_index = fsp->ring_cookie;
-       fd_data.flex_off = 0;
-       fd_data.pctype = 0;
-       fd_data.dest_vsi = vsi->id;
-       fd_data.dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
-       fd_data.fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
-       fd_data.cnt_index = 0;
-       fd_data.fd_id = 0;
+       if (fsp->ring_cookie >= vsi->num_queue_pairs)
+               return -EINVAL;
 
-       switch (fsp->flow_type & ~FLOW_EXT) {
-       case TCP_V4_FLOW:
-               ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
-               break;
-       case UDP_V4_FLOW:
-               ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
-               break;
-       case SCTP_V4_FLOW:
-               ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
-               break;
-       case IPV4_FLOW:
-               ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
-               break;
-       case IP_USER_FLOW:
-               switch (fsp->h_u.usr_ip4_spec.proto) {
-               case IPPROTO_TCP:
-                       ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
-                       break;
-               case IPPROTO_UDP:
-                       ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
-                       break;
-               case IPPROTO_SCTP:
-                       ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
-                       break;
-               default:
-                       ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
-                       break;
-               }
-               break;
-       default:
-               dev_info(&pf->pdev->dev, "Could not specify spec type\n");
-               ret = -EINVAL;
-       }
+       input = kzalloc(sizeof(*input), GFP_KERNEL);
+
+       if (!input)
+               return -ENOMEM;
 
-       kfree(fd_data.raw_packet);
-       fd_data.raw_packet = NULL;
+       input->fd_id = fsp->location;
+
+       if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
+               input->dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;
+       else
+               input->dest_ctl =
+                            I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX;
+
+       input->q_index = fsp->ring_cookie;
+       input->flex_off = 0;
+       input->pctype = 0;
+       input->dest_vsi = vsi->id;
+       input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID;
+       input->cnt_index = 0;
+       input->flow_type = fsp->flow_type;
+       input->ip4_proto = fsp->h_u.usr_ip4_spec.proto;
+       input->src_port = fsp->h_u.tcp_ip4_spec.psrc;
+       input->dst_port = fsp->h_u.tcp_ip4_spec.pdst;
+       input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
+       input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
+
+       ret = i40e_add_del_fdir(vsi, input, true);
+       if (ret)
+               kfree(input);
+       else
+               i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL);
 
        return ret;
 }
@@ -1580,10 +1560,10 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
                ret = i40e_set_rss_hash_opt(pf, cmd);
                break;
        case ETHTOOL_SRXCLSRLINS:
-               ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
+               ret = i40e_add_fdir_ethtool(vsi, cmd);
                break;
        case ETHTOOL_SRXCLSRLDEL:
-               ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
+               ret = i40e_del_fdir_entry(vsi, cmd);
                break;
        default:
                break;
index b901371ca361a1e6eafa411f5b144f6e8866aa9c..a1ec793b93db234ab3144066c558c93236b21184 100644 (file)
@@ -26,6 +26,7 @@
 
 /* Local includes */
 #include "i40e.h"
+#include "i40e_diag.h"
 #ifdef CONFIG_I40E_VXLAN
 #include <net/vxlan.h>
 #endif
@@ -38,7 +39,7 @@ static const char i40e_driver_string[] =
 
 #define DRV_VERSION_MAJOR 0
 #define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 30
+#define DRV_VERSION_BUILD 36
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -305,6 +306,7 @@ static void i40e_tx_timeout(struct net_device *netdev)
                break;
        default:
                netdev_err(netdev, "tx_timeout recovery unsuccessful\n");
+               set_bit(__I40E_DOWN, &vsi->state);
                i40e_down(vsi);
                break;
        }
@@ -375,20 +377,20 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
                        continue;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&tx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
                        packets = tx_ring->stats.packets;
                        bytes   = tx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&tx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
 
                stats->tx_packets += packets;
                stats->tx_bytes   += bytes;
                rx_ring = &tx_ring[1];
 
                do {
-                       start = u64_stats_fetch_begin_bh(&rx_ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
                        packets = rx_ring->stats.packets;
                        bytes   = rx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&rx_ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
 
                stats->rx_packets += packets;
                stats->rx_bytes   += bytes;
@@ -739,6 +741,7 @@ void i40e_update_stats(struct i40e_vsi *vsi)
        u32 rx_page, rx_buf;
        u64 rx_p, rx_b;
        u64 tx_p, tx_b;
+       u32 val;
        int i;
        u16 q;
 
@@ -769,10 +772,10 @@ void i40e_update_stats(struct i40e_vsi *vsi)
                p = ACCESS_ONCE(vsi->tx_rings[q]);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        packets = p->stats.packets;
                        bytes = p->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
                tx_b += bytes;
                tx_p += packets;
                tx_restart += p->tx_stats.restart_queue;
@@ -781,10 +784,10 @@ void i40e_update_stats(struct i40e_vsi *vsi)
                /* Rx queue is part of the same block as Tx queue */
                p = &p[1];
                do {
-                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        packets = p->stats.packets;
                        bytes = p->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
                rx_b += bytes;
                rx_p += packets;
                rx_buf += p->rx_stats.alloc_buff_failed;
@@ -971,6 +974,20 @@ void i40e_update_stats(struct i40e_vsi *vsi)
                i40e_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
                                   pf->stat_offsets_loaded,
                                   &osd->rx_jabber, &nsd->rx_jabber);
+
+               val = rd32(hw, I40E_PRTPM_EEE_STAT);
+               nsd->tx_lpi_status =
+                              (val & I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK) >>
+                               I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT;
+               nsd->rx_lpi_status =
+                              (val & I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK) >>
+                               I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT;
+               i40e_stat_update32(hw, I40E_PRTPM_TLPIC,
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_lpi_count, &nsd->tx_lpi_count);
+               i40e_stat_update32(hw, I40E_PRTPM_RLPIC,
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_lpi_count, &nsd->rx_lpi_count);
        }
 
        pf->stat_offsets_loaded = true;
@@ -1964,11 +1981,14 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
 
        netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid);
 
-       /* If the network stack called us with vid = 0, we should
-        * indicate to i40e_vsi_add_vlan() that we want to receive
-        * any traffic (i.e. with any vlan tag, or untagged)
+       /* If the network stack called us with vid = 0 then
+        * it is asking to receive priority tagged packets with
+        * vlan id 0.  Our HW receives them by default when configured
+        * to receive untagged packets so there is no need to add an
+        * extra filter for vlan 0 tagged packets.
         */
-       ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY);
+       if (vid)
+               ret = i40e_vsi_add_vlan(vsi, vid);
 
        if (!ret && (vid < VLAN_N_VID))
                set_bit(vid, vsi->active_vlans);
@@ -1981,7 +2001,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
  * @netdev: network interface to be adjusted
  * @vid: vlan id to be removed
  *
- * net_device_ops implementation for adding vlan ids
+ * net_device_ops implementation for removing vlan ids
  **/
 static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
                                 __always_unused __be16 proto, u16 vid)
@@ -2177,6 +2197,11 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
        tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FD_SB_ENABLED |
                                               I40E_FLAG_FD_ATR_ENABLED));
        tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP);
+       /* FDIR VSI tx ring can still use RS bit and writebacks */
+       if (vsi->type != I40E_VSI_FDIR)
+               tx_ctx.head_wb_ena = 1;
+       tx_ctx.head_wb_addr = ring->dma +
+                             (ring->count * sizeof(struct i40e_tx_desc));
 
        /* As part of VSI creation/update, FW allocates certain
         * Tx arbitration queue sets for each TC enabled for
@@ -2419,6 +2444,28 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
                i40e_set_rx_mode(vsi->netdev);
 }
 
+/**
+ * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters
+ * @vsi: Pointer to the targeted VSI
+ *
+ * This function replays the hlist on the hw where all the SB Flow Director
+ * filters were saved.
+ **/
+static void i40e_fdir_filter_restore(struct i40e_vsi *vsi)
+{
+       struct i40e_fdir_filter *filter;
+       struct i40e_pf *pf = vsi->back;
+       struct hlist_node *node;
+
+       if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               return;
+
+       hlist_for_each_entry_safe(filter, node,
+                                 &pf->fdir_filter_list, fdir_node) {
+               i40e_add_del_fdir(vsi, filter, true);
+       }
+}
+
 /**
  * i40e_vsi_configure - Set up the VSI for action
  * @vsi: the VSI being configured
@@ -2557,7 +2604,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
        /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
        wr32(hw, I40E_PFINT_LNKLST0, 0);
 
-       /* Associate the queue pair to the vector and enable the q int */
+       /* Associate the queue pair to the vector and enable the queue int */
        val = I40E_QINT_RQCTL_CAUSE_ENA_MASK                  |
              (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
              (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
@@ -2831,12 +2878,14 @@ static irqreturn_t i40e_intr(int irq, void *data)
                val = rd32(hw, I40E_GLGEN_RSTAT);
                val = (val & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
                       >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
-               if (val == I40E_RESET_CORER)
+               if (val == I40E_RESET_CORER) {
                        pf->corer_count++;
-               else if (val == I40E_RESET_GLOBR)
+               } else if (val == I40E_RESET_GLOBR) {
                        pf->globr_count++;
-               else if (val == I40E_RESET_EMPR)
+               } else if (val == I40E_RESET_EMPR) {
                        pf->empr_count++;
+                       set_bit(__I40E_EMP_RESET_REQUESTED, &pf->state);
+               }
        }
 
        if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK) {
@@ -2866,8 +2915,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
                         icr0_remaining);
                if ((icr0_remaining & I40E_PFINT_ICR0_PE_CRITERR_MASK) ||
                    (icr0_remaining & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) ||
-                   (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK) ||
-                   (icr0_remaining & I40E_PFINT_ICR0_MAL_DETECT_MASK)) {
+                   (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK)) {
                        dev_info(&pf->pdev->dev, "device will be reset\n");
                        set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
                        i40e_service_event_schedule(pf);
@@ -3107,13 +3155,13 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
 
        pf_q = vsi->base_queue;
        for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
-               j = 1000;
-               do {
-                       usleep_range(1000, 2000);
+               for (j = 0; j < 50; j++) {
                        tx_reg = rd32(hw, I40E_QTX_ENA(pf_q));
-               } while (j-- && ((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT)
-                              ^ (tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT)) & 1);
-
+                       if (((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT) & 1) ==
+                           ((tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT) & 1))
+                               break;
+                       usleep_range(1000, 2000);
+               }
                /* Skip if the queue is already in the requested state */
                if (enable && (tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
                        continue;
@@ -3123,8 +3171,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
                /* turn on/off the queue */
                if (enable) {
                        wr32(hw, I40E_QTX_HEAD(pf_q), 0);
-                       tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK |
-                                 I40E_QTX_ENA_QENA_STAT_MASK;
+                       tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK;
                } else {
                        tx_reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
                }
@@ -3171,12 +3218,13 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
 
        pf_q = vsi->base_queue;
        for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
-               j = 1000;
-               do {
-                       usleep_range(1000, 2000);
+               for (j = 0; j < 50; j++) {
                        rx_reg = rd32(hw, I40E_QRX_ENA(pf_q));
-               } while (j-- && ((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT)
-                              ^ (rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT)) & 1);
+                       if (((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT) & 1) ==
+                           ((rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT) & 1))
+                               break;
+                       usleep_range(1000, 2000);
+               }
 
                if (enable) {
                        /* is STAT set ? */
@@ -3190,11 +3238,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
 
                /* turn on/off the queue */
                if (enable)
-                       rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK |
-                                 I40E_QRX_ENA_QENA_STAT_MASK;
+                       rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK;
                else
-                       rx_reg &= ~(I40E_QRX_ENA_QENA_REQ_MASK |
-                                 I40E_QRX_ENA_QENA_STAT_MASK);
+                       rx_reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
                wr32(hw, I40E_QRX_ENA(pf_q), rx_reg);
 
                /* wait for the change to finish */
@@ -3732,8 +3778,8 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
                                          NULL);
        if (aq_ret) {
                dev_info(&vsi->back->pdev->dev,
-                        "%s: AQ command Config VSI BW allocation per TC failed = %d\n",
-                        __func__, vsi->back->hw.aq.asq_last_status);
+                        "AQ command Config VSI BW allocation per TC failed = %d\n",
+                        vsi->back->hw.aq.asq_last_status);
                return -EINVAL;
        }
 
@@ -4062,6 +4108,10 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
        } else if (vsi->netdev) {
                netdev_info(vsi->netdev, "NIC Link is Down\n");
        }
+
+       /* replay FDIR SB filters */
+       if (vsi->type == I40E_VSI_FDIR)
+               i40e_fdir_filter_restore(vsi);
        i40e_service_event_schedule(pf);
 
        return 0;
@@ -4208,15 +4258,40 @@ static int i40e_open(struct net_device *netdev)
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
-       char int_name[IFNAMSIZ];
        int err;
 
-       /* disallow open during test */
-       if (test_bit(__I40E_TESTING, &pf->state))
+       /* disallow open during test or if eeprom is broken */
+       if (test_bit(__I40E_TESTING, &pf->state) ||
+           test_bit(__I40E_BAD_EEPROM, &pf->state))
                return -EBUSY;
 
        netif_carrier_off(netdev);
 
+       err = i40e_vsi_open(vsi);
+       if (err)
+               return err;
+
+#ifdef CONFIG_I40E_VXLAN
+       vxlan_get_rx_port(netdev);
+#endif
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_open -
+ * @vsi: the VSI to open
+ *
+ * Finish initialization of the VSI.
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+int i40e_vsi_open(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       char int_name[IFNAMSIZ];
+       int err;
+
        /* allocate descriptors */
        err = i40e_vsi_setup_tx_resources(vsi);
        if (err)
@@ -4229,18 +4304,22 @@ static int i40e_open(struct net_device *netdev)
        if (err)
                goto err_setup_rx;
 
+       if (!vsi->netdev) {
+               err = EINVAL;
+               goto err_setup_rx;
+       }
        snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
-                dev_driver_string(&pf->pdev->dev), netdev->name);
+                dev_driver_string(&pf->pdev->dev), vsi->netdev->name);
        err = i40e_vsi_request_irq(vsi, int_name);
        if (err)
                goto err_setup_rx;
 
        /* Notify the stack of the actual queue counts. */
-       err = netif_set_real_num_tx_queues(netdev, vsi->num_queue_pairs);
+       err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_queue_pairs);
        if (err)
                goto err_set_queues;
 
-       err = netif_set_real_num_rx_queues(netdev, vsi->num_queue_pairs);
+       err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_queue_pairs);
        if (err)
                goto err_set_queues;
 
@@ -4248,10 +4327,6 @@ static int i40e_open(struct net_device *netdev)
        if (err)
                goto err_up_complete;
 
-#ifdef CONFIG_I40E_VXLAN
-       vxlan_get_rx_port(netdev);
-#endif
-
        return 0;
 
 err_up_complete:
@@ -4268,6 +4343,26 @@ err_setup_tx:
        return err;
 }
 
+/**
+ * i40e_fdir_filter_exit - Cleans up the Flow Director accounting
+ * @pf: Pointer to pf
+ *
+ * This function destroys the hlist where all the Flow Director
+ * filters were saved.
+ **/
+static void i40e_fdir_filter_exit(struct i40e_pf *pf)
+{
+       struct i40e_fdir_filter *filter;
+       struct hlist_node *node2;
+
+       hlist_for_each_entry_safe(filter, node2,
+                                 &pf->fdir_filter_list, fdir_node) {
+               hlist_del(&filter->fdir_node);
+               kfree(filter);
+       }
+       pf->fdir_pf_active_filters = 0;
+}
+
 /**
  * i40e_close - Disables a network interface
  * @netdev: network interface device structure
@@ -4321,7 +4416,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
                 * for the warning interrupt will deal with the shutdown
                 * and recovery of the switch setup.
                 */
-               dev_info(&pf->pdev->dev, "GlobalR requested\n");
+               dev_dbg(&pf->pdev->dev, "GlobalR requested\n");
                val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
                val |= I40E_GLGEN_RTRIG_GLOBR_MASK;
                wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
@@ -4332,7 +4427,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
                 *
                 * Same as Global Reset, except does *not* include the MAC/PHY
                 */
-               dev_info(&pf->pdev->dev, "CoreR requested\n");
+               dev_dbg(&pf->pdev->dev, "CoreR requested\n");
                val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
                val |= I40E_GLGEN_RTRIG_CORER_MASK;
                wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
@@ -4366,7 +4461,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
                 * the switch, since we need to do all the recovery as
                 * for the Core Reset.
                 */
-               dev_info(&pf->pdev->dev, "PFR requested\n");
+               dev_dbg(&pf->pdev->dev, "PFR requested\n");
                i40e_handle_reset_warning(pf);
 
        } else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) {
@@ -4415,18 +4510,18 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                           &old_cfg->etscfg.prioritytable,
                           sizeof(new_cfg->etscfg.prioritytable))) {
                        need_reconfig = true;
-                       dev_info(&pf->pdev->dev, "ETS UP2TC changed.\n");
+                       dev_dbg(&pf->pdev->dev, "ETS UP2TC changed.\n");
                }
 
                if (memcmp(&new_cfg->etscfg.tcbwtable,
                           &old_cfg->etscfg.tcbwtable,
                           sizeof(new_cfg->etscfg.tcbwtable)))
-                       dev_info(&pf->pdev->dev, "ETS TC BW Table changed.\n");
+                       dev_dbg(&pf->pdev->dev, "ETS TC BW Table changed.\n");
 
                if (memcmp(&new_cfg->etscfg.tsatable,
                           &old_cfg->etscfg.tsatable,
                           sizeof(new_cfg->etscfg.tsatable)))
-                       dev_info(&pf->pdev->dev, "ETS TSA Table changed.\n");
+                       dev_dbg(&pf->pdev->dev, "ETS TSA Table changed.\n");
        }
 
        /* Check if PFC configuration has changed */
@@ -4434,7 +4529,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                   &old_cfg->pfc,
                   sizeof(new_cfg->pfc))) {
                need_reconfig = true;
-               dev_info(&pf->pdev->dev, "PFC config change detected.\n");
+               dev_dbg(&pf->pdev->dev, "PFC config change detected.\n");
        }
 
        /* Check if APP Table has changed */
@@ -4442,7 +4537,7 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
                   &old_cfg->app,
                   sizeof(new_cfg->app))) {
                need_reconfig = true;
-               dev_info(&pf->pdev->dev, "APP Table change detected.\n");
+               dev_dbg(&pf->pdev->dev, "APP Table change detected.\n");
        }
 
        return need_reconfig;
@@ -4492,7 +4587,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
 
        /* No change detected in DCBX configs */
        if (!memcmp(&tmp_dcbx_cfg, dcbx_cfg, sizeof(tmp_dcbx_cfg))) {
-               dev_info(&pf->pdev->dev, "No change detected in DCBX configuration.\n");
+               dev_dbg(&pf->pdev->dev, "No change detected in DCBX configuration.\n");
                goto exit;
        }
 
@@ -4550,8 +4645,8 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
        struct i40e_vf *vf;
        u16 vf_id;
 
-       dev_info(&pf->pdev->dev, "%s: Rx Queue Number = %d QTX_CTL=0x%08x\n",
-                __func__, queue, qtx_ctl);
+       dev_dbg(&pf->pdev->dev, "overflow Rx Queue Number = %d QTX_CTL=0x%08x\n",
+               queue, qtx_ctl);
 
        /* Queue belongs to VF, find the VF and issue VF reset */
        if (((qtx_ctl & I40E_QTX_CTL_PFVF_Q_MASK)
@@ -4580,6 +4675,54 @@ static void i40e_service_event_complete(struct i40e_pf *pf)
        clear_bit(__I40E_SERVICE_SCHED, &pf->state);
 }
 
+/**
+ * i40e_get_current_fd_count - Get the count of FD filters programmed in the HW
+ * @pf: board private structure
+ **/
+int i40e_get_current_fd_count(struct i40e_pf *pf)
+{
+       int val, fcnt_prog;
+       val = rd32(&pf->hw, I40E_PFQF_FDSTAT);
+       fcnt_prog = (val & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) +
+                   ((val & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >>
+                     I40E_PFQF_FDSTAT_BEST_CNT_SHIFT);
+       return fcnt_prog;
+}
+
+/**
+ * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
+ * @pf: board private structure
+ **/
+void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
+{
+       u32 fcnt_prog, fcnt_avail;
+
+       /* Check if, FD SB or ATR was auto disabled and if there is enough room
+        * to re-enable
+        */
+       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+           (pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               return;
+       fcnt_prog = i40e_get_current_fd_count(pf);
+       fcnt_avail = pf->hw.fdir_shared_filter_count +
+                                              pf->fdir_pf_filter_count;
+       if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) {
+               if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+                   (pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) {
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
+               }
+       }
+       /* Wait for some more space to be available to turn on ATR */
+       if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
+               if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+                   (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
+               }
+       }
+}
+
 /**
  * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
  * @pf: board private structure
@@ -4589,11 +4732,14 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
        if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
                return;
 
-       pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
-
        /* if interface is down do nothing */
        if (test_bit(__I40E_DOWN, &pf->state))
                return;
+       i40e_fdir_check_and_reenable(pf);
+
+       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+           (pf->flags & I40E_FLAG_FD_SB_ENABLED))
+               pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
 }
 
 /**
@@ -4903,7 +5049,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
                                        event.msg_size);
                        break;
                case i40e_aqc_opc_lldp_update_mib:
-                       dev_info(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
+                       dev_dbg(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
 #ifdef CONFIG_I40E_DCB
                        rtnl_lock();
                        ret = i40e_handle_lldp_event(pf, &event);
@@ -4911,7 +5057,7 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
 #endif /* CONFIG_I40E_DCB */
                        break;
                case i40e_aqc_opc_event_lan_overflow:
-                       dev_info(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
+                       dev_dbg(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
                        i40e_handle_lan_overflow_event(pf, &event);
                        break;
                case i40e_aqc_opc_send_msg_to_peer:
@@ -4935,6 +5081,31 @@ static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
        kfree(event.msg_buf);
 }
 
+/**
+ * i40e_verify_eeprom - make sure eeprom is good to use
+ * @pf: board private structure
+ **/
+static void i40e_verify_eeprom(struct i40e_pf *pf)
+{
+       int err;
+
+       err = i40e_diag_eeprom_test(&pf->hw);
+       if (err) {
+               /* retry in case of garbage read */
+               err = i40e_diag_eeprom_test(&pf->hw);
+               if (err) {
+                       dev_info(&pf->pdev->dev, "eeprom check failed (%d), Tx/Rx traffic disabled\n",
+                                err);
+                       set_bit(__I40E_BAD_EEPROM, &pf->state);
+               }
+       }
+
+       if (!err && test_bit(__I40E_BAD_EEPROM, &pf->state)) {
+               dev_info(&pf->pdev->dev, "eeprom check passed, Tx/Rx traffic enabled\n");
+               clear_bit(__I40E_BAD_EEPROM, &pf->state);
+       }
+}
+
 /**
  * i40e_reconstitute_veb - rebuild the VEB and anything connected to it
  * @veb: pointer to the VEB instance
@@ -5053,6 +5224,12 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
        /* increment MSI-X count because current FW skips one */
        pf->hw.func_caps.num_msix_vectors++;
 
+       if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) ||
+           (pf->hw.aq.fw_maj_ver < 2)) {
+               pf->hw.func_caps.num_msix_vectors++;
+               pf->hw.func_caps.num_msix_vectors_vf++;
+       }
+
        if (pf->hw.debug_mask & I40E_DEBUG_USER)
                dev_info(&pf->pdev->dev,
                         "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
@@ -5132,9 +5309,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
                err = i40e_up_complete(vsi);
                if (err)
                        goto err_up_complete;
+               clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
        }
 
-       clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
        return;
 
 err_up_complete:
@@ -5157,6 +5334,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
 {
        int i;
 
+       i40e_fdir_filter_exit(pf);
        for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
                if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
                        i40e_vsi_release(pf->vsi[i]);
@@ -5181,7 +5359,7 @@ static int i40e_prep_for_reset(struct i40e_pf *pf)
        if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
                return 0;
 
-       dev_info(&pf->pdev->dev, "Tearing down internal switch for reset\n");
+       dev_dbg(&pf->pdev->dev, "Tearing down internal switch for reset\n");
 
        if (i40e_check_asq_alive(hw))
                i40e_vc_notify_reset(pf);
@@ -5228,7 +5406,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
 
        if (test_bit(__I40E_DOWN, &pf->state))
                goto end_core_reset;
-       dev_info(&pf->pdev->dev, "Rebuilding internal switch\n");
+       dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
        /* rebuild the basics for the AdminQ, HMC, and initial HW switch */
        ret = i40e_init_adminq(&pf->hw);
@@ -5237,6 +5415,12 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
                goto end_core_reset;
        }
 
+       /* re-verify the eeprom if we just had an EMP reset */
+       if (test_bit(__I40E_EMP_RESET_REQUESTED, &pf->state)) {
+               clear_bit(__I40E_EMP_RESET_REQUESTED, &pf->state);
+               i40e_verify_eeprom(pf);
+       }
+
        ret = i40e_get_capabilities(pf);
        if (ret) {
                dev_info(&pf->pdev->dev, "i40e_get_capabilities failed, %d\n",
@@ -5278,7 +5462,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
         * try to recover minimal use by getting the basic PF VSI working.
         */
        if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) {
-               dev_info(&pf->pdev->dev, "attempting to rebuild switch\n");
+               dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
                /* find the one VEB connected to the MAC, and find orphans */
                for (v = 0; v < I40E_MAX_VEB; v++) {
                        if (!pf->veb[v])
@@ -5331,6 +5515,11 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        /* restart the VSIs that were rebuilt and running before the reset */
        i40e_pf_unquiesce_all_vsi(pf);
 
+       if (pf->num_alloc_vfs) {
+               for (v = 0; v < pf->num_alloc_vfs; v++)
+                       i40e_reset_vf(&pf->vf[v], true);
+       }
+
        /* tell the firmware that we're starting */
        dv.major_version = DRV_VERSION_MAJOR;
        dv.minor_version = DRV_VERSION_MINOR;
@@ -5338,7 +5527,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        dv.subbuild_version = 0;
        i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
 
-       dev_info(&pf->pdev->dev, "PF reset done\n");
+       dev_info(&pf->pdev->dev, "reset complete\n");
 
 end_core_reset:
        clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state);
@@ -5387,7 +5576,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK)
                                >> I40E_GL_MDET_TX_QUEUE_SHIFT;
                dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection TX event 0x%02x on q %d of function 0x%02x\n",
+                        "Malicious Driver Detection event 0x%02x on TX queue %d of function 0x%02x\n",
                         event, queue, func);
                wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
                mdd_detected = true;
@@ -5401,7 +5590,7 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
                u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK)
                                >> I40E_GL_MDET_RX_QUEUE_SHIFT;
                dev_info(&pf->pdev->dev,
-                        "Malicious Driver Detection RX event 0x%02x on q %d of function 0x%02x\n",
+                        "Malicious Driver Detection event 0x%02x on RX queue %d of function 0x%02x\n",
                         event, queue, func);
                wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
                mdd_detected = true;
@@ -5850,37 +6039,16 @@ err_out:
  **/
 static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors)
 {
-       int err = 0;
-
-       pf->num_msix_entries = 0;
-       while (vectors >= I40E_MIN_MSIX) {
-               err = pci_enable_msix(pf->pdev, pf->msix_entries, vectors);
-               if (err == 0) {
-                       /* good to go */
-                       pf->num_msix_entries = vectors;
-                       break;
-               } else if (err < 0) {
-                       /* total failure */
-                       dev_info(&pf->pdev->dev,
-                                "MSI-X vector reservation failed: %d\n", err);
-                       vectors = 0;
-                       break;
-               } else {
-                       /* err > 0 is the hint for retry */
-                       dev_info(&pf->pdev->dev,
-                                "MSI-X vectors wanted %d, retrying with %d\n",
-                                vectors, err);
-                       vectors = err;
-               }
-       }
-
-       if (vectors > 0 && vectors < I40E_MIN_MSIX) {
+       vectors = pci_enable_msix_range(pf->pdev, pf->msix_entries,
+                                       I40E_MIN_MSIX, vectors);
+       if (vectors < 0) {
                dev_info(&pf->pdev->dev,
-                        "Couldn't get enough vectors, only %d available\n",
-                        vectors);
+                        "MSI-X vector reservation failed: %d\n", vectors);
                vectors = 0;
        }
 
+       pf->num_msix_entries = vectors;
+
        return vectors;
 }
 
@@ -5942,7 +6110,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
 
        } else if (vec == I40E_MIN_MSIX) {
                /* Adjust for minimal MSIX use */
-               dev_info(&pf->pdev->dev, "Features disabled, not enough MSIX vectors\n");
+               dev_info(&pf->pdev->dev, "Features disabled, not enough MSI-X vectors\n");
                pf->flags &= ~I40E_FLAG_VMDQ_ENABLED;
                pf->num_vmdq_vsis = 0;
                pf->num_vmdq_qps = 0;
@@ -5978,13 +6146,13 @@ static int i40e_init_msix(struct i40e_pf *pf)
 }
 
 /**
- * i40e_alloc_q_vector - Allocate memory for a single interrupt vector
+ * i40e_vsi_alloc_q_vector - Allocate memory for a single interrupt vector
  * @vsi: the VSI being configured
  * @v_idx: index of the vector in the vsi struct
  *
  * We allocate one q_vector.  If allocation fails we return -ENOMEM.
  **/
-static int i40e_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
+static int i40e_vsi_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
 {
        struct i40e_q_vector *q_vector;
 
@@ -6010,13 +6178,13 @@ static int i40e_alloc_q_vector(struct i40e_vsi *vsi, int v_idx)
 }
 
 /**
- * i40e_alloc_q_vectors - Allocate memory for interrupt vectors
+ * i40e_vsi_alloc_q_vectors - Allocate memory for interrupt vectors
  * @vsi: the VSI being configured
  *
  * We allocate one q_vector per queue interrupt.  If allocation fails we
  * return -ENOMEM.
  **/
-static int i40e_alloc_q_vectors(struct i40e_vsi *vsi)
+static int i40e_vsi_alloc_q_vectors(struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = vsi->back;
        int v_idx, num_q_vectors;
@@ -6031,7 +6199,7 @@ static int i40e_alloc_q_vectors(struct i40e_vsi *vsi)
                return -EINVAL;
 
        for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
-               err = i40e_alloc_q_vector(vsi, v_idx);
+               err = i40e_vsi_alloc_q_vector(vsi, v_idx);
                if (err)
                        goto err_out;
        }
@@ -6071,7 +6239,7 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf)
 
        if (!(pf->flags & I40E_FLAG_MSIX_ENABLED) &&
            (pf->flags & I40E_FLAG_MSI_ENABLED)) {
-               dev_info(&pf->pdev->dev, "MSIX not available, trying MSI\n");
+               dev_info(&pf->pdev->dev, "MSI-X not available, trying MSI\n");
                err = pci_enable_msi(pf->pdev);
                if (err) {
                        dev_info(&pf->pdev->dev, "MSI init failed - %d\n", err);
@@ -6080,7 +6248,7 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf)
        }
 
        if (!(pf->flags & (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED)))
-               dev_info(&pf->pdev->dev, "MSIX and MSI not available, falling back to Legacy IRQ\n");
+               dev_info(&pf->pdev->dev, "MSI-X and MSI not available, falling back to Legacy IRQ\n");
 
        /* track first vector for misc interrupts */
        err = i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT-1);
@@ -6107,7 +6275,8 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
                                  i40e_intr, 0, pf->misc_int_name, pf);
                if (err) {
                        dev_info(&pf->pdev->dev,
-                                "request_irq for msix_misc failed: %d\n", err);
+                                "request_irq for %s failed: %d\n",
+                                pf->misc_int_name, err);
                        return -EFAULT;
                }
        }
@@ -6258,15 +6427,11 @@ static int i40e_sw_init(struct i40e_pf *pf)
            (pf->hw.func_caps.fd_filters_best_effort > 0)) {
                pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
                pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
-               dev_info(&pf->pdev->dev,
-                       "Flow Director ATR mode Enabled\n");
                if (!(pf->flags & I40E_FLAG_MFP_ENABLED)) {
                        pf->flags |= I40E_FLAG_FD_SB_ENABLED;
-                       dev_info(&pf->pdev->dev,
-                                "Flow Director Side Band mode Enabled\n");
                } else {
                        dev_info(&pf->pdev->dev,
-                                "Flow Director Side Band mode Disabled in MFP mode\n");
+                                "Flow Director Sideband mode Disabled in MFP mode\n");
                }
                pf->fdir_pf_filter_count =
                                 pf->hw.func_caps.fd_filters_guaranteed;
@@ -6287,9 +6452,6 @@ static int i40e_sw_init(struct i40e_pf *pf)
                pf->num_req_vfs = min_t(int,
                                        pf->hw.func_caps.num_vfs,
                                        I40E_MAX_VF_COUNT);
-               dev_info(&pf->pdev->dev,
-                        "Number of VFs being requested for PF[%d] = %d\n",
-                        pf->hw.pf_id, pf->num_req_vfs);
        }
 #endif /* CONFIG_PCI_IOV */
        pf->eeprom_version = 0xDEAD;
@@ -6325,6 +6487,39 @@ sw_init_done:
        return err;
 }
 
+/**
+ * i40e_set_ntuple - set the ntuple feature flag and take action
+ * @pf: board private structure to initialize
+ * @features: the feature set that the stack is suggesting
+ *
+ * returns a bool to indicate if reset needs to happen
+ **/
+bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
+{
+       bool need_reset = false;
+
+       /* Check if Flow Director n-tuple support was enabled or disabled.  If
+        * the state changed, we need to reset.
+        */
+       if (features & NETIF_F_NTUPLE) {
+               /* Enable filters and mark for reset */
+               if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
+                       need_reset = true;
+               pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+       } else {
+               /* turn off filters, mark for reset and clear SW filter list */
+               if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+                       need_reset = true;
+                       i40e_fdir_filter_exit(pf);
+               }
+               pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+               /* if ATR was disabled it can be re-enabled. */
+               if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
+                       pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+       }
+       return need_reset;
+}
+
 /**
  * i40e_set_features - set the netdev feature flags
  * @netdev: ptr to the netdev being adjusted
@@ -6335,12 +6530,19 @@ static int i40e_set_features(struct net_device *netdev,
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       bool need_reset;
 
        if (features & NETIF_F_HW_VLAN_CTAG_RX)
                i40e_vlan_stripping_enable(vsi);
        else
                i40e_vlan_stripping_disable(vsi);
 
+       need_reset = i40e_set_ntuple(pf, features);
+
+       if (need_reset)
+               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+
        return 0;
 }
 
@@ -6464,6 +6666,7 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_set_vf_vlan        = i40e_ndo_set_vf_port_vlan,
        .ndo_set_vf_tx_rate     = i40e_ndo_set_vf_bw,
        .ndo_get_vf_config      = i40e_ndo_get_vf_config,
+       .ndo_set_vf_link_state  = i40e_ndo_set_vf_link_state,
 #ifdef CONFIG_I40E_VXLAN
        .ndo_add_vxlan_port     = i40e_add_vxlan_port,
        .ndo_del_vxlan_port     = i40e_del_vxlan_port,
@@ -6495,10 +6698,9 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        np = netdev_priv(netdev);
        np->vsi = vsi;
 
-       netdev->hw_enc_features = NETIF_F_IP_CSUM        |
+       netdev->hw_enc_features |= NETIF_F_IP_CSUM       |
                                  NETIF_F_GSO_UDP_TUNNEL |
-                                 NETIF_F_TSO            |
-                                 NETIF_F_SG;
+                                 NETIF_F_TSO;
 
        netdev->features = NETIF_F_SG                  |
                           NETIF_F_IP_CSUM             |
@@ -6512,6 +6714,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
                           NETIF_F_TSO                 |
                           NETIF_F_TSO6                |
                           NETIF_F_RXCSUM              |
+                          NETIF_F_NTUPLE              |
                           NETIF_F_RXHASH              |
                           0;
 
@@ -6771,8 +6974,6 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
                        if (vsi->netdev) {
                                /* results in a call to i40e_close() */
                                unregister_netdev(vsi->netdev);
-                               free_netdev(vsi->netdev);
-                               vsi->netdev = NULL;
                        }
                } else {
                        if (!test_and_set_bit(__I40E_DOWN, &vsi->state))
@@ -6791,6 +6992,10 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
 
        i40e_vsi_delete(vsi);
        i40e_vsi_free_q_vectors(vsi);
+       if (vsi->netdev) {
+               free_netdev(vsi->netdev);
+               vsi->netdev = NULL;
+       }
        i40e_vsi_clear_rings(vsi);
        i40e_vsi_clear(vsi);
 
@@ -6845,13 +7050,12 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
        }
 
        if (vsi->base_vector) {
-               dev_info(&pf->pdev->dev,
-                        "VSI %d has non-zero base vector %d\n",
+               dev_info(&pf->pdev->dev, "VSI %d has non-zero base vector %d\n",
                         vsi->seid, vsi->base_vector);
                return -EEXIST;
        }
 
-       ret = i40e_alloc_q_vectors(vsi);
+       ret = i40e_vsi_alloc_q_vectors(vsi);
        if (ret) {
                dev_info(&pf->pdev->dev,
                         "failed to allocate %d q_vector for VSI %d, ret=%d\n",
@@ -6865,7 +7069,7 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
                                                 vsi->num_q_vectors, vsi->idx);
        if (vsi->base_vector < 0) {
                dev_info(&pf->pdev->dev,
-                        "failed to get q tracking for VSI %d, err=%d\n",
+                        "failed to get queue tracking for VSI %d, err=%d\n",
                         vsi->seid, vsi->base_vector);
                i40e_vsi_free_q_vectors(vsi);
                ret = -ENOENT;
@@ -7822,6 +8026,44 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf)
        return 0;
 }
 
+#define INFO_STRING_LEN 255
+static void i40e_print_features(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       char *buf, *string;
+
+       string = kzalloc(INFO_STRING_LEN, GFP_KERNEL);
+       if (!string) {
+               dev_err(&pf->pdev->dev, "Features string allocation failed\n");
+               return;
+       }
+
+       buf = string;
+
+       buf += sprintf(string, "Features: PF-id[%d] ", hw->pf_id);
+#ifdef CONFIG_PCI_IOV
+       buf += sprintf(buf, "VFs: %d ", pf->num_req_vfs);
+#endif
+       buf += sprintf(buf, "VSIs: %d QP: %d ", pf->hw.func_caps.num_vsis,
+                      pf->vsi[pf->lan_vsi]->num_queue_pairs);
+
+       if (pf->flags & I40E_FLAG_RSS_ENABLED)
+               buf += sprintf(buf, "RSS ");
+       buf += sprintf(buf, "FDir ");
+       if (pf->flags & I40E_FLAG_FD_ATR_ENABLED)
+               buf += sprintf(buf, "ATR ");
+       if (pf->flags & I40E_FLAG_FD_SB_ENABLED)
+               buf += sprintf(buf, "NTUPLE ");
+       if (pf->flags & I40E_FLAG_DCB_ENABLED)
+               buf += sprintf(buf, "DCB ");
+       if (pf->flags & I40E_FLAG_PTP)
+               buf += sprintf(buf, "PTP ");
+
+       BUG_ON(buf > (string + INFO_STRING_LEN));
+       dev_info(&pf->pdev->dev, "%s\n", string);
+       kfree(string);
+}
+
 /**
  * i40e_probe - Device initialization routine
  * @pdev: PCI device information struct
@@ -7848,16 +8090,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                return err;
 
        /* set up for high or low dma */
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-               /* coherent mask for the same size will always succeed if
-                * dma_set_mask does
-                */
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-       } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       } else {
-               dev_err(&pdev->dev, "DMA configuration failed: %d\n", err);
-               err = -EIO;
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+       if (err)
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pdev->dev,
+                       "DMA configuration failed: 0x%x\n", err);
                goto err_dma;
        }
 
@@ -7946,13 +8184,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        err = i40e_init_adminq(hw);
        dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw));
-       if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
-                >> I40E_NVM_VERSION_HI_SHIFT) != I40E_CURRENT_NVM_VERSION_HI) {
-               dev_info(&pdev->dev,
-                        "warning: NVM version not supported, supported version: %02x.%02x\n",
-                        I40E_CURRENT_NVM_VERSION_HI,
-                        I40E_CURRENT_NVM_VERSION_LO);
-       }
        if (err) {
                dev_info(&pdev->dev,
                         "init_adminq failed: %d expecting API %02x.%02x\n",
@@ -7961,6 +8192,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_pf_reset;
        }
 
+       i40e_verify_eeprom(pf);
+
        i40e_clear_pxe_mode(hw);
        err = i40e_get_capabilities(pf);
        if (err)
@@ -8062,7 +8295,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* prep for VF support */
        if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
-           (pf->flags & I40E_FLAG_MSIX_ENABLED)) {
+           (pf->flags & I40E_FLAG_MSIX_ENABLED) &&
+           !test_bit(__I40E_BAD_EEPROM, &pf->state)) {
                u32 val;
 
                /* disable link interrupts for VFs */
@@ -8070,6 +8304,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
                wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
                i40e_flush(hw);
+
+               if (pci_num_vf(pdev)) {
+                       dev_info(&pdev->dev,
+                                "Active VFs found, allocating resources.\n");
+                       err = i40e_alloc_vfs(pf, pci_num_vf(pdev));
+                       if (err)
+                               dev_info(&pdev->dev,
+                                        "Error %d allocating resources for existing VFs\n",
+                                        err);
+               }
        }
 
        pfs_found++;
@@ -8092,7 +8336,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        i40e_set_pci_config_data(hw, link_status);
 
-       dev_info(&pdev->dev, "PCI Express: %s %s\n",
+       dev_info(&pdev->dev, "PCI-Express: %s %s\n",
                (hw->bus.speed == i40e_bus_speed_8000 ? "Speed 8.0GT/s" :
                 hw->bus.speed == i40e_bus_speed_5000 ? "Speed 5.0GT/s" :
                 hw->bus.speed == i40e_bus_speed_2500 ? "Speed 2.5GT/s" :
@@ -8109,6 +8353,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_warn(&pdev->dev, "Please move the device to a different PCI-e link with more lanes and/or higher transfer rate.\n");
        }
 
+       /* print a string summarizing features */
+       i40e_print_features(pf);
+
        return 0;
 
        /* Unwind what we've done if something failed in the setup */
@@ -8165,16 +8412,16 @@ static void i40e_remove(struct pci_dev *pdev)
 
        i40e_ptp_stop(pf);
 
-       if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
-               i40e_free_vfs(pf);
-               pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
-       }
-
        /* no more scheduling of any task */
        set_bit(__I40E_DOWN, &pf->state);
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
 
+       if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
+               i40e_free_vfs(pf);
+               pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
+       }
+
        i40e_fdir_teardown(pf);
 
        /* If there is a switch structure or any orphans, remove them.
index 73f95b081927c13413f7a006a6638195b3929507..262bdf11d221e5a30be53a2f57a09e1865b32e79 100644 (file)
 #include "i40e_prototype.h"
 
 /**
- *  i40e_init_nvm_ops - Initialize NVM function pointers.
- *  @hw: pointer to the HW structure.
+ * i40e_init_nvm_ops - Initialize NVM function pointers
+ * @hw: pointer to the HW structure
  *
- *  Setups the function pointers and the NVM info structure. Should be called
- *  once per NVM initialization, e.g. inside the i40e_init_shared_code().
- *  Please notice that the NVM term is used here (& in all methods covered
- *  in this file) as an equivalent of the FLASH part mapped into the SR.
- *  We are accessing FLASH always thru the Shadow RAM.
+ * Setup the function pointers and the NVM info structure. Should be called
+ * once per NVM initialization, e.g. inside the i40e_init_shared_code().
+ * Please notice that the NVM term is used here (& in all methods covered
+ * in this file) as an equivalent of the FLASH part mapped into the SR.
+ * We are accessing FLASH always thru the Shadow RAM.
  **/
 i40e_status i40e_init_nvm(struct i40e_hw *hw)
 {
@@ -49,16 +49,16 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw)
        gens = rd32(hw, I40E_GLNVM_GENS);
        sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
                           I40E_GLNVM_GENS_SR_SIZE_SHIFT);
-       /* Switching to words (sr_size contains power of 2KB). */
+       /* Switching to words (sr_size contains power of 2KB) */
        nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
 
-       /* Check if we are in the normal or blank NVM programming mode. */
+       /* Check if we are in the normal or blank NVM programming mode */
        fla = rd32(hw, I40E_GLNVM_FLA);
-       if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode. */
-               /* Max NVM timeout. */
+       if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */
+               /* Max NVM timeout */
                nvm->timeout = I40E_MAX_NVM_TIMEOUT;
                nvm->blank_nvm_mode = false;
-       } else { /* Blank programming mode. */
+       } else { /* Blank programming mode */
                nvm->blank_nvm_mode = true;
                ret_code = I40E_ERR_NVM_BLANK_MODE;
                hw_dbg(hw, "NVM init error: unsupported blank mode.\n");
@@ -68,12 +68,12 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_acquire_nvm - Generic request for acquiring the NVM ownership.
- *  @hw: pointer to the HW structure.
- *  @access: NVM access type (read or write).
+ * i40e_acquire_nvm - Generic request for acquiring the NVM ownership
+ * @hw: pointer to the HW structure
+ * @access: NVM access type (read or write)
  *
- *  This function will request NVM ownership for reading
- *  via the proper Admin Command.
+ * This function will request NVM ownership for reading
+ * via the proper Admin Command.
  **/
 i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
                                       enum i40e_aq_resource_access_type access)
@@ -87,20 +87,20 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
 
        ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
                                            0, &time, NULL);
-       /* Reading the Global Device Timer. */
+       /* Reading the Global Device Timer */
        gtime = rd32(hw, I40E_GLVFGEN_TIMER);
 
-       /* Store the timeout. */
+       /* Store the timeout */
        hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
 
        if (ret_code) {
-               /* Set the polling timeout. */
+               /* Set the polling timeout */
                if (time > I40E_MAX_NVM_TIMEOUT)
                        timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
                                  + gtime;
                else
                        timeout = hw->nvm.hw_semaphore_timeout;
-               /* Poll until the current NVM owner timeouts. */
+               /* Poll until the current NVM owner timeouts */
                while (gtime < timeout) {
                        usleep_range(10000, 20000);
                        ret_code = i40e_aq_request_resource(hw,
@@ -128,10 +128,10 @@ i40e_i40e_acquire_nvm_exit:
 }
 
 /**
- *  i40e_release_nvm - Generic request for releasing the NVM ownership.
- *  @hw: pointer to the HW structure.
+ * i40e_release_nvm - Generic request for releasing the NVM ownership
+ * @hw: pointer to the HW structure
  *
- *  This function will release NVM resource via the proper Admin Command.
+ * This function will release NVM resource via the proper Admin Command.
  **/
 void i40e_release_nvm(struct i40e_hw *hw)
 {
@@ -140,17 +140,17 @@ void i40e_release_nvm(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit.
- *  @hw: pointer to the HW structure.
+ * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit
+ * @hw: pointer to the HW structure
  *
- *  Polls the SRCTL Shadow RAM register done bit.
+ * Polls the SRCTL Shadow RAM register done bit.
  **/
 static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
 {
        i40e_status ret_code = I40E_ERR_TIMEOUT;
        u32 srctl, wait_cnt;
 
-       /* Poll the I40E_GLNVM_SRCTL until the done bit is set. */
+       /* Poll the I40E_GLNVM_SRCTL until the done bit is set */
        for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
                srctl = rd32(hw, I40E_GLNVM_SRCTL);
                if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
@@ -165,12 +165,12 @@ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
 }
 
 /**
- *  i40e_read_nvm_word - Reads Shadow RAM
- *  @hw: pointer to the HW structure.
- *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
- *  @data: word read from the Shadow RAM.
+ * i40e_read_nvm_word - Reads Shadow RAM
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
+ * @data: word read from the Shadow RAM
  *
- *  Reads 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
  **/
 i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
                                         u16 *data)
@@ -184,15 +184,15 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
                goto read_nvm_exit;
        }
 
-       /* Poll the done bit first. */
+       /* Poll the done bit first */
        ret_code = i40e_poll_sr_srctl_done_bit(hw);
        if (!ret_code) {
-               /* Write the address and start reading. */
+               /* Write the address and start reading */
                sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
                         (1 << I40E_GLNVM_SRCTL_START_SHIFT);
                wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
 
-               /* Poll I40E_GLNVM_SRCTL until the done bit is set. */
+               /* Poll I40E_GLNVM_SRCTL until the done bit is set */
                ret_code = i40e_poll_sr_srctl_done_bit(hw);
                if (!ret_code) {
                        sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
@@ -210,16 +210,15 @@ read_nvm_exit:
 }
 
 /**
- *  i40e_read_nvm_buffer - Reads Shadow RAM buffer.
- *  @hw: pointer to the HW structure.
- *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
- *  @words: number of words to read (in) &
- *          number of words read before the NVM ownership timeout (out).
- *  @data: words read from the Shadow RAM.
+ * i40e_read_nvm_buffer - Reads Shadow RAM buffer
+ * @hw: pointer to the HW structure
+ * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ * @words: (in) number of words to read; (out) number of words actually read
+ * @data: words read from the Shadow RAM
  *
- *  Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
- *  method. The buffer read is preceded by the NVM ownership take
- *  and followed by the release.
+ * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
+ * method. The buffer read is preceded by the NVM ownership take
+ * and followed by the release.
  **/
 i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
                                           u16 *words, u16 *data)
@@ -227,7 +226,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
        i40e_status ret_code = 0;
        u16 index, word;
 
-       /* Loop thru the selected region. */
+       /* Loop thru the selected region */
        for (word = 0; word < *words; word++) {
                index = offset + word;
                ret_code = i40e_read_nvm_word(hw, index, &data[word]);
@@ -235,21 +234,21 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
                        break;
        }
 
-       /* Update the number of words read from the Shadow RAM. */
+       /* Update the number of words read from the Shadow RAM */
        *words = word;
 
        return ret_code;
 }
 
 /**
- *  i40e_calc_nvm_checksum - Calculates and returns the checksum
- *  @hw: pointer to hardware structure
- *  @checksum: pointer to the checksum
+ * i40e_calc_nvm_checksum - Calculates and returns the checksum
+ * @hw: pointer to hardware structure
+ * @checksum: pointer to the checksum
  *
- *  This function calculate SW Checksum that covers the whole 64kB shadow RAM
- *  except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
- *  is customer specific and unknown. Therefore, this function skips all maximum
- *  possible size of VPD (1kB).
+ * This function calculates SW Checksum that covers the whole 64kB shadow RAM
+ * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
+ * is customer specific and unknown. Therefore, this function skips all maximum
+ * possible size of VPD (1kB).
  **/
 static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
                                                    u16 *checksum)
@@ -311,12 +310,12 @@ i40e_calc_nvm_checksum_exit:
 }
 
 /**
- *  i40e_validate_nvm_checksum - Validate EEPROM checksum
- *  @hw: pointer to hardware structure
- *  @checksum: calculated checksum
+ * i40e_validate_nvm_checksum - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum: calculated checksum
  *
- *  Performs checksum calculation and validates the NVM SW checksum. If the
- *  caller does not need checksum, the value can be NULL.
+ * Performs checksum calculation and validates the NVM SW checksum. If the
+ * caller does not need checksum, the value can be NULL.
  **/
 i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
                                                 u16 *checksum)
index ed91f93ede2bd6bc839676560e3da077a873a245..9cd57e617959b1622ec57f8c8f6e2146c9c800a6 100644 (file)
@@ -231,6 +231,13 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
                                                 u16 *checksum);
 void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status);
 
+extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[];
+
+static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+       return i40e_ptype_lookup[ptype];
+}
+
 /* prototype for functions used for SW locks */
 
 /* i40e_common for VF drivers*/
index d4bb482b1a7f277e301b4f221030b242c9e2d187..a329aacb392f3400332047954eab72190ce42bae 100644 (file)
@@ -25,6 +25,7 @@
  ******************************************************************************/
 
 #include "i40e.h"
+#include "i40e_prototype.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
                                u32 td_tag)
@@ -39,11 +40,12 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
 #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
 /**
  * i40e_program_fdir_filter - Program a Flow Director filter
- * @fdir_input: Packet data that will be filter parameters
+ * @fdir_data: Packet data that will be filter parameters
+ * @raw_packet: the pre-allocated packet buffer for FDir
  * @pf: The pf pointer
  * @add: True for add/update, False for remove
  **/
-int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet,
                             struct i40e_pf *pf, bool add)
 {
        struct i40e_filter_program_desc *fdir_desc;
@@ -68,8 +70,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
        tx_ring = vsi->tx_rings[0];
        dev = tx_ring->dev;
 
-       dma = dma_map_single(dev, fdir_data->raw_packet,
-                            I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE);
+       dma = dma_map_single(dev, raw_packet,
+                            I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE);
        if (dma_mapping_error(dev, dma))
                goto dma_fail;
 
@@ -132,14 +134,14 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
        tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0;
 
        /* record length, and DMA address */
-       dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+       dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE);
        dma_unmap_addr_set(tx_buf, dma, dma);
 
        tx_desc->buffer_addr = cpu_to_le64(dma);
        td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY;
 
        tx_desc->cmd_type_offset_bsz =
-               build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0);
+               build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0);
 
        /* set the timestamp */
        tx_buf->time_stamp = jiffies;
@@ -161,26 +163,329 @@ dma_fail:
        return -1;
 }
 
+#define IP_HEADER_OFFSET 14
+#define I40E_UDPIP_DUMMY_PACKET_LEN 42
+/**
+ * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
+                                  struct i40e_fdir_filter *fd_data,
+                                  u8 *raw_packet, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct udphdr *udp;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       int i;
+       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+               0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+       memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN);
+
+       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+       udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET
+             + sizeof(struct iphdr));
+
+       ip->daddr = fd_data->dst_ip[0];
+       udp->dest = fd_data->dst_port;
+       ip->saddr = fd_data->src_ip[0];
+       udp->source = fd_data->src_port;
+
+       for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+            i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
+               fd_data->pctype = i;
+               ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+                       err = true;
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+               }
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+#define I40E_TCPIP_DUMMY_PACKET_LEN 54
+/**
+ * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
+                                  struct i40e_fdir_filter *fd_data,
+                                  u8 *raw_packet, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct tcphdr *tcp;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       /* Dummy packet */
+       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+               0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11,
+               0x0, 0x72, 0, 0, 0, 0};
+
+       memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN);
+
+       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+       tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET
+             + sizeof(struct iphdr));
+
+       ip->daddr = fd_data->dst_ip[0];
+       tcp->dest = fd_data->dst_port;
+       ip->saddr = fd_data->src_ip[0];
+       tcp->source = fd_data->src_port;
+
+       if (add) {
+               if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) {
+                       dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
+                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+               }
+       }
+
+       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
+       ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+               err = true;
+       } else {
+               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+       }
+
+       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+
+       ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+               err = true;
+       } else {
+               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+                         fd_data->pctype, ret);
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
+                                   struct i40e_fdir_filter *fd_data,
+                                   u8 *raw_packet, bool add)
+{
+       return -EOPNOTSUPP;
+}
+
+#define I40E_IP_DUMMY_PACKET_LEN 34
+/**
+ * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @raw_packet: the pre-allocated packet buffer for FDir
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
+                                 struct i40e_fdir_filter *fd_data,
+                                 u8 *raw_packet, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       int i;
+       static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0,
+               0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0};
+
+       memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN);
+       ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET);
+
+       ip->saddr = fd_data->src_ip[0];
+       ip->daddr = fd_data->dst_ip[0];
+       ip->protocol = 0;
+
+       for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+            i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
+               fd_data->pctype = i;
+               ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+                       err = true;
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+               }
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir - Build raw packets to add/del fdir filter
+ * @vsi: pointer to the targeted VSI
+ * @cmd: command to get or set RX flow classification rules
+ * @add: true adds a filter, false removes it
+ *
+ **/
+int i40e_add_del_fdir(struct i40e_vsi *vsi,
+                     struct i40e_fdir_filter *input, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       u8 *raw_packet;
+       int ret;
+
+       /* Populate the Flow Director that we have at the moment
+        * and allocate the raw packet buffer for the calling functions
+        */
+       raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL);
+       if (!raw_packet)
+               return -ENOMEM;
+
+       switch (input->flow_type & ~FLOW_EXT) {
+       case TCP_V4_FLOW:
+               ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet,
+                                             add);
+               break;
+       case UDP_V4_FLOW:
+               ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet,
+                                             add);
+               break;
+       case SCTP_V4_FLOW:
+               ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet,
+                                              add);
+               break;
+       case IPV4_FLOW:
+               ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet,
+                                            add);
+               break;
+       case IP_USER_FLOW:
+               switch (input->ip4_proto) {
+               case IPPROTO_TCP:
+                       ret = i40e_add_del_fdir_tcpv4(vsi, input,
+                                                     raw_packet, add);
+                       break;
+               case IPPROTO_UDP:
+                       ret = i40e_add_del_fdir_udpv4(vsi, input,
+                                                     raw_packet, add);
+                       break;
+               case IPPROTO_SCTP:
+                       ret = i40e_add_del_fdir_sctpv4(vsi, input,
+                                                      raw_packet, add);
+                       break;
+               default:
+                       ret = i40e_add_del_fdir_ipv4(vsi, input,
+                                                    raw_packet, add);
+                       break;
+               }
+               break;
+       default:
+               dev_info(&pf->pdev->dev, "Could not specify spec type %d",
+                        input->flow_type);
+               ret = -EINVAL;
+       }
+
+       kfree(raw_packet);
+       return ret;
+}
+
 /**
  * i40e_fd_handle_status - check the Programming Status for FD
  * @rx_ring: the Rx ring for this descriptor
- * @qw: the descriptor data
+ * @rx_desc: the Rx descriptor for programming Status, not a packet descriptor.
  * @prog_id: the id originally used for programming
  *
  * This is used to verify if the FD programming or invalidation
  * requested by SW to the HW is successful or not and take actions accordingly.
  **/
-static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id)
+static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
+                                 union i40e_rx_desc *rx_desc, u8 prog_id)
 {
-       struct pci_dev *pdev = rx_ring->vsi->back->pdev;
+       struct i40e_pf *pf = rx_ring->vsi->back;
+       struct pci_dev *pdev = pf->pdev;
+       u32 fcnt_prog, fcnt_avail;
        u32 error;
+       u64 qw;
 
+       qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
        error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>
                I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
 
-       /* for now just print the Status */
-       dev_info(&pdev->dev, "FD programming id %02x, Status %08x\n",
-                prog_id, error);
+       if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) {
+               dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n",
+                        rx_desc->wb.qword0.hi_dword.fd_id);
+
+               /* filter programming failed most likely due to table full */
+               fcnt_prog = i40e_get_current_fd_count(pf);
+               fcnt_avail = pf->hw.fdir_shared_filter_count +
+                                                      pf->fdir_pf_filter_count;
+
+               /* If ATR is running fcnt_prog can quickly change,
+                * if we are very close to full, it makes sense to disable
+                * FD ATR/SB and then re-enable it when there is room.
+                */
+               if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
+                       /* Turn off ATR first */
+                       if (pf->flags | I40E_FLAG_FD_ATR_ENABLED) {
+                               pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                               dev_warn(&pdev->dev, "FD filter space full, ATR for further flows will be turned off\n");
+                               pf->auto_disable_flags |=
+                                                      I40E_FLAG_FD_ATR_ENABLED;
+                               pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
+                       } else if (pf->flags | I40E_FLAG_FD_SB_ENABLED) {
+                               pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                               dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
+                               pf->auto_disable_flags |=
+                                                       I40E_FLAG_FD_SB_ENABLED;
+                               pf->flags |= I40E_FLAG_FDIR_REQUIRES_REINIT;
+                       }
+               } else {
+                       dev_info(&pdev->dev, "FD filter programming error");
+               }
+       } else if (error ==
+                         (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
+               if (I40E_DEBUG_FD & pf->hw.debug_mask)
+                       dev_info(&pdev->dev, "ntuple filter loc = %d, could not be removed\n",
+                                rx_desc->wb.qword0.hi_dword.fd_id);
+       }
 }
 
 /**
@@ -314,6 +619,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
        return ret;
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_clean_tx_irq - Reclaim resources after transmit completes
  * @tx_ring:  tx ring to clean
@@ -325,6 +644,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
 {
        u16 i = tx_ring->next_to_clean;
        struct i40e_tx_buffer *tx_buf;
+       struct i40e_tx_desc *tx_head;
        struct i40e_tx_desc *tx_desc;
        unsigned int total_packets = 0;
        unsigned int total_bytes = 0;
@@ -333,6 +653,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
        tx_desc = I40E_TX_DESC(tx_ring, i);
        i -= tx_ring->count;
 
+       tx_head = I40E_TX_DESC(tx_ring, i40e_get_head(tx_ring));
+
        do {
                struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch;
 
@@ -343,9 +665,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                /* prevent any other reads prior to eop_desc */
                read_barrier_depends();
 
-               /* if the descriptor isn't done, no work yet to do */
-               if (!(eop_desc->cmd_type_offset_bsz &
-                     cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE)))
+               /* we have caught up to head, no work left to do */
+               if (tx_head == tx_desc)
                        break;
 
                /* clear next_to_watch to prevent false hangs */
@@ -577,7 +898,7 @@ static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
                  I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
 
        if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
-               i40e_fd_handle_status(rx_ring, qw, id);
+               i40e_fd_handle_status(rx_ring, rx_desc, id);
 }
 
 /**
@@ -601,6 +922,10 @@ int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)
 
        /* round up to nearest 4K */
        tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
+       /* add u32 for head writeback, align after this takes care of
+        * guaranteeing this is at least one cache line in size
+        */
+       tx_ring->size += sizeof(u32);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
        tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
                                           &tx_ring->dma, GFP_KERNEL);
@@ -892,7 +1217,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
              rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
                return;
 
-       /* likely incorrect csum if alternate IP extention headers found */
+       /* likely incorrect csum if alternate IP extension headers found */
        if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
                return;
 
@@ -955,6 +1280,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring,
                return 0;
 }
 
+/**
+ * i40e_ptype_to_hash - get a hash type
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns a hash type to be used by skb_set_hash
+ **/
+static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+{
+       struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+
+       if (!decoded.known)
+               return PKT_HASH_TYPE_NONE;
+
+       if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+           decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+               return PKT_HASH_TYPE_L4;
+       else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+                decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+               return PKT_HASH_TYPE_L3;
+       else
+               return PKT_HASH_TYPE_L2;
+}
+
 /**
  * i40e_clean_rx_irq - Reclaim resources after receive completes
  * @rx_ring:  rx ring to clean
@@ -972,8 +1320,11 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        u16 i = rx_ring->next_to_clean;
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
+       u8 rx_ptype;
        u64 qword;
-       u16 rx_ptype;
+
+       if (budget <= 0)
+               return 0;
 
        rx_desc = I40E_RX_DESC(rx_ring, i);
        qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
@@ -1087,7 +1438,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                        goto next_desc;
                }
 
-               skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
+                            i40e_ptype_to_hash(rx_ptype));
                if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) {
                        i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status &
                                           I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >>
@@ -1246,8 +1598,6 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (!tx_ring->atr_sample_rate)
                return;
 
-       tx_ring->atr_count++;
-
        /* snag network header to get L4 type and address */
        hdr.network = skb_network_header(skb);
 
@@ -1269,8 +1619,17 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        th = (struct tcphdr *)(hdr.network + hlen);
 
-       /* sample on all syn/fin packets or once every atr sample rate */
-       if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate))
+       /* Due to lack of space, no more new filters can be programmed */
+       if (th->syn && (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
+               return;
+
+       tx_ring->atr_count++;
+
+       /* sample on all syn/fin/rst packets or once every atr sample rate */
+       if (!th->fin &&
+           !th->syn &&
+           !th->rst &&
+           (tx_ring->atr_count < tx_ring->atr_sample_rate))
                return;
 
        tx_ring->atr_count = 0;
@@ -1294,7 +1653,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        dtype_cmd = I40E_TX_DESC_DTYPE_FILTER_PROG;
 
-       dtype_cmd |= th->fin ?
+       dtype_cmd |= (th->fin || th->rst) ?
                     (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
                      I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
                     (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
@@ -1596,7 +1955,8 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
        struct i40e_tx_context_desc *context_desc;
        int i = tx_ring->next_to_use;
 
-       if (!cd_type_cmd_tso_mss && !cd_tunneling && !cd_l2tag2)
+       if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) &&
+           !cd_tunneling && !cd_l2tag2)
                return;
 
        /* grab the next descriptor */
@@ -1707,9 +2067,23 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
                tx_bi = &tx_ring->tx_bi[i];
        }
 
-       tx_desc->cmd_type_offset_bsz =
-               build_ctob(td_cmd, td_offset, size, td_tag) |
-               cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
+       /* Place RS bit on last descriptor of any packet that spans across the
+        * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
+        */
+#define WB_STRIDE 0x3
+       if (((i & WB_STRIDE) != WB_STRIDE) &&
+           (first <= &tx_ring->tx_bi[i]) &&
+           (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
+               tx_desc->cmd_type_offset_bsz =
+                       build_ctob(td_cmd, td_offset, size, td_tag) |
+                       cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
+                                        I40E_TXD_QW1_CMD_SHIFT);
+       } else {
+               tx_desc->cmd_type_offset_bsz =
+                       build_ctob(td_cmd, td_offset, size, td_tag) |
+                       cpu_to_le64((u64)I40E_TXD_CMD <<
+                                        I40E_TXD_QW1_CMD_SHIFT);
+       }
 
        netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
                                                 tx_ring->queue_index),
@@ -1812,7 +2186,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
 
        /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
         *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-        *       + 2 desc gap to keep tail from touching head,
+        *       + 4 desc gap to avoid the cache line where head is,
         *       + 1 desc for context descriptor,
         * otherwise try next time
         */
@@ -1823,7 +2197,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
        count += skb_shinfo(skb)->nr_frags;
 #endif
        count += TXD_USE_COUNT(skb_headlen(skb));
-       if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
                tx_ring->tx_stats.tx_busy++;
                return 0;
        }
index 181a825d3160dc377d4b909821a15959b3c49fe2..71a968fe557f33e12f6feb81d416f4f5a55946fb 100644 (file)
@@ -91,6 +91,7 @@ enum i40e_debug_mask {
        I40E_DEBUG_FLOW                 = 0x00000200,
        I40E_DEBUG_DCB                  = 0x00000400,
        I40E_DEBUG_DIAG                 = 0x00000800,
+       I40E_DEBUG_FD                   = 0x00001000,
 
        I40E_DEBUG_AQ_MESSAGE           = 0x01000000,
        I40E_DEBUG_AQ_DESCRIPTOR        = 0x02000000,
@@ -458,6 +459,10 @@ union i40e_32byte_rx_desc {
                        union {
                                __le32 rss; /* RSS Hash */
                                __le32 fcoe_param; /* FCoE DDP Context id */
+                               /* Flow director filter id in case of
+                                * Programming status desc WB
+                                */
+                               __le32 fd_id;
                        } hi_dword;
                } qword0;
                struct {
@@ -698,7 +703,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks {
 enum i40e_rx_prog_status_desc_error_bits {
        /* Note: These are predefined bit offsets */
        I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT      = 0,
-       I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT      = 1,
+       I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT      = 1,
        I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT    = 2,
        I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT    = 3
 };
@@ -1010,6 +1015,11 @@ struct i40e_hw_port_stats {
        u64 tx_size_big;                /* ptc9522 */
        u64 mac_short_packet_dropped;   /* mspdc */
        u64 checksum_error;             /* xec */
+       /* EEE LPI */
+       bool tx_lpi_status;
+       bool rx_lpi_status;
+       u64 tx_lpi_count;               /* etlpic */
+       u64 rx_lpi_count;               /* erlpic */
 };
 
 /* Checksum and Shadow RAM pointers */
index b9d1c1c8ca5a69f0d4d801f3cba0e4bc960ab46a..02c11a7f7d29e80c533b48894e5ee0b5619a9c91 100644 (file)
@@ -69,7 +69,7 @@ static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id)
 {
        struct i40e_pf *pf = vf->pf;
 
-       return vector_id <= pf->hw.func_caps.num_msix_vectors_vf;
+       return vector_id < pf->hw.func_caps.num_msix_vectors_vf;
 }
 
 /***********************vf resource mgmt routines*****************/
@@ -126,8 +126,8 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx,
                reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
        else
                reg_idx = I40E_VPINT_LNKLSTN(
-                                          (pf->hw.func_caps.num_msix_vectors_vf
-                                             * vf->vf_id) + (vector_id - 1));
+                    ((pf->hw.func_caps.num_msix_vectors_vf - 1) * vf->vf_id) +
+                    (vector_id - 1));
 
        if (vecmap->rxq_map == 0 && vecmap->txq_map == 0) {
                /* Special case - No queues mapped on this vector */
@@ -230,6 +230,9 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx,
        tx_ctx.qlen = info->ring_len;
        tx_ctx.rdylist = le16_to_cpu(pf->vsi[vsi_idx]->info.qs_handle[0]);
        tx_ctx.rdylist_act = 0;
+       tx_ctx.head_wb_ena = 1;
+       tx_ctx.head_wb_addr = info->dma_ring_addr +
+                             (info->ring_len * sizeof(struct i40e_tx_desc));
 
        /* clear the context in the HMC */
        ret = i40e_clear_lan_tx_queue_context(hw, pf_queue_id);
@@ -408,18 +411,10 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
                                 "Could not allocate VF broadcast filter\n");
        }
 
-       if (!f) {
-               dev_err(&pf->pdev->dev, "Unable to add ucast filter\n");
-               ret = -ENOMEM;
-               goto error_alloc_vsi_res;
-       }
-
        /* program mac filter */
        ret = i40e_sync_vsi_filters(vsi);
-       if (ret) {
+       if (ret)
                dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
-               goto error_alloc_vsi_res;
-       }
 
 error_alloc_vsi_res:
        return ret;
@@ -514,7 +509,8 @@ static void i40e_free_vf_res(struct i40e_vf *vf)
                vf->lan_vsi_index = 0;
                vf->lan_vsi_id = 0;
        }
-       msix_vf = pf->hw.func_caps.num_msix_vectors_vf + 1;
+       msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
+
        /* disable interrupts so the VF starts in a known state */
        for (i = 0; i < msix_vf; i++) {
                /* format is same for both registers */
@@ -679,9 +675,9 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
 complete_reset:
        /* reallocate vf resources to reset the VSI state */
        i40e_free_vf_res(vf);
-       mdelay(10);
        i40e_alloc_vf_res(vf);
        i40e_enable_vf_mappings(vf);
+       set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
 
        /* tell the VF the reset is done */
        wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
@@ -847,7 +843,7 @@ void i40e_free_vfs(struct i40e_pf *pf)
  *
  * allocate vf resources
  **/
-static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
+int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
 {
        struct i40e_vf *vfs;
        int i, ret = 0;
@@ -855,16 +851,18 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
        /* Disable interrupt 0 so we don't try to handle the VFLR. */
        i40e_irq_dynamic_disable_icr0(pf);
 
-       ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
-       if (ret) {
-               dev_err(&pf->pdev->dev,
-                       "pci_enable_sriov failed with error %d!\n", ret);
-               pf->num_alloc_vfs = 0;
-               goto err_iov;
+       /* Check to see if we're just allocating resources for extant VFs */
+       if (pci_num_vf(pf->pdev) != num_alloc_vfs) {
+               ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
+               if (ret) {
+                       dev_err(&pf->pdev->dev,
+                               "Failed to enable SR-IOV, error %d.\n", ret);
+                       pf->num_alloc_vfs = 0;
+                       goto err_iov;
+               }
        }
-
        /* allocate memory */
-       vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL);
+       vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
        if (!vfs) {
                ret = -ENOMEM;
                goto err_alloc;
@@ -1776,7 +1774,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
                           u32 v_retval, u8 *msg, u16 msglen)
 {
        struct i40e_hw *hw = &pf->hw;
-       int local_vf_id = vf_id - hw->func_caps.vf_base_id;
+       unsigned int local_vf_id = vf_id - hw->func_caps.vf_base_id;
        struct i40e_vf *vf;
        int ret;
 
@@ -1873,7 +1871,8 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
                        /* clear the bit in GLGEN_VFLRSTAT */
                        wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx));
 
-                       i40e_reset_vf(vf, true);
+                       if (!test_bit(__I40E_DOWN, &pf->state))
+                               i40e_reset_vf(vf, true);
                }
        }
 
@@ -1924,15 +1923,28 @@ static void i40e_vc_vf_broadcast(struct i40e_pf *pf,
 void i40e_vc_notify_link_state(struct i40e_pf *pf)
 {
        struct i40e_virtchnl_pf_event pfe;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf = pf->vf;
+       struct i40e_link_status *ls = &pf->hw.phy.link_info;
+       int i;
 
        pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
        pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
-       pfe.event_data.link_event.link_status =
-           pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
-       pfe.event_data.link_event.link_speed = pf->hw.phy.link_info.link_speed;
-
-       i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, I40E_SUCCESS,
-                            (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event));
+       for (i = 0; i < pf->num_alloc_vfs; i++) {
+               if (vf->link_forced) {
+                       pfe.event_data.link_event.link_status = vf->link_up;
+                       pfe.event_data.link_event.link_speed =
+                               (vf->link_up ? I40E_LINK_SPEED_40GB : 0);
+               } else {
+                       pfe.event_data.link_event.link_status =
+                               ls->link_info & I40E_AQ_LINK_UP;
+                       pfe.event_data.link_event.link_speed = ls->link_speed;
+               }
+               i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
+                                      0, (u8 *)&pfe, sizeof(pfe),
+                                      NULL);
+               vf++;
+       }
 }
 
 /**
@@ -2197,3 +2209,64 @@ int i40e_ndo_get_vf_config(struct net_device *netdev,
 error_param:
        return ret;
 }
+
+/**
+ * i40e_ndo_set_vf_link_state
+ * @netdev: network interface device structure
+ * @vf_id: vf identifier
+ * @link: required link state
+ *
+ * Set the link state of a specified VF, regardless of physical link state
+ **/
+int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_virtchnl_pf_event pfe;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf;
+       int ret = 0;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_out;
+       }
+
+       vf = &pf->vf[vf_id];
+
+       pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
+       pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
+
+       switch (link) {
+       case IFLA_VF_LINK_STATE_AUTO:
+               vf->link_forced = false;
+               pfe.event_data.link_event.link_status =
+                       pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
+               pfe.event_data.link_event.link_speed =
+                       pf->hw.phy.link_info.link_speed;
+               break;
+       case IFLA_VF_LINK_STATE_ENABLE:
+               vf->link_forced = true;
+               vf->link_up = true;
+               pfe.event_data.link_event.link_status = true;
+               pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
+               break;
+       case IFLA_VF_LINK_STATE_DISABLE:
+               vf->link_forced = true;
+               vf->link_up = false;
+               pfe.event_data.link_event.link_status = false;
+               pfe.event_data.link_event.link_speed = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               goto error_out;
+       }
+       /* Notify the VF of its new link state */
+       i40e_aq_send_msg_to_vf(hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
+                              0, (u8 *)&pfe, sizeof(pfe), NULL);
+
+error_out:
+       return ret;
+}
index cc1feee36e12b69e0ffaa300a4aa8509ba97bd4b..389c47f396d5261d708228f48d8e1bf8ed90e4c5 100644 (file)
@@ -98,10 +98,13 @@ struct i40e_vf {
 
        unsigned long vf_caps;  /* vf's adv. capabilities */
        unsigned long vf_states;        /* vf's runtime states */
+       bool link_forced;
+       bool link_up;           /* only valid if vf link is forced */
 };
 
 void i40e_free_vfs(struct i40e_pf *pf);
 int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
+int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs);
 int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
                           u32 v_retval, u8 *msg, u16 msglen);
 int i40e_vc_process_vflr_event(struct i40e_pf *pf);
@@ -115,6 +118,8 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
 int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate);
 int i40e_ndo_get_vf_config(struct net_device *netdev,
                           int vf_id, struct ifla_vf_info *ivi);
+int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link);
+
 void i40e_vc_notify_link_state(struct i40e_pf *pf);
 void i40e_vc_notify_reset(struct i40e_pf *pf);
 
index f7cea1bca38d08303f20c5dca3d08470a2e3a03a..97662b6bd98a3e5badd0660bfcc9c932500ae124 100644 (file)
@@ -1229,7 +1229,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE                 2
 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP                  3
 
-       __le32 tenant_id ;
+       __le32 tenant_id;
        u8     reserved[4];
        __le16 queue_number;
 #define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT                  0
index 7b13953b28c47a34af943a684b376dcb1d3ebf15..c688a0fc5c2965a2ddf42d935b1fabd6902ace23 100644 (file)
@@ -160,6 +160,372 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
 }
 
 
+/* The i40evf_ptype_lookup table is used to convert from the 8-bit ptype in the
+ * hardware to a bit-field that can be used by SW to more easily determine the
+ * packet type.
+ *
+ * Macros are used to shorten the table lines and make this table human
+ * readable.
+ *
+ * We store the PTYPE in the top byte of the bit field - this is just so that
+ * we can check that the table doesn't have a row missing, as the index into
+ * the table should be the PTYPE.
+ *
+ * Typical work flow:
+ *
+ * IF NOT i40evf_ptype_lookup[ptype].known
+ * THEN
+ *      Packet is unknown
+ * ELSE IF i40evf_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP
+ *      Use the rest of the fields to look at the tunnels, inner protocols, etc
+ * ELSE
+ *      Use the enum i40e_rx_l2_ptype to decode the packet type
+ * ENDIF
+ */
+
+/* macro to make the table lines short */
+#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\
+       {       PTYPE, \
+               1, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP, \
+               I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \
+               I40E_RX_PTYPE_##OUTER_FRAG, \
+               I40E_RX_PTYPE_TUNNEL_##T, \
+               I40E_RX_PTYPE_TUNNEL_END_##TE, \
+               I40E_RX_PTYPE_##TEF, \
+               I40E_RX_PTYPE_INNER_PROT_##I, \
+               I40E_RX_PTYPE_PAYLOAD_LAYER_##PL }
+
+#define I40E_PTT_UNUSED_ENTRY(PTYPE) \
+               { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+
+/* shorter macros makes the table fit but are terse */
+#define I40E_RX_PTYPE_NOF              I40E_RX_PTYPE_NOT_FRAG
+#define I40E_RX_PTYPE_FRG              I40E_RX_PTYPE_FRAG
+#define I40E_RX_PTYPE_INNER_PROT_TS    I40E_RX_PTYPE_INNER_PROT_TIMESYNC
+
+/* Lookup table mapping the HW PTYPE to the bit field for decoding */
+struct i40e_rx_ptype_decoded i40evf_ptype_lookup[] = {
+       /* L2 Packet types */
+       I40E_PTT_UNUSED_ENTRY(0),
+       I40E_PTT(1,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(2,  L2, NONE, NOF, NONE, NONE, NOF, TS,   PAY2),
+       I40E_PTT(3,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(4),
+       I40E_PTT_UNUSED_ENTRY(5),
+       I40E_PTT(6,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(7,  L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT_UNUSED_ENTRY(8),
+       I40E_PTT_UNUSED_ENTRY(9),
+       I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2),
+       I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE),
+       I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3),
+
+       /* Non Tunneled IPv4 */
+       I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(25),
+       I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv4 */
+       I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(32),
+       I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> IPv6 */
+       I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(39),
+       I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT */
+       I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> IPv4 */
+       I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(47),
+       I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> IPv6 */
+       I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(54),
+       I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC */
+       I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 --> GRE/NAT --> MAC --> IPv4 */
+       I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(62),
+       I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT -> MAC --> IPv6 */
+       I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(69),
+       I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv4 --> GRE/NAT --> MAC/VLAN */
+       I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(77),
+       I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(84),
+       I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* Non Tunneled IPv6 */
+       I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3),
+       I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP,  PAY3),
+       I40E_PTT_UNUSED_ENTRY(91),
+       I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP,  PAY4),
+       I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4),
+       I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv4 */
+       I40E_PTT(95,  IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(96,  IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(97,  IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(98),
+       I40E_PTT(99,  IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> IPv6 */
+       I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(105),
+       I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT */
+       I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> IPv4 */
+       I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(113),
+       I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> IPv6 */
+       I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(120),
+       I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC */
+       I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv4 */
+       I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(128),
+       I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC -> IPv6 */
+       I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(135),
+       I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN */
+       I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */
+       I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3),
+       I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3),
+       I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(143),
+       I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP,  PAY4),
+       I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4),
+       I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4),
+
+       /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */
+       I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3),
+       I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3),
+       I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP,  PAY4),
+       I40E_PTT_UNUSED_ENTRY(150),
+       I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP,  PAY4),
+       I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4),
+       I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4),
+
+       /* unused entries */
+       I40E_PTT_UNUSED_ENTRY(154),
+       I40E_PTT_UNUSED_ENTRY(155),
+       I40E_PTT_UNUSED_ENTRY(156),
+       I40E_PTT_UNUSED_ENTRY(157),
+       I40E_PTT_UNUSED_ENTRY(158),
+       I40E_PTT_UNUSED_ENTRY(159),
+
+       I40E_PTT_UNUSED_ENTRY(160),
+       I40E_PTT_UNUSED_ENTRY(161),
+       I40E_PTT_UNUSED_ENTRY(162),
+       I40E_PTT_UNUSED_ENTRY(163),
+       I40E_PTT_UNUSED_ENTRY(164),
+       I40E_PTT_UNUSED_ENTRY(165),
+       I40E_PTT_UNUSED_ENTRY(166),
+       I40E_PTT_UNUSED_ENTRY(167),
+       I40E_PTT_UNUSED_ENTRY(168),
+       I40E_PTT_UNUSED_ENTRY(169),
+
+       I40E_PTT_UNUSED_ENTRY(170),
+       I40E_PTT_UNUSED_ENTRY(171),
+       I40E_PTT_UNUSED_ENTRY(172),
+       I40E_PTT_UNUSED_ENTRY(173),
+       I40E_PTT_UNUSED_ENTRY(174),
+       I40E_PTT_UNUSED_ENTRY(175),
+       I40E_PTT_UNUSED_ENTRY(176),
+       I40E_PTT_UNUSED_ENTRY(177),
+       I40E_PTT_UNUSED_ENTRY(178),
+       I40E_PTT_UNUSED_ENTRY(179),
+
+       I40E_PTT_UNUSED_ENTRY(180),
+       I40E_PTT_UNUSED_ENTRY(181),
+       I40E_PTT_UNUSED_ENTRY(182),
+       I40E_PTT_UNUSED_ENTRY(183),
+       I40E_PTT_UNUSED_ENTRY(184),
+       I40E_PTT_UNUSED_ENTRY(185),
+       I40E_PTT_UNUSED_ENTRY(186),
+       I40E_PTT_UNUSED_ENTRY(187),
+       I40E_PTT_UNUSED_ENTRY(188),
+       I40E_PTT_UNUSED_ENTRY(189),
+
+       I40E_PTT_UNUSED_ENTRY(190),
+       I40E_PTT_UNUSED_ENTRY(191),
+       I40E_PTT_UNUSED_ENTRY(192),
+       I40E_PTT_UNUSED_ENTRY(193),
+       I40E_PTT_UNUSED_ENTRY(194),
+       I40E_PTT_UNUSED_ENTRY(195),
+       I40E_PTT_UNUSED_ENTRY(196),
+       I40E_PTT_UNUSED_ENTRY(197),
+       I40E_PTT_UNUSED_ENTRY(198),
+       I40E_PTT_UNUSED_ENTRY(199),
+
+       I40E_PTT_UNUSED_ENTRY(200),
+       I40E_PTT_UNUSED_ENTRY(201),
+       I40E_PTT_UNUSED_ENTRY(202),
+       I40E_PTT_UNUSED_ENTRY(203),
+       I40E_PTT_UNUSED_ENTRY(204),
+       I40E_PTT_UNUSED_ENTRY(205),
+       I40E_PTT_UNUSED_ENTRY(206),
+       I40E_PTT_UNUSED_ENTRY(207),
+       I40E_PTT_UNUSED_ENTRY(208),
+       I40E_PTT_UNUSED_ENTRY(209),
+
+       I40E_PTT_UNUSED_ENTRY(210),
+       I40E_PTT_UNUSED_ENTRY(211),
+       I40E_PTT_UNUSED_ENTRY(212),
+       I40E_PTT_UNUSED_ENTRY(213),
+       I40E_PTT_UNUSED_ENTRY(214),
+       I40E_PTT_UNUSED_ENTRY(215),
+       I40E_PTT_UNUSED_ENTRY(216),
+       I40E_PTT_UNUSED_ENTRY(217),
+       I40E_PTT_UNUSED_ENTRY(218),
+       I40E_PTT_UNUSED_ENTRY(219),
+
+       I40E_PTT_UNUSED_ENTRY(220),
+       I40E_PTT_UNUSED_ENTRY(221),
+       I40E_PTT_UNUSED_ENTRY(222),
+       I40E_PTT_UNUSED_ENTRY(223),
+       I40E_PTT_UNUSED_ENTRY(224),
+       I40E_PTT_UNUSED_ENTRY(225),
+       I40E_PTT_UNUSED_ENTRY(226),
+       I40E_PTT_UNUSED_ENTRY(227),
+       I40E_PTT_UNUSED_ENTRY(228),
+       I40E_PTT_UNUSED_ENTRY(229),
+
+       I40E_PTT_UNUSED_ENTRY(230),
+       I40E_PTT_UNUSED_ENTRY(231),
+       I40E_PTT_UNUSED_ENTRY(232),
+       I40E_PTT_UNUSED_ENTRY(233),
+       I40E_PTT_UNUSED_ENTRY(234),
+       I40E_PTT_UNUSED_ENTRY(235),
+       I40E_PTT_UNUSED_ENTRY(236),
+       I40E_PTT_UNUSED_ENTRY(237),
+       I40E_PTT_UNUSED_ENTRY(238),
+       I40E_PTT_UNUSED_ENTRY(239),
+
+       I40E_PTT_UNUSED_ENTRY(240),
+       I40E_PTT_UNUSED_ENTRY(241),
+       I40E_PTT_UNUSED_ENTRY(242),
+       I40E_PTT_UNUSED_ENTRY(243),
+       I40E_PTT_UNUSED_ENTRY(244),
+       I40E_PTT_UNUSED_ENTRY(245),
+       I40E_PTT_UNUSED_ENTRY(246),
+       I40E_PTT_UNUSED_ENTRY(247),
+       I40E_PTT_UNUSED_ENTRY(248),
+       I40E_PTT_UNUSED_ENTRY(249),
+
+       I40E_PTT_UNUSED_ENTRY(250),
+       I40E_PTT_UNUSED_ENTRY(251),
+       I40E_PTT_UNUSED_ENTRY(252),
+       I40E_PTT_UNUSED_ENTRY(253),
+       I40E_PTT_UNUSED_ENTRY(254),
+       I40E_PTT_UNUSED_ENTRY(255)
+};
+
+
 /**
  * i40e_aq_send_msg_to_pf
  * @hw: pointer to the hardware structure
index 7841573a58c943304af1aa671699af1756fb61ea..97ab8c2b76f8f0e6cf1c6c485eaeafee0e42a5a1 100644 (file)
@@ -63,6 +63,13 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw,
 
 i40e_status i40e_set_mac_type(struct i40e_hw *hw);
 
+extern struct i40e_rx_ptype_decoded i40evf_ptype_lookup[];
+
+static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype)
+{
+       return i40evf_ptype_lookup[ptype];
+}
+
 /* prototype for functions used for SW locks */
 
 /* i40e_common for VF drivers*/
index ffdb01d853dbdf3500524f335d352cb932b4af85..53be5f44d0158eca869fe0a9a818d3fa597bcd53 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -24,6 +24,7 @@
 #include <linux/prefetch.h>
 
 #include "i40evf.h"
+#include "i40e_prototype.h"
 
 static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
                                u32 td_tag)
@@ -168,6 +169,20 @@ static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
        return ret;
 }
 
+/**
+ * i40e_get_head - Retrieve head from head writeback
+ * @tx_ring:  tx ring to fetch head of
+ *
+ * Returns value of Tx ring head based on value stored
+ * in head write-back location
+ **/
+static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
+{
+       void *head = (struct i40e_tx_desc *)tx_ring->desc + tx_ring->count;
+
+       return le32_to_cpu(*(volatile __le32 *)head);
+}
+
 /**
  * i40e_clean_tx_irq - Reclaim resources after transmit completes
  * @tx_ring:  tx ring to clean
@@ -179,6 +194,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
 {
        u16 i = tx_ring->next_to_clean;
        struct i40e_tx_buffer *tx_buf;
+       struct i40e_tx_desc *tx_head;
        struct i40e_tx_desc *tx_desc;
        unsigned int total_packets = 0;
        unsigned int total_bytes = 0;
@@ -187,6 +203,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
        tx_desc = I40E_TX_DESC(tx_ring, i);
        i -= tx_ring->count;
 
+       tx_head = I40E_TX_DESC(tx_ring, i40e_get_head(tx_ring));
+
        do {
                struct i40e_tx_desc *eop_desc = tx_buf->next_to_watch;
 
@@ -197,9 +215,8 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                /* prevent any other reads prior to eop_desc */
                read_barrier_depends();
 
-               /* if the descriptor isn't done, no work yet to do */
-               if (!(eop_desc->cmd_type_offset_bsz &
-                     cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE)))
+               /* we have caught up to head, no work left to do */
+               if (tx_head == tx_desc)
                        break;
 
                /* clear next_to_watch to prevent false hangs */
@@ -431,6 +448,10 @@ int i40evf_setup_tx_descriptors(struct i40e_ring *tx_ring)
 
        /* round up to nearest 4K */
        tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
+       /* add u32 for head writeback, align after this takes care of
+        * guaranteeing this is at least one cache line in size
+        */
+       tx_ring->size += sizeof(u32);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
        tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
                                           &tx_ring->dma, GFP_KERNEL);
@@ -722,7 +743,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
              rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
                return;
 
-       /* likely incorrect csum if alternate IP extention headers found */
+       /* likely incorrect csum if alternate IP extension headers found */
        if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT))
                return;
 
@@ -785,6 +806,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring,
                return 0;
 }
 
+/**
+ * i40e_ptype_to_hash - get a hash type
+ * @ptype: the ptype value from the descriptor
+ *
+ * Returns a hash type to be used by skb_set_hash
+ **/
+static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype)
+{
+       struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype);
+
+       if (!decoded.known)
+               return PKT_HASH_TYPE_NONE;
+
+       if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+           decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4)
+               return PKT_HASH_TYPE_L4;
+       else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP &&
+                decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3)
+               return PKT_HASH_TYPE_L3;
+       else
+               return PKT_HASH_TYPE_L2;
+}
+
 /**
  * i40e_clean_rx_irq - Reclaim resources after receive completes
  * @rx_ring:  rx ring to clean
@@ -802,13 +846,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        u16 i = rx_ring->next_to_clean;
        union i40e_rx_desc *rx_desc;
        u32 rx_error, rx_status;
+       u8 rx_ptype;
        u64 qword;
-       u16 rx_ptype;
 
        rx_desc = I40E_RX_DESC(rx_ring, i);
        qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
-       rx_status = (qword & I40E_RXD_QW1_STATUS_MASK)
-                               >> I40E_RXD_QW1_STATUS_SHIFT;
+       rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >>
+                   I40E_RXD_QW1_STATUS_SHIFT;
 
        while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {
                union i40e_rx_desc *next_rxd;
@@ -912,7 +956,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                        goto next_desc;
                }
 
-               skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+               skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc),
+                            i40e_ptype_to_hash(rx_ptype));
                /* probably a little skewed due to removing CRC */
                total_rx_bytes += skb->len;
                total_rx_packets++;
@@ -1241,7 +1286,8 @@ static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
        struct i40e_tx_context_desc *context_desc;
        int i = tx_ring->next_to_use;
 
-       if (!cd_type_cmd_tso_mss && !cd_tunneling && !cd_l2tag2)
+       if ((cd_type_cmd_tso_mss == I40E_TX_DESC_DTYPE_CONTEXT) &&
+           !cd_tunneling && !cd_l2tag2)
                return;
 
        /* grab the next descriptor */
@@ -1352,9 +1398,23 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
                tx_bi = &tx_ring->tx_bi[i];
        }
 
-       tx_desc->cmd_type_offset_bsz =
-               build_ctob(td_cmd, td_offset, size, td_tag) |
-               cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
+       /* Place RS bit on last descriptor of any packet that spans across the
+        * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
+        */
+#define WB_STRIDE 0x3
+       if (((i & WB_STRIDE) != WB_STRIDE) &&
+           (first <= &tx_ring->tx_bi[i]) &&
+           (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
+               tx_desc->cmd_type_offset_bsz =
+                       build_ctob(td_cmd, td_offset, size, td_tag) |
+                       cpu_to_le64((u64)I40E_TX_DESC_CMD_EOP <<
+                                        I40E_TXD_QW1_CMD_SHIFT);
+       } else {
+               tx_desc->cmd_type_offset_bsz =
+                       build_ctob(td_cmd, td_offset, size, td_tag) |
+                       cpu_to_le64((u64)I40E_TXD_CMD <<
+                                        I40E_TXD_QW1_CMD_SHIFT);
+       }
 
        netdev_tx_sent_queue(netdev_get_tx_queue(tx_ring->netdev,
                                                 tx_ring->queue_index),
@@ -1457,7 +1517,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
 
        /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
         *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
-        *       + 2 desc gap to keep tail from touching head,
+        *       + 4 desc gap to avoid the cache line where head is,
         *       + 1 desc for context descriptor,
         * otherwise try next time
         */
@@ -1468,7 +1528,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb,
        count += skb_shinfo(skb)->nr_frags;
 #endif
        count += TXD_USE_COUNT(skb_headlen(skb));
-       if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+       if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) {
                tx_ring->tx_stats.tx_busy++;
                return 0;
        }
index 3bffac06592f58557ac9028cf60fc12614c74a03..4673b3381eddaa1672edca1f60b85e89d33ab247 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -64,8 +64,6 @@
 struct i40e_hw;
 typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
 
-#define ETH_ALEN       6
-
 /* Data type manipulation macros. */
 
 #define I40E_DESC_UNUSED(R)    \
@@ -90,6 +88,7 @@ enum i40e_debug_mask {
        I40E_DEBUG_FLOW                 = 0x00000200,
        I40E_DEBUG_DCB                  = 0x00000400,
        I40E_DEBUG_DIAG                 = 0x00000800,
+       I40E_DEBUG_FD                   = 0x00001000,
 
        I40E_DEBUG_AQ_MESSAGE           = 0x01000000,
        I40E_DEBUG_AQ_DESCRIPTOR        = 0x02000000,
@@ -466,6 +465,10 @@ union i40e_32byte_rx_desc {
                        union {
                                __le32 rss; /* RSS Hash */
                                __le32 fcoe_param; /* FCoE DDP Context id */
+                               /* Flow director filter id in case of
+                                * Programming status desc WB
+                                */
+                               __le32 fd_id;
                        } hi_dword;
                } qword0;
                struct {
@@ -706,7 +709,7 @@ enum i40e_rx_prog_status_desc_prog_id_masks {
 enum i40e_rx_prog_status_desc_error_bits {
        /* Note: These are predefined bit offsets */
        I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT      = 0,
-       I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT      = 1,
+       I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT      = 1,
        I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT    = 2,
        I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT    = 3
 };
@@ -1018,6 +1021,11 @@ struct i40e_hw_port_stats {
        u64 tx_size_big;                /* ptc9522 */
        u64 mac_short_packet_dropped;   /* mspdc */
        u64 checksum_error;             /* xec */
+       /* EEE LPI */
+       bool tx_lpi_status;
+       bool rx_lpi_status;
+       u64 tx_lpi_count;               /* etlpic */
+       u64 rx_lpi_count;               /* erlpic */
 };
 
 /* Checksum and Shadow RAM pointers */
index ff6529b288a137190e35fe3d86ea17ad1929db51..807807d6238738c0e111739e9dc96d1f2200d77a 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -38,8 +38,6 @@
 #include <linux/ipv6.h>
 #include <net/ip6_checksum.h>
 #include <net/udp.h>
-#include <linux/sctp.h>
-
 
 #include "i40e_type.h"
 #include "i40e_virtchnl.h"
@@ -164,15 +162,14 @@ struct i40evf_vlan_filter {
 /* Driver state. The order of these is important! */
 enum i40evf_state_t {
        __I40EVF_STARTUP,               /* driver loaded, probe complete */
-       __I40EVF_FAILED,                /* PF communication failed. Fatal. */
        __I40EVF_REMOVE,                /* driver is being unloaded */
        __I40EVF_INIT_VERSION_CHECK,    /* aq msg sent, awaiting reply */
        __I40EVF_INIT_GET_RESOURCES,    /* aq msg sent, awaiting reply */
        __I40EVF_INIT_SW,               /* got resources, setting up structs */
+       __I40EVF_RESETTING,             /* in reset */
        /* Below here, watchdog is running */
        __I40EVF_DOWN,                  /* ready, can be opened */
        __I40EVF_TESTING,               /* in ethtool self-test */
-       __I40EVF_RESETTING,             /* in reset */
        __I40EVF_RUNNING,               /* opened, working */
 };
 
@@ -185,47 +182,25 @@ enum i40evf_critical_section_t {
 /* board specific private data structure */
 struct i40evf_adapter {
        struct timer_list watchdog_timer;
-       struct vlan_group *vlgrp;
        struct work_struct reset_task;
        struct work_struct adminq_task;
        struct delayed_work init_task;
        struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
        struct list_head vlan_filter_list;
-       char name[MAX_MSIX_COUNT][IFNAMSIZ + 9];
-
-       /* Interrupt Throttle Rate */
-       u32 itr_setting;
-       u16 eitr_low;
-       u16 eitr_high;
+       char misc_vector_name[IFNAMSIZ + 9];
 
        /* TX */
        struct i40e_ring *tx_rings[I40E_MAX_VSI_QP];
-       u64 restart_queue;
-       u64 hw_csum_tx_good;
-       u64 lsc_int;
-       u64 hw_tso_ctxt;
-       u64 hw_tso6_ctxt;
        u32 tx_timeout_count;
        struct list_head mac_filter_list;
-#ifdef DEBUG
-       bool detect_tx_hung;
-#endif /* DEBUG */
 
        /* RX */
        struct i40e_ring *rx_rings[I40E_MAX_VSI_QP];
-       int txd_count;
-       int rxd_count;
        u64 hw_csum_rx_error;
-       u64 hw_rx_no_dma_resources;
-       u64 hw_csum_rx_good;
-       u64 non_eop_descs;
        int num_msix_vectors;
        struct msix_entry *msix_entries;
 
-       u64 rx_hdr_split;
-
-       u32 init_state;
-       volatile unsigned long flags;
+       u32 flags;
 #define I40EVF_FLAG_RX_CSUM_ENABLED              (u32)(1)
 #define I40EVF_FLAG_RX_1BUF_CAPABLE              (u32)(1 << 1)
 #define I40EVF_FLAG_RX_PS_CAPABLE                (u32)(1 << 2)
@@ -234,6 +209,9 @@ struct i40evf_adapter {
 #define I40EVF_FLAG_IMIR_ENABLED                 (u32)(1 << 5)
 #define I40EVF_FLAG_MQ_CAPABLE                   (u32)(1 << 6)
 #define I40EVF_FLAG_NEED_LINK_UPDATE             (u32)(1 << 7)
+#define I40EVF_FLAG_PF_COMMS_FAILED              (u32)(1 << 8)
+#define I40EVF_FLAG_RESET_PENDING                (u32)(1 << 9)
+#define I40EVF_FLAG_RESET_NEEDED                 (u32)(1 << 10)
 /* duplcates for common code */
 #define I40E_FLAG_FDIR_ATR_ENABLED              0
 #define I40E_FLAG_DCB_ENABLED                   0
@@ -251,21 +229,19 @@ struct i40evf_adapter {
 #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES                (u32)(1 << 6)
 #define I40EVF_FLAG_AQ_MAP_VECTORS             (u32)(1 << 7)
 #define I40EVF_FLAG_AQ_HANDLE_RESET            (u32)(1 << 8)
+
        /* OS defined structs */
        struct net_device *netdev;
        struct pci_dev *pdev;
        struct net_device_stats net_stats;
 
-       /* structs defined in i40e_vf.h */
-       struct i40e_hw hw;
+       struct i40e_hw hw; /* defined in i40e_type.h */
 
        enum i40evf_state_t state;
        volatile unsigned long crit_section;
-       u64 tx_busy;
 
        struct work_struct watchdog_task;
        bool netdev_registered;
-       bool dev_closed;
        bool link_up;
        enum i40e_virtchnl_ops current_op;
        struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */
@@ -276,11 +252,6 @@ struct i40evf_adapter {
        u32 aq_wait_count;
 };
 
-struct i40evf_info {
-       enum i40e_mac_type      mac;
-       unsigned int            flags;
-};
-
 
 /* needed by i40evf_ethtool.c */
 extern char i40evf_driver_name[];
@@ -315,6 +286,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter);
 void i40evf_del_vlans(struct i40evf_adapter *adapter);
 void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags);
 void i40evf_request_stats(struct i40evf_adapter *adapter);
+void i40evf_request_reset(struct i40evf_adapter *adapter);
 void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
                                enum i40e_virtchnl_ops v_opcode,
                                i40e_status v_retval, u8 *msg, u16 msglen);
index b0b1f4bf5ac08afb7c6cf62ac76419f36cfbd6c1..8b0db1ce179c5447ce83240098e6c076d6782ed6 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -241,6 +241,7 @@ static int i40evf_set_ringparam(struct net_device *netdev,
 {
        struct i40evf_adapter *adapter = netdev_priv(netdev);
        u32 new_rx_count, new_tx_count;
+       int i;
 
        if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
                return -EINVAL;
@@ -256,12 +257,14 @@ static int i40evf_set_ringparam(struct net_device *netdev,
        new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE);
 
        /* if nothing to do return success */
-       if ((new_tx_count == adapter->txd_count) &&
-           (new_rx_count == adapter->rxd_count))
+       if ((new_tx_count == adapter->tx_rings[0]->count) &&
+           (new_rx_count == adapter->rx_rings[0]->count))
                return 0;
 
-       adapter->txd_count = new_tx_count;
-       adapter->rxd_count = new_rx_count;
+       for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) {
+               adapter->tx_rings[0]->count = new_tx_count;
+               adapter->rx_rings[0]->count = new_rx_count;
+       }
 
        if (netif_running(netdev))
                i40evf_reinit_locked(adapter);
index f5caf441924370145b0fb3a5e409033893c40aff..51c84c19d2bee9d834615e967c1dc92ec082ee75 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -31,10 +31,10 @@ char i40evf_driver_name[] = "i40evf";
 static const char i40evf_driver_string[] =
        "Intel(R) XL710 X710 Virtual Function Network Driver";
 
-#define DRV_VERSION "0.9.11"
+#define DRV_VERSION "0.9.16"
 const char i40evf_driver_version[] = DRV_VERSION;
 static const char i40evf_copyright[] =
-       "Copyright (c) 2013 Intel Corporation.";
+       "Copyright (c) 2013 - 2014 Intel Corporation.";
 
 /* i40evf_pci_tbl - PCI Device ID Table
  *
@@ -167,9 +167,11 @@ static void i40evf_tx_timeout(struct net_device *netdev)
        struct i40evf_adapter *adapter = netdev_priv(netdev);
 
        adapter->tx_timeout_count++;
-
-       /* Do the reset outside of interrupt context */
-       schedule_work(&adapter->reset_task);
+       dev_info(&adapter->pdev->dev, "TX timeout detected.\n");
+       if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
+               adapter->flags |= I40EVF_FLAG_RESET_NEEDED;
+               schedule_work(&adapter->reset_task);
+       }
 }
 
 /**
@@ -211,6 +213,9 @@ static void i40evf_irq_disable(struct i40evf_adapter *adapter)
        int i;
        struct i40e_hw *hw = &adapter->hw;
 
+       if (!adapter->msix_entries)
+               return;
+
        for (i = 1; i < adapter->num_msix_vectors; i++) {
                wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), 0);
                synchronize_irq(adapter->msix_entries[i].vector);
@@ -511,12 +516,14 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        int err;
 
-       sprintf(adapter->name[0], "i40evf:mbx");
+       sprintf(adapter->misc_vector_name, "i40evf:mbx");
        err = request_irq(adapter->msix_entries[0].vector,
-                         &i40evf_msix_aq, 0, adapter->name[0], netdev);
+                         &i40evf_msix_aq, 0,
+                         adapter->misc_vector_name, netdev);
        if (err) {
                dev_err(&adapter->pdev->dev,
-                       "request_irq for msix_aq failed: %d\n", err);
+                       "request_irq for %s failed: %d\n",
+                       adapter->misc_vector_name, err);
                free_irq(adapter->msix_entries[0].vector, netdev);
        }
        return err;
@@ -963,16 +970,23 @@ void i40evf_down(struct i40evf_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        struct i40evf_mac_filter *f;
 
-       /* remove all MAC filters from the VSI */
+       /* remove all MAC filters */
        list_for_each_entry(f, &adapter->mac_filter_list, list) {
                f->remove = true;
        }
-       adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
-       /* disable receives */
-       adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
-       mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
-       msleep(20);
-
+       /* remove all VLAN filters */
+       list_for_each_entry(f, &adapter->vlan_filter_list, list) {
+               f->remove = true;
+       }
+       if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
+           adapter->state != __I40EVF_RESETTING) {
+               adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+               adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
+               /* disable receives */
+               adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
+               mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
+               msleep(20);
+       }
        netif_tx_disable(netdev);
 
        netif_tx_stop_all_queues(netdev);
@@ -1124,8 +1138,8 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter)
         * than CPU's.  So let's be conservative and only ask for
         * (roughly) twice the number of vectors as there are CPU's.
         */
-       v_budget = min(pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS;
-       v_budget = min(v_budget, (int)adapter->vf_res->max_vectors + 1);
+       v_budget = min_t(int, pairs, (int)(num_online_cpus() * 2)) + NONQ_VECS;
+       v_budget = min_t(int, v_budget, (int)adapter->vf_res->max_vectors);
 
        /* A failure in MSI-X entry allocation isn't fatal, but it does
         * mean we disable MSI-X capabilities of the adapter.
@@ -1291,19 +1305,47 @@ static void i40evf_watchdog_task(struct work_struct *work)
                                          watchdog_task);
        struct i40e_hw *hw = &adapter->hw;
 
-       if (adapter->state < __I40EVF_DOWN)
+       if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section))
+               goto restart_watchdog;
+
+       if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
+               dev_info(&adapter->pdev->dev, "Checking for redemption\n");
+               if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) {
+                       /* A chance for redemption! */
+                       dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n");
+                       adapter->state = __I40EVF_STARTUP;
+                       adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
+                       schedule_delayed_work(&adapter->init_task, 10);
+                       clear_bit(__I40EVF_IN_CRITICAL_TASK,
+                                 &adapter->crit_section);
+                       /* Don't reschedule the watchdog, since we've restarted
+                        * the init task. When init_task contacts the PF and
+                        * gets everything set up again, it'll restart the
+                        * watchdog for us. Down, boy. Sit. Stay. Woof.
+                        */
+                       return;
+               }
+               adapter->aq_pending = 0;
+               adapter->aq_required = 0;
+               adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
                goto watchdog_done;
+       }
 
-       if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section))
+       if ((adapter->state < __I40EVF_DOWN) ||
+           (adapter->flags & I40EVF_FLAG_RESET_PENDING))
                goto watchdog_done;
 
-       /* check for unannounced reset */
-       if ((adapter->state != __I40EVF_RESETTING) &&
+       /* check for reset */
+       if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) &&
            (rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) {
                adapter->state = __I40EVF_RESETTING;
+               adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+               dev_err(&adapter->pdev->dev, "Hardware reset detected.\n");
+               dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
                schedule_work(&adapter->reset_task);
-               dev_info(&adapter->pdev->dev, "%s: hardware reset detected\n",
-                        __func__);
+               adapter->aq_pending = 0;
+               adapter->aq_required = 0;
+               adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
                goto watchdog_done;
        }
 
@@ -1358,16 +1400,25 @@ static void i40evf_watchdog_task(struct work_struct *work)
 
        i40evf_irq_enable(adapter, true);
        i40evf_fire_sw_int(adapter, 0xFF);
+
 watchdog_done:
+       clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+restart_watchdog:
        if (adapter->aq_required)
                mod_timer(&adapter->watchdog_timer,
                          jiffies + msecs_to_jiffies(20));
        else
                mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2));
-       clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
        schedule_work(&adapter->adminq_task);
 }
 
+static int next_queue(struct i40evf_adapter *adapter, int j)
+{
+       j += 1;
+
+       return j >= adapter->vsi_res->num_queue_pairs ? 0 : j;
+}
+
 /**
  * i40evf_configure_rss - Prepare for RSS if used
  * @adapter: board private structure
@@ -1398,19 +1449,19 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
        wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
 
        /* Populate the LUT with max no. of queues in round robin fashion */
-       for (i = 0, j = 0; i < I40E_VFQF_HLUT_MAX_INDEX; i++, j++) {
-               if (j == adapter->vsi_res->num_queue_pairs)
-                       j = 0;
-               /* lut = 4-byte sliding window of 4 lut entries */
-               lut = (lut << 8) | (j &
-                        ((0x1 << 8) - 1));
-               /* On i = 3, we have 4 entries in lut; write to the register */
-               if ((i & 3) == 3)
-                       wr32(hw, I40E_VFQF_HLUT(i >> 2), lut);
+       j = adapter->vsi_res->num_queue_pairs;
+       for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
+               lut = next_queue(adapter, j);
+               lut |= next_queue(adapter, j) << 8;
+               lut |= next_queue(adapter, j) << 16;
+               lut |= next_queue(adapter, j) << 24;
+               wr32(hw, I40E_VFQF_HLUT(i), lut);
        }
        i40e_flush(hw);
 }
 
+#define I40EVF_RESET_WAIT_MS 100
+#define I40EVF_RESET_WAIT_COUNT 200
 /**
  * i40evf_reset_task - Call-back task to handle hardware reset
  * @work: pointer to work_struct
@@ -1421,8 +1472,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter)
  **/
 static void i40evf_reset_task(struct work_struct *work)
 {
-       struct i40evf_adapter *adapter =
-                       container_of(work, struct i40evf_adapter, reset_task);
+       struct i40evf_adapter *adapter = container_of(work,
+                                                     struct i40evf_adapter,
+                                                     reset_task);
        struct i40e_hw *hw = &adapter->hw;
        int i = 0, err;
        uint32_t rstat_val;
@@ -1431,21 +1483,61 @@ static void i40evf_reset_task(struct work_struct *work)
                                &adapter->crit_section))
                udelay(500);
 
-       /* wait until the reset is complete */
-       for (i = 0; i < 20; i++) {
+       if (adapter->flags & I40EVF_FLAG_RESET_NEEDED) {
+               dev_info(&adapter->pdev->dev, "Requesting reset from PF\n");
+               i40evf_request_reset(adapter);
+       }
+
+       /* poll until we see the reset actually happen */
+       for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
                rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
                            I40E_VFGEN_RSTAT_VFR_STATE_MASK;
-               if (rstat_val == I40E_VFR_COMPLETED)
+               if (rstat_val != I40E_VFR_VFACTIVE) {
+                       dev_info(&adapter->pdev->dev, "Reset now occurring\n");
                        break;
-               else
-                       mdelay(100);
+               } else {
+                       msleep(I40EVF_RESET_WAIT_MS);
+               }
+       }
+       if (i == I40EVF_RESET_WAIT_COUNT) {
+               dev_err(&adapter->pdev->dev, "Reset was not detected\n");
+               adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+               goto continue_reset; /* act like the reset happened */
+       }
+
+       /* wait until the reset is complete and the PF is responding to us */
+       for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) {
+               rstat_val = rd32(hw, I40E_VFGEN_RSTAT) &
+                           I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+               if (rstat_val == I40E_VFR_VFACTIVE) {
+                       dev_info(&adapter->pdev->dev, "Reset is complete. Reinitializing.\n");
+                       break;
+               } else {
+                       msleep(I40EVF_RESET_WAIT_MS);
+               }
        }
-       if (i == 20) {
+       if (i == I40EVF_RESET_WAIT_COUNT) {
                /* reset never finished */
-               dev_info(&adapter->pdev->dev, "%s: reset never finished: %x\n",
-                       __func__, rstat_val);
-               /* carry on anyway */
+               dev_err(&adapter->pdev->dev, "Reset never finished (%x). PF driver is dead, and so am I.\n",
+                       rstat_val);
+               adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
+
+               if (netif_running(adapter->netdev))
+                       i40evf_close(adapter->netdev);
+
+               i40evf_free_misc_irq(adapter);
+               i40evf_reset_interrupt_capability(adapter);
+               i40evf_free_queues(adapter);
+               kfree(adapter->vf_res);
+               i40evf_shutdown_adminq(hw);
+               adapter->netdev->flags &= ~IFF_UP;
+               clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
+               return; /* Do not attempt to reinit. It's dead, Jim. */
        }
+
+continue_reset:
+       adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
+
        i40evf_down(adapter);
        adapter->state = __I40EVF_RESETTING;
 
@@ -1505,6 +1597,9 @@ static void i40evf_adminq_task(struct work_struct *work)
        i40e_status ret;
        u16 pending;
 
+       if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
+               return;
+
        event.msg_size = I40EVF_MAX_AQ_BUF_SIZE;
        event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL);
        if (!event.msg_buf) {
@@ -1636,6 +1731,10 @@ static int i40evf_open(struct net_device *netdev)
        struct i40evf_adapter *adapter = netdev_priv(netdev);
        int err;
 
+       if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) {
+               dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n");
+               return -EIO;
+       }
        if (adapter->state != __I40EVF_DOWN)
                return -EBUSY;
 
@@ -1690,8 +1789,12 @@ static int i40evf_close(struct net_device *netdev)
 {
        struct i40evf_adapter *adapter = netdev_priv(netdev);
 
+       if (adapter->state <= __I40EVF_DOWN)
+               return 0;
+
        /* signal that we are down to the interrupt handler */
        adapter->state = __I40EVF_DOWN;
+
        set_bit(__I40E_DOWN, &adapter->vsi.state);
 
        i40evf_down(adapter);
@@ -1842,16 +1945,18 @@ static void i40evf_init_task(struct work_struct *work)
        switch (adapter->state) {
        case __I40EVF_STARTUP:
                /* driver loaded, probe complete */
+               adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED;
+               adapter->flags &= ~I40EVF_FLAG_RESET_PENDING;
                err = i40e_set_mac_type(hw);
                if (err) {
-                       dev_info(&pdev->dev, "%s: set_mac_type failed: %d\n",
-                               __func__, err);
+                       dev_err(&pdev->dev, "Failed to set MAC type (%d)\n",
+                               err);
                goto err;
                }
                err = i40evf_check_reset_complete(hw);
                if (err) {
-                       dev_info(&pdev->dev, "%s: device is still in reset (%d).\n",
-                               __func__, err);
+                       dev_err(&pdev->dev, "Device is still in reset (%d)\n",
+                               err);
                        goto err;
                }
                hw->aq.num_arq_entries = I40EVF_AQ_LEN;
@@ -1861,14 +1966,13 @@ static void i40evf_init_task(struct work_struct *work)
 
                err = i40evf_init_adminq(hw);
                if (err) {
-                       dev_info(&pdev->dev, "%s: init_adminq failed: %d\n",
-                               __func__, err);
+                       dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n",
+                               err);
                        goto err;
                }
                err = i40evf_send_api_ver(adapter);
                if (err) {
-                       dev_info(&pdev->dev, "%s: unable to send to PF (%d)\n",
-                               __func__, err);
+                       dev_err(&pdev->dev, "Unable to send to PF (%d)\n", err);
                        i40evf_shutdown_adminq(hw);
                        goto err;
                }
@@ -1876,19 +1980,21 @@ static void i40evf_init_task(struct work_struct *work)
                goto restart;
                break;
        case __I40EVF_INIT_VERSION_CHECK:
-               if (!i40evf_asq_done(hw))
+               if (!i40evf_asq_done(hw)) {
+                       dev_err(&pdev->dev, "Admin queue command never completed.\n");
                        goto err;
+               }
 
                /* aq msg sent, awaiting reply */
                err = i40evf_verify_api_ver(adapter);
                if (err) {
-                       dev_err(&pdev->dev, "Unable to verify API version, error %d\n",
+                       dev_err(&pdev->dev, "Unable to verify API version (%d)\n",
                                err);
                        goto err;
                }
                err = i40evf_send_vf_config_msg(adapter);
                if (err) {
-                       dev_err(&pdev->dev, "Unable send config request, error %d\n",
+                       dev_err(&pdev->dev, "Unable send config request (%d)\n",
                                err);
                        goto err;
                }
@@ -1902,18 +2008,15 @@ static void i40evf_init_task(struct work_struct *work)
                                (I40E_MAX_VF_VSI *
                                 sizeof(struct i40e_virtchnl_vsi_resource));
                        adapter->vf_res = kzalloc(bufsz, GFP_KERNEL);
-                       if (!adapter->vf_res) {
-                               dev_err(&pdev->dev, "%s: unable to allocate memory\n",
-                                       __func__);
+                       if (!adapter->vf_res)
                                goto err;
-                       }
                }
                err = i40evf_get_vf_config(adapter);
                if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
                        goto restart;
                if (err) {
-                       dev_info(&pdev->dev, "%s: unable to get VF config (%d)\n",
-                               __func__, err);
+                       dev_err(&pdev->dev, "Unable to get VF config (%d)\n",
+                               err);
                        goto err_alloc;
                }
                adapter->state = __I40EVF_INIT_SW;
@@ -1927,25 +2030,23 @@ static void i40evf_init_task(struct work_struct *work)
                        adapter->vsi_res = &adapter->vf_res->vsi_res[i];
        }
        if (!adapter->vsi_res) {
-               dev_info(&pdev->dev, "%s: no LAN VSI found\n", __func__);
+               dev_err(&pdev->dev, "No LAN VSI found\n");
                goto err_alloc;
        }
 
        adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED;
 
-       adapter->txd_count = I40EVF_DEFAULT_TXD;
-       adapter->rxd_count = I40EVF_DEFAULT_RXD;
-
        netdev->netdev_ops = &i40evf_netdev_ops;
        i40evf_set_ethtool_ops(netdev);
        netdev->watchdog_timeo = 5 * HZ;
-
-       netdev->features |= NETIF_F_SG |
+       netdev->features |= NETIF_F_HIGHDMA |
+                           NETIF_F_SG |
                            NETIF_F_IP_CSUM |
                            NETIF_F_SCTP_CSUM |
                            NETIF_F_IPV6_CSUM |
                            NETIF_F_TSO |
                            NETIF_F_TSO6 |
+                           NETIF_F_RXCSUM |
                            NETIF_F_GRO;
 
        if (adapter->vf_res->vf_offload_flags
@@ -1956,11 +2057,13 @@ static void i40evf_init_task(struct work_struct *work)
                                    NETIF_F_HW_VLAN_CTAG_FILTER;
        }
 
-       /* The HW MAC address was set and/or determined in sw_init */
+       /* copy netdev features into list of user selectable features */
+       netdev->hw_features |= netdev->features;
+       netdev->hw_features &= ~NETIF_F_RXCSUM;
+
        if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
-               dev_info(&pdev->dev,
-                       "Invalid MAC address %pMAC, using random\n",
-                       adapter->hw.mac.addr);
+               dev_info(&pdev->dev, "Invalid MAC address %pMAC, using random\n",
+                        adapter->hw.mac.addr);
                random_ether_addr(adapter->hw.mac.addr);
        }
        memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
@@ -1994,8 +2097,6 @@ static void i40evf_init_task(struct work_struct *work)
 
        netif_carrier_off(netdev);
 
-       strcpy(netdev->name, "eth%d");
-
        adapter->vsi.id = adapter->vsi_res->vsi_id;
        adapter->vsi.seid = adapter->vsi_res->vsi_id; /* dummy */
        adapter->vsi.back = adapter;
@@ -2005,9 +2106,11 @@ static void i40evf_init_task(struct work_struct *work)
        adapter->vsi.tx_itr_setting = I40E_ITR_DYNAMIC;
        adapter->vsi.netdev = adapter->netdev;
 
-       err = register_netdev(netdev);
-       if (err)
-               goto err_register;
+       if (!adapter->netdev_registered) {
+               err = register_netdev(netdev);
+               if (err)
+                       goto err_register;
+       }
 
        adapter->netdev_registered = true;
 
@@ -2031,7 +2134,6 @@ err_register:
        i40evf_free_misc_irq(adapter);
 err_sw_init:
        i40evf_reset_interrupt_capability(adapter);
-       adapter->state = __I40EVF_FAILED;
 err_alloc:
        kfree(adapter->vf_res);
        adapter->vf_res = NULL;
@@ -2039,9 +2141,7 @@ err:
        /* Things went into the weeds, so try again later */
        if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) {
                dev_err(&pdev->dev, "Failed to communicate with PF; giving up.\n");
-               if (hw->aq.asq.count)
-                       i40evf_shutdown_adminq(hw); /* ignore error */
-               adapter->state = __I40EVF_FAILED;
+               adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED;
                return; /* do not reschedule */
        }
        schedule_delayed_work(&adapter->init_task, HZ * 3);
@@ -2084,25 +2184,18 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct net_device *netdev;
        struct i40evf_adapter *adapter = NULL;
        struct i40e_hw *hw = NULL;
-       int err, pci_using_dac;
+       int err;
 
        err = pci_enable_device(pdev);
        if (err)
                return err;
 
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
-               pci_using_dac = true;
-               /* coherent mask for the same size will always succeed if
-                * dma_set_mask does
-                */
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-       } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
-               pci_using_dac = false;
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       } else {
-               dev_err(&pdev->dev, "%s: DMA configuration failed: %d\n",
-                        __func__, err);
-               err = -EIO;
+       err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+       if (err)
+               err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pdev->dev,
+                       "DMA configuration failed: 0x%x\n", err);
                goto err_dma;
        }
 
@@ -2128,8 +2221,6 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        pci_set_drvdata(pdev, netdev);
        adapter = netdev_priv(netdev);
-       if (pci_using_dac)
-               netdev->features |= NETIF_F_HIGHDMA;
 
        adapter->netdev = netdev;
        adapter->pdev = pdev;
@@ -2271,6 +2362,7 @@ static void i40evf_remove(struct pci_dev *pdev)
        struct i40e_hw *hw = &adapter->hw;
 
        cancel_delayed_work_sync(&adapter->init_task);
+       cancel_work_sync(&adapter->reset_task);
 
        if (adapter->netdev_registered) {
                unregister_netdev(netdev);
@@ -2278,17 +2370,15 @@ static void i40evf_remove(struct pci_dev *pdev)
        }
        adapter->state = __I40EVF_REMOVE;
 
-       if (adapter->num_msix_vectors) {
+       if (adapter->msix_entries) {
                i40evf_misc_irq_disable(adapter);
-               del_timer_sync(&adapter->watchdog_timer);
-
-               flush_scheduled_work();
-
                i40evf_free_misc_irq(adapter);
-
                i40evf_reset_interrupt_capability(adapter);
        }
 
+       del_timer_sync(&adapter->watchdog_timer);
+       flush_scheduled_work();
+
        if (hw->aq.asq.count)
                i40evf_shutdown_adminq(hw);
 
index e6978d79e62bb691a0434b3935b58d870f98f2f4..e294f012647d801417af4ca1f68d0629cbaf08cc 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver
- * Copyright(c) 2013 Intel Corporation.
+ * Copyright(c) 2013 - 2014 Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -43,6 +43,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter,
        struct i40e_hw *hw = &adapter->hw;
        i40e_status err;
 
+       if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
+               return 0; /* nothing to see here, move along */
+
        err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL);
        if (err)
                dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n",
@@ -651,6 +654,18 @@ void i40evf_request_stats(struct i40evf_adapter *adapter)
                /* if the request failed, don't lock out others */
                adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
 }
+/**
+ * i40evf_request_reset
+ * @adapter: adapter structure
+ *
+ * Request that the PF reset this VF. No response is expected.
+ **/
+void i40evf_request_reset(struct i40evf_adapter *adapter)
+{
+       /* Don't check CURRENT_OP - this is always higher priority */
+       i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0);
+       adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
+}
 
 /**
  * i40evf_virtchnl_completion
@@ -689,10 +704,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
                        }
                        break;
                case I40E_VIRTCHNL_EVENT_RESET_IMPENDING:
-                       adapter->state = __I40EVF_RESETTING;
-                       schedule_work(&adapter->reset_task);
-                       dev_info(&adapter->pdev->dev,
-                                "%s: hardware reset pending\n", __func__);
+                       dev_info(&adapter->pdev->dev, "PF reset warning received\n");
+                       if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) {
+                               adapter->flags |= I40EVF_FLAG_RESET_PENDING;
+                               dev_info(&adapter->pdev->dev, "Scheduling reset task\n");
+                               schedule_work(&adapter->reset_task);
+                       }
                        break;
                default:
                        dev_err(&adapter->pdev->dev,
index f19700e285bb5f5397b3ace776453974f4e8a9d5..5bcb2de75933ecad8866b6988f6c5d4cf6ad34c8 100644 (file)
@@ -1,7 +1,7 @@
 ################################################################################
 #
 # Intel 82575 PCI-Express Ethernet Linux driver
-# Copyright(c) 1999 - 2013 Intel Corporation.
+# Copyright(c) 1999 - 2014 Intel Corporation.
 #
 # This program is free software; you can redistribute it and/or modify it
 # under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
 # more details.
 #
 # You should have received a copy of the GNU General Public License along with
-# this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+# this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # The full GNU General Public License is included in this distribution in
 # the file called "COPYING".
index 06df6928f44c2942f3e9b51647d047d790a2d6af..fa36fe12e77502658cfe864780849d6f00e93c2e 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -77,8 +76,6 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw);
 static const u16 e1000_82580_rxpbs_table[] =
        { 36, 72, 144, 1, 2, 4, 8, 16,
          35, 70, 140 };
-#define E1000_82580_RXPBS_TABLE_SIZE \
-       (sizeof(e1000_82580_rxpbs_table)/sizeof(u16))
 
 /**
  *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
@@ -2308,7 +2305,7 @@ u16 igb_rxpbs_adjust_82580(u32 data)
 {
        u16 ret_val = 0;
 
-       if (data < E1000_82580_RXPBS_TABLE_SIZE)
+       if (data < ARRAY_SIZE(e1000_82580_rxpbs_table))
                ret_val = e1000_82580_rxpbs_table[data];
 
        return ret_val;
@@ -2714,13 +2711,14 @@ static const u8 e1000_emc_therm_limit[4] = {
        E1000_EMC_DIODE3_THERM_LIMIT
 };
 
+#ifdef CONFIG_IGB_HWMON
 /**
  *  igb_get_thermal_sensor_data_generic - Gathers thermal sensor data
  *  @hw: pointer to hardware structure
  *
  *  Updates the temperatures in mac.thermal_sensor_data
  **/
-s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
+static s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
 {
        s32 status = E1000_SUCCESS;
        u16 ets_offset;
@@ -2774,7 +2772,7 @@ s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw)
  *  Sets the thermal sensor thresholds according to the NVM map
  *  and save off the threshold and location values into mac.thermal_sensor_data
  **/
-s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
+static s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
 {
        s32 status = E1000_SUCCESS;
        u16 ets_offset;
@@ -2836,6 +2834,7 @@ s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw)
        return status;
 }
 
+#endif
 static struct e1000_mac_operations e1000_mac_ops_82575 = {
        .init_hw              = igb_init_hw_82575,
        .check_for_link       = igb_check_for_link_82575,
index 8c2437722aad2b32fec48bfc3f17bdf71db5c164..09d78be72416563beeda5e3cb72a7338b2aa7060 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -231,6 +230,10 @@ struct e1000_adv_tx_context_desc {
 #define E1000_VMOLR_STRVLAN    0x40000000 /* Vlan stripping enable */
 #define E1000_VMOLR_STRCRC     0x80000000 /* CRC stripping enable */
 
+#define E1000_DVMOLR_HIDEVLAN  0x20000000 /* Hide vlan enable */
+#define E1000_DVMOLR_STRVLAN   0x40000000 /* Vlan stripping enable */
+#define E1000_DVMOLR_STRCRC    0x80000000 /* CRC stripping enable */
+
 #define E1000_VLVF_ARRAY_SIZE     32
 #define E1000_VLVF_VLANID_MASK    0x00000FFF
 #define E1000_VLVF_POOLSEL_SHIFT  12
@@ -266,8 +269,7 @@ u16 igb_rxpbs_adjust_82580(u32 data);
 s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data);
 s32 igb_set_eee_i350(struct e1000_hw *);
 s32 igb_set_eee_i354(struct e1000_hw *);
-s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *);
-s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw);
+s32 igb_get_eee_status_i354(struct e1000_hw *hw, bool *status);
 
 #define E1000_I2C_THERMAL_SENSOR_ADDR  0xF8
 #define E1000_EMC_INTERNAL_DATA                0x00
index 0571b973be80d357bbbe4fec67c0fef0b3859546..b05bf925ac721982d8ded6d3aa647d64236890f4 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
 #define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
 
 /* Extended Device Control */
+#define E1000_CTRL_EXT_SDP2_DATA 0x00000040 /* Value of SW Defineable Pin 2 */
 #define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Defineable Pin 3 */
+#define E1000_CTRL_EXT_SDP2_DIR  0x00000400 /* SDP2 Data direction */
+#define E1000_CTRL_EXT_SDP3_DIR  0x00000800 /* SDP3 Data direction */
+
 /* Physical Func Reset Done Indication */
 #define E1000_CTRL_EXT_PFRSTD    0x00004000
 #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
 /* enable link status from external LINK_0 and LINK_1 pins */
 #define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
 #define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
-#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SDP0_DIR 0x00400000  /* SDP0 Data direction */
+#define E1000_CTRL_SDP1_DIR 0x00800000  /* SDP1 Data direction */
 #define E1000_CTRL_RST      0x04000000  /* Global reset */
 #define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
 #define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
 
 #define E1000_TIMINCA_16NS_SHIFT 24
 
-#define E1000_TSICR_TXTS 0x00000002
-#define E1000_TSIM_TXTS 0x00000002
+/* Time Sync Interrupt Cause/Mask Register Bits */
+
+#define TSINTR_SYS_WRAP  (1 << 0) /* SYSTIM Wrap around. */
+#define TSINTR_TXTS      (1 << 1) /* Transmit Timestamp. */
+#define TSINTR_RXTS      (1 << 2) /* Receive Timestamp. */
+#define TSINTR_TT0       (1 << 3) /* Target Time 0 Trigger. */
+#define TSINTR_TT1       (1 << 4) /* Target Time 1 Trigger. */
+#define TSINTR_AUTT0     (1 << 5) /* Auxiliary Timestamp 0 Taken. */
+#define TSINTR_AUTT1     (1 << 6) /* Auxiliary Timestamp 1 Taken. */
+#define TSINTR_TADJ      (1 << 7) /* Time Adjust Done. */
+
+#define TSYNC_INTERRUPTS TSINTR_TXTS
+#define E1000_TSICR_TXTS TSINTR_TXTS
+
+/* TSAUXC Configuration Bits */
+#define TSAUXC_EN_TT0    (1 << 0)  /* Enable target time 0. */
+#define TSAUXC_EN_TT1    (1 << 1)  /* Enable target time 1. */
+#define TSAUXC_EN_CLK0   (1 << 2)  /* Enable Configurable Frequency Clock 0. */
+#define TSAUXC_SAMP_AUT0 (1 << 3)  /* Latch SYSTIML/H into AUXSTMPL/0. */
+#define TSAUXC_ST0       (1 << 4)  /* Start Clock 0 Toggle on Target Time 0. */
+#define TSAUXC_EN_CLK1   (1 << 5)  /* Enable Configurable Frequency Clock 1. */
+#define TSAUXC_SAMP_AUT1 (1 << 6)  /* Latch SYSTIML/H into AUXSTMPL/1. */
+#define TSAUXC_ST1       (1 << 7)  /* Start Clock 1 Toggle on Target Time 1. */
+#define TSAUXC_EN_TS0    (1 << 8)  /* Enable hardware timestamp 0. */
+#define TSAUXC_AUTT0     (1 << 9)  /* Auxiliary Timestamp Taken. */
+#define TSAUXC_EN_TS1    (1 << 10) /* Enable hardware timestamp 0. */
+#define TSAUXC_AUTT1     (1 << 11) /* Auxiliary Timestamp Taken. */
+#define TSAUXC_PLSG      (1 << 17) /* Generate a pulse. */
+#define TSAUXC_DISABLE   (1 << 31) /* Disable SYSTIM Count Operation. */
+
+/* SDP Configuration Bits */
+#define AUX0_SEL_SDP0    (0 << 0)  /* Assign SDP0 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP1    (1 << 0)  /* Assign SDP1 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP2    (2 << 0)  /* Assign SDP2 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP3    (3 << 0)  /* Assign SDP3 to auxiliary time stamp 0. */
+#define AUX0_TS_SDP_EN   (1 << 2)  /* Enable auxiliary time stamp trigger 0. */
+#define AUX1_SEL_SDP0    (0 << 3)  /* Assign SDP0 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP1    (1 << 3)  /* Assign SDP1 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP2    (2 << 3)  /* Assign SDP2 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP3    (3 << 3)  /* Assign SDP3 to auxiliary time stamp 1. */
+#define AUX1_TS_SDP_EN   (1 << 5)  /* Enable auxiliary time stamp trigger 1. */
+#define TS_SDP0_SEL_TT0  (0 << 6)  /* Target time 0 is output on SDP0. */
+#define TS_SDP0_SEL_TT1  (1 << 6)  /* Target time 1 is output on SDP0. */
+#define TS_SDP0_SEL_FC0  (2 << 6)  /* Freq clock  0 is output on SDP0. */
+#define TS_SDP0_SEL_FC1  (3 << 6)  /* Freq clock  1 is output on SDP0. */
+#define TS_SDP0_EN       (1 << 8)  /* SDP0 is assigned to Tsync. */
+#define TS_SDP1_SEL_TT0  (0 << 9)  /* Target time 0 is output on SDP1. */
+#define TS_SDP1_SEL_TT1  (1 << 9)  /* Target time 1 is output on SDP1. */
+#define TS_SDP1_SEL_FC0  (2 << 9)  /* Freq clock  0 is output on SDP1. */
+#define TS_SDP1_SEL_FC1  (3 << 9)  /* Freq clock  1 is output on SDP1. */
+#define TS_SDP1_EN       (1 << 11) /* SDP1 is assigned to Tsync. */
+#define TS_SDP2_SEL_TT0  (0 << 12) /* Target time 0 is output on SDP2. */
+#define TS_SDP2_SEL_TT1  (1 << 12) /* Target time 1 is output on SDP2. */
+#define TS_SDP2_SEL_FC0  (2 << 12) /* Freq clock  0 is output on SDP2. */
+#define TS_SDP2_SEL_FC1  (3 << 12) /* Freq clock  1 is output on SDP2. */
+#define TS_SDP2_EN       (1 << 14) /* SDP2 is assigned to Tsync. */
+#define TS_SDP3_SEL_TT0  (0 << 15) /* Target time 0 is output on SDP3. */
+#define TS_SDP3_SEL_TT1  (1 << 15) /* Target time 1 is output on SDP3. */
+#define TS_SDP3_SEL_FC0  (2 << 15) /* Freq clock  0 is output on SDP3. */
+#define TS_SDP3_SEL_FC1  (3 << 15) /* Freq clock  1 is output on SDP3. */
+#define TS_SDP3_EN       (1 << 17) /* SDP3 is assigned to Tsync. */
 
 #define E1000_MDICNFG_EXT_MDIO    0x80000000      /* MDI ext/int destination */
 #define E1000_MDICNFG_COM_MDIO    0x40000000      /* MDI shared w/ lan 0 */
index ab99e2b582a85c7b445d54ec85f867c431cf1e29..10741d170f2ddad46b2fad14d362998bdc19d639 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index 0c0393316a3a4eb0b3784e72003cf6367bba8061..db963397cc27f42fd15829ec6dc540e19af5f562 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -35,6 +34,8 @@
 #include "e1000_hw.h"
 #include "e1000_i210.h"
 
+static s32 igb_update_flash_i210(struct e1000_hw *hw);
+
 /**
  * igb_get_hw_semaphore_i210 - Acquire hardware semaphore
  *  @hw: pointer to the HW structure
@@ -111,7 +112,7 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw)
  *  Return successful if access grant bit set, else clear the request for
  *  EEPROM access and return -E1000_ERR_NVM (-1).
  **/
-s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
+static s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
 {
        return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
 }
@@ -123,7 +124,7 @@ s32 igb_acquire_nvm_i210(struct e1000_hw *hw)
  *  Stop any current commands to the EEPROM and clear the EEPROM request bit,
  *  then release the semaphores acquired.
  **/
-void igb_release_nvm_i210(struct e1000_hw *hw)
+static void igb_release_nvm_i210(struct e1000_hw *hw)
 {
        igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM);
 }
@@ -206,8 +207,8 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask)
  *  Reads a 16 bit word from the Shadow Ram using the EERD register.
  *  Uses necessary synchronization semaphores.
  **/
-s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
-                            u16 *data)
+static s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
+                                 u16 *data)
 {
        s32 status = E1000_SUCCESS;
        u16 i, count;
@@ -306,8 +307,8 @@ out:
  *  If error code is returned, data and Shadow RAM may be inconsistent - buffer
  *  partially written.
  **/
-s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
-                             u16 *data)
+static s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
+                                  u16 *data)
 {
        s32 status = E1000_SUCCESS;
        u16 i, count;
@@ -555,7 +556,7 @@ s32 igb_read_invm_version(struct e1000_hw *hw,
  *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
  *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
  **/
-s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
+static s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
 {
        s32 status = E1000_SUCCESS;
        s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *);
@@ -590,7 +591,7 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw)
  *  up to the checksum.  Then calculates the EEPROM checksum and writes the
  *  value to the EEPROM. Next commit EEPROM data onto the Flash.
  **/
-s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
+static s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw)
 {
        s32 ret_val = E1000_SUCCESS;
        u16 checksum = 0;
@@ -684,7 +685,7 @@ bool igb_get_flash_presence_i210(struct e1000_hw *hw)
  *  @hw: pointer to the HW structure
  *
  **/
-s32 igb_update_flash_i210(struct e1000_hw *hw)
+static s32 igb_update_flash_i210(struct e1000_hw *hw)
 {
        s32 ret_val = E1000_SUCCESS;
        u32 flup;
index 2d913716573a29a830610de841164e30e505cdfb..907fe99a9813130e45a3dddf0d5d48c6dfdc492d 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
 #ifndef _E1000_I210_H_
 #define _E1000_I210_H_
 
-s32 igb_update_flash_i210(struct e1000_hw *hw);
-s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw);
-s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw);
-s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words,
-                           u16 *data);
-s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words,
-                          u16 *data);
 s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
 void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask);
-s32 igb_acquire_nvm_i210(struct e1000_hw *hw);
-void igb_release_nvm_i210(struct e1000_hw *hw);
 s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data);
 s32 igb_read_invm_version(struct e1000_hw *hw,
                          struct e1000_fw_version *invm_ver);
index 298f0ed50670c0388a53e82d3509beca6aaf351e..5910a932ea7c92cb67223a7c900f7c3b3e36a990 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index e4cbe8ef67b3094b32b73cbccda9be5673243d1f..99299ba8ee3a2def53ab2e6fcc8c5c039aca0265 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index dac1447fabf74620e562ebf38feb4f367db2ec4f..d5b121771c313716543b16f5a8464866afd4f8e2 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index de9bba41acf3c01b2f744e6cb30511ca97a514ac..f52f5515e5a8a8aedcc1568f90fdf1b986b2947e 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index a7db7f3db914daafb957d11372b885614152020c..9abf82919c65535d7b3fd7f7d7200f80fffd1f0a 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index 433b7419cb98ad15bb3da0532fb120ff25ff4596..5b101170b17e4bbc9af310c8aacd5e0b891344a0 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index ad2b74d95138c1542bb78a55b7d620e5695f2abb..4009bbab7407d21945e7c1af20df5deedba564a3 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -393,77 +392,6 @@ s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data)
        return 0;
 }
 
-/**
- *  e1000_write_sfp_data_byte - Writes SFP module data.
- *  @hw: pointer to the HW structure
- *  @offset: byte location offset to write to
- *  @data: data to write
- *
- *  Writes one byte to SFP module data stored
- *  in SFP resided EEPROM memory or SFP diagnostic area.
- *  Function should be called with
- *  E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access
- *  E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters
- *  access
- **/
-s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data)
-{
-       u32 i = 0;
-       u32 i2ccmd = 0;
-       u32 data_local = 0;
-
-       if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) {
-               hw_dbg("I2CCMD command address exceeds upper limit\n");
-               return -E1000_ERR_PHY;
-       }
-       /* The programming interface is 16 bits wide
-        * so we need to read the whole word first
-        * then update appropriate byte lane and write
-        * the updated word back.
-        */
-       /* Set up Op-code, EEPROM Address,in the I2CCMD
-        * register. The MAC will take care of interfacing
-        * with an EEPROM to write the data given.
-        */
-       i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) |
-                 E1000_I2CCMD_OPCODE_READ);
-       /* Set a command to read single word */
-       wr32(E1000_I2CCMD, i2ccmd);
-       for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) {
-               udelay(50);
-               /* Poll the ready bit to see if lastly
-                * launched I2C operation completed
-                */
-               i2ccmd = rd32(E1000_I2CCMD);
-               if (i2ccmd & E1000_I2CCMD_READY) {
-                       /* Check if this is READ or WRITE phase */
-                       if ((i2ccmd & E1000_I2CCMD_OPCODE_READ) ==
-                           E1000_I2CCMD_OPCODE_READ) {
-                               /* Write the selected byte
-                                * lane and update whole word
-                                */
-                               data_local = i2ccmd & 0xFF00;
-                               data_local |= data;
-                               i2ccmd = ((offset <<
-                                       E1000_I2CCMD_REG_ADDR_SHIFT) |
-                                       E1000_I2CCMD_OPCODE_WRITE | data_local);
-                               wr32(E1000_I2CCMD, i2ccmd);
-                       } else {
-                               break;
-                       }
-               }
-       }
-       if (!(i2ccmd & E1000_I2CCMD_READY)) {
-               hw_dbg("I2CCMD Write did not complete\n");
-               return -E1000_ERR_PHY;
-       }
-       if (i2ccmd & E1000_I2CCMD_ERROR) {
-               hw_dbg("I2CCMD Error bit set\n");
-               return -E1000_ERR_PHY;
-       }
-       return 0;
-}
-
 /**
  *  igb_read_phy_reg_igp - Read igp PHY register
  *  @hw: pointer to the HW structure
index 6a0873f2095a49affef31c68ced1dd0d785aa265..4c2c36c46a7398d217c1418b3966b4cde5813812 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -70,7 +69,6 @@ s32  igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
 s32  igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
 s32  igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
 s32  igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data);
-s32  e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data);
 s32  igb_copper_link_setup_82580(struct e1000_hw *hw);
 s32  igb_get_phy_info_82580(struct e1000_hw *hw);
 s32  igb_phy_force_speed_duplex_82580(struct e1000_hw *hw);
index 82632c6c53afcb37239f2898eea9a01f5f95edfd..bdb246e848e13bb5e569f279336dbb5a2c5bfe86 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -41,6 +40,7 @@
 #define E1000_FCT      0x00030  /* Flow Control Type - RW */
 #define E1000_CONNSW   0x00034  /* Copper/Fiber switch control - RW */
 #define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_TSSDP    0x0003C  /* Time Sync SDP Configuration Register - RW */
 #define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
 #define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
 #define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
 #define E1000_SYSTIMH    0x0B604 /* System time register High - RO */
 #define E1000_TIMINCA    0x0B608 /* Increment attributes register - RW */
 #define E1000_TSAUXC     0x0B640 /* Timesync Auxiliary Control register */
+#define E1000_TRGTTIML0  0x0B644 /* Target Time Register 0 Low  - RW */
+#define E1000_TRGTTIMH0  0x0B648 /* Target Time Register 0 High - RW */
+#define E1000_TRGTTIML1  0x0B64C /* Target Time Register 1 Low  - RW */
+#define E1000_TRGTTIMH1  0x0B650 /* Target Time Register 1 High - RW */
+#define E1000_AUXSTMPL0  0x0B65C /* Auxiliary Time Stamp 0 Register Low  - RO */
+#define E1000_AUXSTMPH0  0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
+#define E1000_AUXSTMPL1  0x0B664 /* Auxiliary Time Stamp 1 Register Low  - RO */
+#define E1000_AUXSTMPH1  0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
 #define E1000_SYSTIMR    0x0B6F8 /* System time register Residue */
 #define E1000_TSICR      0x0B66C /* Interrupt Cause Register */
 #define E1000_TSIM       0x0B674 /* Interrupt Mask Register */
 #define E1000_P2VMAILBOX(_n)   (0x00C00 + (4 * (_n)))
 #define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
 #define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
+#define E1000_DVMOLR(_n)       (0x0C038 + (64 * (_n)))
 #define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
                                                        * Filter - RW */
 #define E1000_VMVIR(_n)        (0x03700 + (4 * (_n)))
 
-#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
-#define rd32(reg) (readl(hw->hw_addr + reg))
+struct e1000_hw;
+
+u32 igb_rd32(struct e1000_hw *hw, u32 reg);
+
+/* write operations, indexed using DWORDS */
+#define wr32(reg, val) \
+do { \
+       u8 __iomem *hw_addr = ACCESS_ONCE((hw)->hw_addr); \
+       if (!E1000_REMOVED(hw_addr)) \
+               writel((val), &hw_addr[(reg)]); \
+} while (0)
+
+#define rd32(reg) (igb_rd32(hw, reg))
+
 #define wrfl() ((void)rd32(E1000_STATUS))
 
 #define array_wr32(reg, offset, value) \
-       (writel(value, hw->hw_addr + reg + ((offset) << 2)))
+       wr32((reg) + ((offset) << 2), (value))
+
 #define array_rd32(reg, offset) \
        (readl(hw->hw_addr + reg + ((offset) << 2)))
 
 #define E1000_INVM_DATA_REG(_n)        (0x12120 + 4*(_n))
 #define E1000_INVM_SIZE                64 /* Number of INVM Data Registers */
 
+#define E1000_REMOVED(h) unlikely(!(h))
+
 #endif
index ccf472f073ddde8865b1733ce1c88aae53225801..7fbe1e925143efb7b4af4b9f06c29fa3027d2e7e 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -42,6 +41,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/pci.h>
+#include <linux/mdio.h>
 
 struct igb_adapter;
 
@@ -434,6 +434,7 @@ struct igb_adapter {
        struct delayed_work ptp_overflow_work;
        struct work_struct ptp_tx_work;
        struct sk_buff *ptp_tx_skb;
+       struct hwtstamp_config tstamp_config;
        unsigned long ptp_tx_start;
        unsigned long last_rx_ptp_check;
        spinlock_t tmreg_lock;
@@ -456,6 +457,7 @@ struct igb_adapter {
        unsigned long link_check_timeout;
        int copper_tries;
        struct e1000_info ei;
+       u16 eee_advert;
 };
 
 #define IGB_FLAG_HAS_MSI               (1 << 0)
@@ -472,6 +474,7 @@ struct igb_adapter {
 #define IGB_FLAG_MAS_CAPABLE           (1 << 11)
 #define IGB_FLAG_MAS_ENABLE            (1 << 12)
 #define IGB_FLAG_HAS_MSIX              (1 << 13)
+#define IGB_FLAG_EEE                   (1 << 14)
 
 /* Media Auto Sense */
 #define IGB_MAS_ENABLE_0               0X0001
@@ -489,7 +492,8 @@ struct igb_adapter {
 enum e1000_state_t {
        __IGB_TESTING,
        __IGB_RESETTING,
-       __IGB_DOWN
+       __IGB_DOWN,
+       __IGB_PTP_TX_IN_PROGRESS,
 };
 
 enum igb_boards {
@@ -525,9 +529,7 @@ void igb_set_fw_version(struct igb_adapter *);
 void igb_ptp_init(struct igb_adapter *adapter);
 void igb_ptp_stop(struct igb_adapter *adapter);
 void igb_ptp_reset(struct igb_adapter *adapter);
-void igb_ptp_tx_work(struct work_struct *work);
 void igb_ptp_rx_hang(struct igb_adapter *adapter);
-void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
 void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb);
 void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va,
                         struct sk_buff *skb);
@@ -545,8 +547,8 @@ static inline void igb_ptp_rx_hwtstamp(struct igb_ring *rx_ring,
        rx_ring->last_rx_timestamp = jiffies;
 }
 
-int igb_ptp_hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr,
-                          int cmd);
+int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr);
+int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr);
 #ifdef CONFIG_IGB_HWMON
 void igb_sysfs_exit(struct igb_adapter *adapter);
 int igb_sysfs_init(struct igb_adapter *adapter);
index 1df02378de6949ddf5fd11aff02548ba2fba6625..e5570acbeea84509855a98383ab128876e7447c9 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -2274,15 +2273,15 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
 
                ring = adapter->tx_ring[j];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
                        data[i]   = ring->tx_stats.packets;
                        data[i+1] = ring->tx_stats.bytes;
                        data[i+2] = ring->tx_stats.restart_queue;
-               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp2);
+                       start = u64_stats_fetch_begin_irq(&ring->tx_syncp2);
                        restart2  = ring->tx_stats.restart_queue2;
-               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp2, start));
+               } while (u64_stats_fetch_retry_irq(&ring->tx_syncp2, start));
                data[i+2] += restart2;
 
                i += IGB_TX_QUEUE_STATS_LEN;
@@ -2290,13 +2289,13 @@ static void igb_get_ethtool_stats(struct net_device *netdev,
        for (j = 0; j < adapter->num_rx_queues; j++) {
                ring = adapter->rx_ring[j];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
                        data[i]   = ring->rx_stats.packets;
                        data[i+1] = ring->rx_stats.bytes;
                        data[i+2] = ring->rx_stats.drops;
                        data[i+3] = ring->rx_stats.csum_err;
                        data[i+4] = ring->rx_stats.alloc_failed;
-               } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
                i += IGB_RX_QUEUE_STATS_LEN;
        }
        spin_unlock(&adapter->stats64_lock);
@@ -2354,6 +2353,11 @@ static int igb_get_ts_info(struct net_device *dev,
 {
        struct igb_adapter *adapter = netdev_priv(dev);
 
+       if (adapter->ptp_clock)
+               info->phc_index = ptp_clock_index(adapter->ptp_clock);
+       else
+               info->phc_index = -1;
+
        switch (adapter->hw.mac.type) {
        case e1000_82575:
                info->so_timestamping =
@@ -2375,11 +2379,6 @@ static int igb_get_ts_info(struct net_device *dev,
                        SOF_TIMESTAMPING_RX_HARDWARE |
                        SOF_TIMESTAMPING_RAW_HARDWARE;
 
-               if (adapter->ptp_clock)
-                       info->phc_index = ptp_clock_index(adapter->ptp_clock);
-               else
-                       info->phc_index = -1;
-
                info->tx_types =
                        (1 << HWTSTAMP_TX_OFF) |
                        (1 << HWTSTAMP_TX_ON);
@@ -2588,7 +2587,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       u32 ipcnfg, eeer, ret_val;
+       u32 ret_val;
        u16 phy_data;
 
        if ((hw->mac.type < e1000_i350) ||
@@ -2597,16 +2596,25 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
 
        edata->supported = (SUPPORTED_1000baseT_Full |
                            SUPPORTED_100baseT_Full);
+       if (!hw->dev_spec._82575.eee_disable)
+               edata->advertised =
+                       mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
+
+       /* The IPCNFG and EEER registers are not supported on I354. */
+       if (hw->mac.type == e1000_i354) {
+               igb_get_eee_status_i354(hw, (bool *)&edata->eee_active);
+       } else {
+               u32 eeer;
 
-       ipcnfg = rd32(E1000_IPCNFG);
-       eeer = rd32(E1000_EEER);
+               eeer = rd32(E1000_EEER);
 
-       /* EEE status on negotiated link */
-       if (ipcnfg & E1000_IPCNFG_EEE_1G_AN)
-               edata->advertised = ADVERTISED_1000baseT_Full;
+               /* EEE status on negotiated link */
+               if (eeer & E1000_EEER_EEE_NEG)
+                       edata->eee_active = true;
 
-       if (ipcnfg & E1000_IPCNFG_EEE_100M_AN)
-               edata->advertised |= ADVERTISED_100baseT_Full;
+               if (eeer & E1000_EEER_TX_LPI_EN)
+                       edata->tx_lpi_enabled = true;
+       }
 
        /* EEE Link Partner Advertised */
        switch (hw->mac.type) {
@@ -2617,8 +2625,8 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
                        return -ENODATA;
 
                edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
-
                break;
+       case e1000_i354:
        case e1000_i210:
        case e1000_i211:
                ret_val = igb_read_xmdio_reg(hw, E1000_EEE_LP_ADV_ADDR_I210,
@@ -2634,12 +2642,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
                break;
        }
 
-       if (eeer & E1000_EEER_EEE_NEG)
-               edata->eee_active = true;
-
        edata->eee_enabled = !hw->dev_spec._82575.eee_disable;
 
-       if (eeer & E1000_EEER_TX_LPI_EN)
+       if ((hw->mac.type == e1000_i354) &&
+           (edata->eee_enabled))
                edata->tx_lpi_enabled = true;
 
        /* Report correct negotiated EEE status for devices that
@@ -2687,9 +2693,10 @@ static int igb_set_eee(struct net_device *netdev,
                        return -EINVAL;
                }
 
-               if (eee_curr.advertised != edata->advertised) {
+               if (edata->advertised &
+                   ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
                        dev_err(&adapter->pdev->dev,
-                               "Setting EEE Advertisement is not supported\n");
+                               "EEE Advertisement supports only 100Tx and or 100T full duplex\n");
                        return -EINVAL;
                }
 
@@ -2699,9 +2706,14 @@ static int igb_set_eee(struct net_device *netdev,
                        return -EINVAL;
                }
 
+       adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
        if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
                hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
-               igb_set_eee_i350(hw);
+               adapter->flags |= IGB_FLAG_EEE;
+               if (hw->mac.type == e1000_i350)
+                       igb_set_eee_i350(hw);
+               else
+                       igb_set_eee_i354(hw);
 
                /* reset link */
                if (netif_running(netdev))
@@ -2779,9 +2791,11 @@ static int igb_get_module_eeprom(struct net_device *netdev,
        /* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
        for (i = 0; i < last_word - first_word + 1; i++) {
                status = igb_read_phy_reg_i2c(hw, first_word + i, &dataword[i]);
-               if (status != E1000_SUCCESS)
+               if (status != E1000_SUCCESS) {
                        /* Error occurred while reading module */
+                       kfree(dataword);
                        return -EIO;
+               }
 
                be16_to_cpus(&dataword[i]);
        }
index e0af5bc616139bc6540577952175345053399dd1..8333f67acf96b3a6e83746c1cedd1f0eff7636ec 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  this program; if not, see <http://www.gnu.org/licenses/>.
 
   The full GNU General Public License is included in this distribution in
   the file called "COPYING".
index 46d31a49f5ea677d27a2162c672bca6bf27cc0c6..55fc5596e2d045042a3f33251440fdc137214d13 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel(R) Gigabit Ethernet Linux driver
-  Copyright(c) 2007-2013 Intel Corporation.
+  Copyright(c) 2007-2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -13,8 +13,7 @@
   more details.
 
   You should have received a copy of the GNU General Public License along with
-  this program; if not, write to the Free Software Foundation, Inc.,
-  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+  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".
@@ -70,7 +69,7 @@ char igb_driver_version[] = DRV_VERSION;
 static const char igb_driver_string[] =
                                "Intel(R) Gigabit Ethernet Network Driver";
 static const char igb_copyright[] =
-                               "Copyright (c) 2007-2013 Intel Corporation.";
+                               "Copyright (c) 2007-2014 Intel Corporation.";
 
 static const struct e1000_info *igb_info_tbl[] = {
        [board_82575] = &e1000_82575_info,
@@ -752,6 +751,28 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
        }
 }
 
+u32 igb_rd32(struct e1000_hw *hw, u32 reg)
+{
+       struct igb_adapter *igb = container_of(hw, struct igb_adapter, hw);
+       u8 __iomem *hw_addr = ACCESS_ONCE(hw->hw_addr);
+       u32 value = 0;
+
+       if (E1000_REMOVED(hw_addr))
+               return ~value;
+
+       value = readl(&hw_addr[reg]);
+
+       /* reads should not return all F's */
+       if (!(~value) && (!reg || !(~readl(hw_addr)))) {
+               struct net_device *netdev = igb->netdev;
+               hw->hw_addr = NULL;
+               netif_device_detach(netdev);
+               netdev_err(netdev, "PCIe link lost, device now detached\n");
+       }
+
+       return value;
+}
+
 /**
  *  igb_write_ivar - configure ivar for given MSI-X vector
  *  @hw: pointer to the HW structure
@@ -1014,6 +1035,12 @@ static void igb_reset_q_vector(struct igb_adapter *adapter, int v_idx)
 {
        struct igb_q_vector *q_vector = adapter->q_vector[v_idx];
 
+       /* Coming from igb_set_interrupt_capability, the vectors are not yet
+        * allocated. So, q_vector is NULL so we should stop here.
+        */
+       if (!q_vector)
+               return;
+
        if (q_vector->tx.ring)
                adapter->tx_ring[q_vector->tx.ring->queue_index] = NULL;
 
@@ -1111,16 +1138,18 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter, bool msix)
        for (i = 0; i < numvecs; i++)
                adapter->msix_entries[i].entry = i;
 
-       err = pci_enable_msix(adapter->pdev,
-                             adapter->msix_entries,
-                             numvecs);
-       if (err == 0)
+       err = pci_enable_msix_range(adapter->pdev,
+                                   adapter->msix_entries,
+                                   numvecs,
+                                   numvecs);
+       if (err > 0)
                return;
 
        igb_reset_interrupt_capability(adapter);
 
        /* If we can't do MSI-X, try MSI */
 msi_only:
+       adapter->flags &= ~IGB_FLAG_HAS_MSIX;
 #ifdef CONFIG_PCI_IOV
        /* disable SR-IOV for non MSI-X configurations */
        if (adapter->vf_data) {
@@ -1726,6 +1755,10 @@ int igb_up(struct igb_adapter *adapter)
        hw->mac.get_link_status = 1;
        schedule_work(&adapter->watchdog_task);
 
+       if ((adapter->flags & IGB_FLAG_EEE) &&
+           (!hw->dev_spec._82575.eee_disable))
+               adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T;
+
        return 0;
 }
 
@@ -1974,6 +2007,21 @@ void igb_reset(struct igb_adapter *adapter)
                }
        }
 #endif
+       /* Re-establish EEE setting */
+       if (hw->phy.media_type == e1000_media_type_copper) {
+               switch (mac->type) {
+               case e1000_i350:
+               case e1000_i210:
+               case e1000_i211:
+                       igb_set_eee_i350(hw);
+                       break;
+               case e1000_i354:
+                       igb_set_eee_i354(hw);
+                       break;
+               default:
+                       break;
+               }
+       }
        if (!netif_running(adapter->netdev))
                igb_power_down_link(adapter);
 
@@ -2560,23 +2608,36 @@ static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                (adapter->flags & IGB_FLAG_HAS_MSIX) ? "MSI-X" :
                (adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy",
                adapter->num_rx_queues, adapter->num_tx_queues);
-       switch (hw->mac.type) {
-       case e1000_i350:
-       case e1000_i210:
-       case e1000_i211:
-               igb_set_eee_i350(hw);
-               break;
-       case e1000_i354:
-               if (hw->phy.media_type == e1000_media_type_copper) {
+       if (hw->phy.media_type == e1000_media_type_copper) {
+               switch (hw->mac.type) {
+               case e1000_i350:
+               case e1000_i210:
+               case e1000_i211:
+                       /* Enable EEE for internal copper PHY devices */
+                       err = igb_set_eee_i350(hw);
+                       if ((!err) &&
+                           (!hw->dev_spec._82575.eee_disable)) {
+                               adapter->eee_advert =
+                                       MDIO_EEE_100TX | MDIO_EEE_1000T;
+                               adapter->flags |= IGB_FLAG_EEE;
+                       }
+                       break;
+               case e1000_i354:
                        if ((rd32(E1000_CTRL_EXT) &
-                           E1000_CTRL_EXT_LINK_MODE_SGMII))
-                               igb_set_eee_i354(hw);
+                           E1000_CTRL_EXT_LINK_MODE_SGMII)) {
+                               err = igb_set_eee_i354(hw);
+                               if ((!err) &&
+                                       (!hw->dev_spec._82575.eee_disable)) {
+                                       adapter->eee_advert =
+                                          MDIO_EEE_100TX | MDIO_EEE_1000T;
+                                       adapter->flags |= IGB_FLAG_EEE;
+                               }
+                       }
+                       break;
+               default:
+                       break;
                }
-               break;
-       default:
-               break;
        }
-
        pm_runtime_put_noidle(&pdev->dev);
        return 0;
 
@@ -3510,6 +3571,13 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter,
 
        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
@@ -4158,6 +4226,15 @@ static void igb_watchdog_task(struct work_struct *work)
                               (ctrl & E1000_CTRL_RFCE) ?  "RX" :
                               (ctrl & E1000_CTRL_TFCE) ?  "TX" : "None");
 
+                       /* disable EEE if enabled */
+                       if ((adapter->flags & IGB_FLAG_EEE) &&
+                               (adapter->link_duplex == HALF_DUPLEX)) {
+                               dev_info(&adapter->pdev->dev,
+                               "EEE Disabled: unsupported at half duplex. Re-enable using ethtool when at full duplex.\n");
+                               adapter->hw.dev_spec._82575.eee_disable = true;
+                               adapter->flags &= ~IGB_FLAG_EEE;
+                       }
+
                        /* check if SmartSpeed worked */
                        igb_check_downshift(hw);
                        if (phy->speed_downgraded)
@@ -4306,8 +4383,7 @@ enum latency_range {
  *  were determined based on theoretical maximum wire speed and testing
  *  data, in order to minimize response time while increasing bulk
  *  throughput.
- *  This functionality is controlled by the InterruptThrottleRate module
- *  parameter (see igb_param.c)
+ *  This functionality is controlled by ethtool's coalescing settings.
  *  NOTE:  This function is called only when operating in a multiqueue
  *         receive environment.
  **/
@@ -4381,8 +4457,7 @@ clear_counts:
  *  based on theoretical maximum wire speed and thresholds were set based
  *  on testing data as well as attempting to minimize response time
  *  while increasing bulk throughput.
- *  this functionality is controlled by the InterruptThrottleRate module
- *  parameter (see igb_param.c)
+ *  This functionality is controlled by ethtool's coalescing settings.
  *  NOTE:  These calculations are only valid when operating in a single-
  *         queue environment.
  **/
@@ -4546,7 +4621,7 @@ static int igb_tso(struct igb_ring *tx_ring,
        /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
        type_tucmd = E1000_ADVTXD_TUCMD_L4T_TCP;
 
-       if (first->protocol == __constant_htons(ETH_P_IP)) {
+       if (first->protocol == htons(ETH_P_IP)) {
                struct iphdr *iph = ip_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
@@ -4602,12 +4677,12 @@ static void igb_tx_csum(struct igb_ring *tx_ring, struct igb_tx_buffer *first)
        } else {
                u8 l4_hdr = 0;
                switch (first->protocol) {
-               case __constant_htons(ETH_P_IP):
+               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 __constant_htons(ETH_P_IPV6):
+               case htons(ETH_P_IPV6):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        l4_hdr = ipv6_hdr(skb)->nexthdr;
                        break;
@@ -4905,12 +4980,11 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
        first->bytecount = skb->len;
        first->gso_segs = 1;
 
-       skb_tx_timestamp(skb);
-
        if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
                struct igb_adapter *adapter = netdev_priv(tx_ring->netdev);
 
-               if (!(adapter->ptp_tx_skb)) {
+               if (!test_and_set_bit_lock(__IGB_PTP_TX_IN_PROGRESS,
+                                          &adapter->state)) {
                        skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                        tx_flags |= IGB_TX_FLAGS_TSTAMP;
 
@@ -4921,6 +4995,8 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
                }
        }
 
+       skb_tx_timestamp(skb);
+
        if (vlan_tx_tag_present(skb)) {
                tx_flags |= IGB_TX_FLAGS_VLAN;
                tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
@@ -5127,10 +5203,10 @@ void igb_update_stats(struct igb_adapter *adapter,
                }
 
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->rx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->rx_syncp);
                        _bytes = ring->rx_stats.bytes;
                        _packets = ring->rx_stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->rx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->rx_syncp, start));
                bytes += _bytes;
                packets += _packets;
        }
@@ -5143,10 +5219,10 @@ void igb_update_stats(struct igb_adapter *adapter,
        for (i = 0; i < adapter->num_tx_queues; i++) {
                struct igb_ring *ring = adapter->tx_ring[i];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->tx_syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->tx_syncp);
                        _bytes = ring->tx_stats.bytes;
                        _packets = ring->tx_stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->tx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->tx_syncp, start));
                bytes += _bytes;
                packets += _packets;
        }
@@ -6620,7 +6696,9 @@ static inline void igb_rx_hash(struct igb_ring *ring,
                               struct sk_buff *skb)
 {
        if (ring->netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+               skb_set_hash(skb,
+                            le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+                            PKT_HASH_TYPE_L3);
 }
 
 /**
@@ -6690,7 +6768,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
        hdr.network += ETH_HLEN;
 
        /* handle any vlan tag if present */
-       if (protocol == __constant_htons(ETH_P_8021Q)) {
+       if (protocol == htons(ETH_P_8021Q)) {
                if ((hdr.network - data) > (max_len - VLAN_HLEN))
                        return max_len;
 
@@ -6699,7 +6777,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
        }
 
        /* handle L3 protocols */
-       if (protocol == __constant_htons(ETH_P_IP)) {
+       if (protocol == htons(ETH_P_IP)) {
                if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
                        return max_len;
 
@@ -6713,7 +6791,7 @@ static unsigned int igb_get_headlen(unsigned char *data,
                /* record next protocol if header is present */
                if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
                        nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == __constant_htons(ETH_P_IPV6)) {
+       } else if (protocol == htons(ETH_P_IPV6)) {
                if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
                        return max_len;
 
@@ -6903,7 +6981,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
        unsigned int total_bytes = 0, total_packets = 0;
        u16 cleaned_count = igb_desc_unused(rx_ring);
 
-       do {
+       while (likely(total_packets < budget)) {
                union e1000_adv_rx_desc *rx_desc;
 
                /* return some buffers to hardware, one at a time is too slow */
@@ -6955,7 +7033,7 @@ static bool igb_clean_rx_irq(struct igb_q_vector *q_vector, const int budget)
 
                /* update budget accounting */
                total_packets++;
-       } while (likely(total_packets < budget));
+       }
 
        /* place incomplete frames back on ring for completion */
        rx_ring->skb = skb;
@@ -7114,8 +7192,10 @@ static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
        case SIOCGMIIREG:
        case SIOCSMIIREG:
                return igb_mii_ioctl(netdev, ifr, cmd);
+       case SIOCGHWTSTAMP:
+               return igb_ptp_get_ts_config(netdev, ifr);
        case SIOCSHWTSTAMP:
-               return igb_ptp_hwtstamp_ioctl(netdev, ifr, cmd);
+               return igb_ptp_set_ts_config(netdev, ifr);
        default:
                return -EOPNOTSUPP;
        }
index 5a54e3dc535de95e9525ccf4bc24ae6f8dcdbcaf..2cca8fd5e574feb779be5cbc05f0e176574267da 100644 (file)
@@ -12,9 +12,8 @@
  * 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.
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include <linux/module.h>
 #include <linux/device.h>
@@ -75,6 +74,8 @@
 #define INCVALUE_82576                 (16 << IGB_82576_TSYNC_SHIFT)
 #define IGB_NBITS_82580                        40
 
+static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter);
+
 /* SYSTIM read access for the 82576 */
 static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc)
 {
@@ -372,7 +373,7 @@ static int igb_ptp_enable(struct ptp_clock_info *ptp,
  * This work function polls the TSYNCTXCTL valid bit to determine when a
  * timestamp has been taken for the current stored skb.
  **/
-void igb_ptp_tx_work(struct work_struct *work)
+static void igb_ptp_tx_work(struct work_struct *work)
 {
        struct igb_adapter *adapter = container_of(work, struct igb_adapter,
                                                   ptp_tx_work);
@@ -386,6 +387,7 @@ void igb_ptp_tx_work(struct work_struct *work)
                                   IGB_PTP_TX_TIMEOUT)) {
                dev_kfree_skb_any(adapter->ptp_tx_skb);
                adapter->ptp_tx_skb = NULL;
+               clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
                adapter->tx_hwtstamp_timeouts++;
                dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang");
                return;
@@ -466,7 +468,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter)
  * available, then it must have been for this skb here because we only
  * allow only one such packet into the queue.
  **/
-void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
+static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
        struct skb_shared_hwtstamps shhwtstamps;
@@ -479,6 +481,7 @@ void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
        skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
        dev_kfree_skb_any(adapter->ptp_tx_skb);
        adapter->ptp_tx_skb = NULL;
+       clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
 }
 
 /**
@@ -540,10 +543,26 @@ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
 }
 
 /**
- * igb_ptp_hwtstamp_ioctl - control hardware time stamping
+ * igb_ptp_get_ts_config - get hardware time stamping config
+ * @netdev:
+ * @ifreq:
+ *
+ * Get the hwtstamp_config settings to return to the user. Rather than attempt
+ * to deconstruct the settings from the registers, just return a shadow copy
+ * of the last known settings.
+ **/
+int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr)
+{
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct hwtstamp_config *config = &adapter->tstamp_config;
+
+       return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
+               -EFAULT : 0;
+}
+/**
+ * igb_ptp_set_ts_config - control hardware time stamping
  * @netdev:
  * @ifreq:
- * @cmd:
  *
  * Outgoing time stamping can be enabled and disabled. Play nice and
  * disable it when requested, although it shouldn't case any overhead
@@ -557,12 +576,11 @@ void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector,
  * not supported, with the exception of "all V2 events regardless of
  * level 2 or 4".
  **/
-int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
-                          struct ifreq *ifr, int cmd)
+int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       struct hwtstamp_config config;
+       struct hwtstamp_config *config = &adapter->tstamp_config;
        u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED;
        u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
        u32 tsync_rx_cfg = 0;
@@ -570,14 +588,14 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
        bool is_l2 = false;
        u32 regval;
 
-       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+       if (copy_from_user(config, ifr->ifr_data, sizeof(*config)))
                return -EFAULT;
 
        /* reserved for future extensions */
-       if (config.flags)
+       if (config->flags)
                return -EINVAL;
 
-       switch (config.tx_type) {
+       switch (config->tx_type) {
        case HWTSTAMP_TX_OFF:
                tsync_tx_ctl = 0;
        case HWTSTAMP_TX_ON:
@@ -586,7 +604,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
                return -ERANGE;
        }
 
-       switch (config.rx_filter) {
+       switch (config->rx_filter) {
        case HWTSTAMP_FILTER_NONE:
                tsync_rx_ctl = 0;
                break;
@@ -610,7 +628,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
        case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
        case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
                tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2;
-               config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+               config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
                is_l2 = true;
                is_l4 = true;
                break;
@@ -621,12 +639,12 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
                 */
                if (hw->mac.type != e1000_82576) {
                        tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
-                       config.rx_filter = HWTSTAMP_FILTER_ALL;
+                       config->rx_filter = HWTSTAMP_FILTER_ALL;
                        break;
                }
                /* fall through */
        default:
-               config.rx_filter = HWTSTAMP_FILTER_NONE;
+               config->rx_filter = HWTSTAMP_FILTER_NONE;
                return -ERANGE;
        }
 
@@ -643,7 +661,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
        if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) {
                tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED;
                tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL;
-               config.rx_filter = HWTSTAMP_FILTER_ALL;
+               config->rx_filter = HWTSTAMP_FILTER_ALL;
                is_l2 = true;
                is_l4 = true;
 
@@ -707,7 +725,7 @@ int igb_ptp_hwtstamp_ioctl(struct net_device *netdev,
        regval = rd32(E1000_RXSTMPL);
        regval = rd32(E1000_RXSTMPH);
 
-       return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+       return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
                -EFAULT : 0;
 }
 
@@ -798,7 +816,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
 
        /* Initialize the time sync interrupts for devices that support it. */
        if (hw->mac.type >= e1000_82580) {
-               wr32(E1000_TSIM, E1000_TSIM_TXTS);
+               wr32(E1000_TSIM, TSYNC_INTERRUPTS);
                wr32(E1000_IMS, E1000_IMS_TS);
        }
 
@@ -841,6 +859,7 @@ void igb_ptp_stop(struct igb_adapter *adapter)
        if (adapter->ptp_tx_skb) {
                dev_kfree_skb_any(adapter->ptp_tx_skb);
                adapter->ptp_tx_skb = NULL;
+               clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
        }
 
        if (adapter->ptp_clock) {
@@ -864,6 +883,9 @@ void igb_ptp_reset(struct igb_adapter *adapter)
        if (!(adapter->flags & IGB_FLAG_PTP))
                return;
 
+       /* reset the tstamp_config */
+       memset(&adapter->tstamp_config, 0, sizeof(adapter->tstamp_config));
+
        switch (adapter->hw.mac.type) {
        case e1000_82576:
                /* Dial the nominal frequency. */
@@ -876,7 +898,7 @@ void igb_ptp_reset(struct igb_adapter *adapter)
        case e1000_i211:
                /* Enable the timer functions and interrupts. */
                wr32(E1000_TSAUXC, 0x0);
-               wr32(E1000_TSIM, E1000_TSIM_TXTS);
+               wr32(E1000_TSIM, TSYNC_INTERRUPTS);
                wr32(E1000_IMS, E1000_IMS_TS);
                break;
        default:
index 675435fc2e53c8b30c84571a02184e50088a242f..b7ab03a2f28f702f604e9f5accd9fb4529b85e70 100644 (file)
@@ -1043,11 +1043,11 @@ static void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter)
                for (i = 0; i < 3; i++)
                        adapter->msix_entries[i].entry = i;
 
-               err = pci_enable_msix(adapter->pdev,
-                                     adapter->msix_entries, 3);
+               err = pci_enable_msix_range(adapter->pdev,
+                                           adapter->msix_entries, 3, 3);
        }
 
-       if (err) {
+       if (err < 0) {
                /* MSI-X failed */
                dev_err(&adapter->pdev->dev,
                        "Failed to initialize MSI-X interrupts.\n");
@@ -2014,12 +2014,12 @@ static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
 
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        switch (skb->protocol) {
-                       case __constant_htons(ETH_P_IP):
+                       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 __constant_htons(ETH_P_IPV6):
+                       case htons(ETH_P_IPV6):
                                if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
                                        tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
                                break;
index 57e390cbe6d0d21630f6bf6904a0c8a663601931..f42c201f727fc7fdb46062808cd0435927081256 100644 (file)
@@ -1521,12 +1521,12 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        int tso;
 
        if (test_bit(__IXGB_DOWN, &adapter->flags)) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
        if (skb->len <= 0) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -1543,7 +1543,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        tso = ixgb_tso(adapter, skb);
        if (tso < 0) {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index 0186ea2969fe9cb0d9ed53ad122c95739caec78e..2fff0fc4e6e8a0b76a1ed880da906d08397c7ed2 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -765,6 +766,7 @@ struct ixgbe_adapter {
        struct ptp_clock_info ptp_caps;
        struct work_struct ptp_tx_work;
        struct sk_buff *ptp_tx_skb;
+       struct hwtstamp_config tstamp_config;
        unsigned long ptp_tx_start;
        unsigned long last_overflow_check;
        unsigned long last_rx_ptp_check;
@@ -884,7 +886,6 @@ 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);
-bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
 void ixgbe_set_rx_mode(struct net_device *netdev);
 #ifdef CONFIG_IXGBE_DCB
 void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter);
@@ -958,8 +959,8 @@ static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring,
        rx_ring->last_rx_timestamp = jiffies;
 }
 
-int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, struct ifreq *ifr,
-                            int cmd);
+int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
+int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr);
 void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_reset(struct ixgbe_adapter *adapter);
 void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr);
index a26f3fee4f359be56b4346b9a5d871efedc8ca1d..4c78ea8946c1b48838db6d7e9ce890089ff6ab59 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -57,10 +58,12 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
  **/
 static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
 {
-       struct ixgbe_adapter *adapter = hw->back;
        u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR);
        u16 pcie_devctl2;
 
+       if (ixgbe_removed(hw->hw_addr))
+               return;
+
        /* only take action if timeout value is defaulted to 0 */
        if (gcr & IXGBE_GCR_CMPL_TMOUT_MASK)
                goto out;
@@ -79,11 +82,9 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw)
         * directly in order to set the completion timeout value for
         * 16ms to 55ms
         */
-       pci_read_config_word(adapter->pdev,
-                            IXGBE_PCI_DEVICE_CONTROL2, &pcie_devctl2);
+       pcie_devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2);
        pcie_devctl2 |= IXGBE_PCI_DEVICE_CONTROL2_16ms;
-       pci_write_config_word(adapter->pdev,
-                             IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2);
+       ixgbe_write_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2);
 out:
        /* disable completion timeout resend */
        gcr &= ~IXGBE_GCR_CMPL_TMOUT_RESEND;
@@ -100,6 +101,7 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
        mac->mcft_size = IXGBE_82598_MC_TBL_SIZE;
        mac->vft_size = IXGBE_82598_VFT_TBL_SIZE;
        mac->num_rar_entries = IXGBE_82598_RAR_ENTRIES;
+       mac->rx_pb_size = IXGBE_82598_RX_PB_SIZE;
        mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES;
        mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -201,8 +203,6 @@ static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
                IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval);
        }
 
-       hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE;
-
        /* set the completion timeout for interface */
        if (ret_val == 0)
                ixgbe_set_pcie_completion_timeout(hw);
@@ -1237,14 +1237,14 @@ static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw)
 }
 
 /**
- * ixgbe_set_rxpba_82598 - Configure packet buffers
+ * ixgbe_set_rxpba_82598 - Initialize RX packet buffer
  * @hw: pointer to hardware structure
- * @dcb_config: pointer to ixgbe_dcb_config structure
- *
- * Configure packet buffers.
- */
-static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb, u32 headroom,
-                                 int strategy)
+ * @num_pb: number of packet buffers to allocate
+ * @headroom: reserve n KB of headroom
+ * @strategy: packet buffer allocation strategy
+ **/
+static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb,
+                                 u32 headroom, int strategy)
 {
        u32 rxpktsize = IXGBE_RXPBSIZE_64KB;
        u8  i = 0;
@@ -1315,7 +1315,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
        .release_swfw_sync      = &ixgbe_release_swfw_sync,
        .get_thermal_sensor_data = NULL,
        .init_thermal_sensor_thresh = NULL,
-       .mng_fw_enabled         = NULL,
+       .prot_autoc_read        = &prot_autoc_read_generic,
+       .prot_autoc_write       = &prot_autoc_write_generic,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
index edda6814108c9d120fe994740edfcc04f710943d..f32b3dd1ba8e18911fd58876ed20e494d92ae389 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -63,8 +64,10 @@ static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
                                     u8 dev_addr, u8 *data);
 static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset,
                                      u8 dev_addr, u8 data);
+static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
+static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
 
-static bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
+bool ixgbe_mng_enabled(struct ixgbe_hw *hw)
 {
        u32 fwsm, manc, factps;
 
@@ -91,7 +94,7 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
         * and MNG not enabled
         */
        if ((mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
-           !hw->mng_fw_enabled) {
+           !ixgbe_mng_enabled(hw)) {
                mac->ops.disable_tx_laser =
                                       &ixgbe_disable_tx_laser_multispeed_fiber;
                mac->ops.enable_tx_laser =
@@ -122,7 +125,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
 {
        s32 ret_val = 0;
        u16 list_offset, data_offset, data_value;
-       bool got_lock = false;
 
        if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) {
                ixgbe_init_mac_link_ops_82599(hw);
@@ -160,30 +162,10 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
                usleep_range(hw->eeprom.semaphore_delay * 1000,
                             hw->eeprom.semaphore_delay * 2000);
 
-               /* Need SW/FW semaphore around AUTOC writes if LESM on,
-                * likewise reset_pipeline requires lock as it also writes
-                * AUTOC.
-                */
-               if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
-                       ret_val = hw->mac.ops.acquire_swfw_sync(hw,
-                                                       IXGBE_GSSR_MAC_CSR_SM);
-                       if (ret_val)
-                               goto setup_sfp_out;
-
-                       got_lock = true;
-               }
-
                /* Restart DSP and set SFI mode */
-               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((hw->mac.orig_autoc) |
-                               IXGBE_AUTOC_LMS_10G_SERIAL));
-               hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
-               ret_val = ixgbe_reset_pipeline_82599(hw);
-
-               if (got_lock) {
-                       hw->mac.ops.release_swfw_sync(hw,
-                                                     IXGBE_GSSR_MAC_CSR_SM);
-                       got_lock = false;
-               }
+               ret_val = hw->mac.ops.prot_autoc_write(hw,
+                       hw->mac.orig_autoc | IXGBE_AUTOC_LMS_10G_SERIAL,
+                       false);
 
                if (ret_val) {
                        hw_dbg(hw, " sfp module setup not complete\n");
@@ -207,6 +189,81 @@ setup_sfp_err:
        return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
 }
 
+/**
+ *  prot_autoc_read_82599 - Hides MAC differences needed for AUTOC read
+ *  @hw: pointer to hardware structure
+ *  @locked: Return the if we locked for this read.
+ *  @reg_val: Value we read from AUTOC
+ *
+ *  For this part (82599) we need to wrap read-modify-writes with a possible
+ *  FW/SW lock.  It is assumed this lock will be freed with the next
+ *  prot_autoc_write_82599().  Note, that locked can only be true in cases
+ *  where this function doesn't return an error.
+ **/
+static s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked,
+                                u32 *reg_val)
+{
+       s32 ret_val;
+
+       *locked = false;
+       /* If LESM is on then we need to hold the SW/FW semaphore. */
+       if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+               ret_val = hw->mac.ops.acquire_swfw_sync(hw,
+                                       IXGBE_GSSR_MAC_CSR_SM);
+               if (ret_val)
+                       return IXGBE_ERR_SWFW_SYNC;
+
+               *locked = true;
+       }
+
+       *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       return 0;
+}
+
+/**
+ * prot_autoc_write_82599 - Hides MAC differences needed for AUTOC write
+ * @hw: pointer to hardware structure
+ * @reg_val: value to write to AUTOC
+ * @locked: bool to indicate whether the SW/FW lock was already taken by
+ *          previous proc_autoc_read_82599.
+ *
+ * This part (82599) may need to hold a the SW/FW lock around all writes to
+ * AUTOC. Likewise after a write we need to do a pipeline reset.
+ **/
+static s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked)
+{
+       s32 ret_val = 0;
+
+       /* Blocked by MNG FW so bail */
+       if (ixgbe_check_reset_blocked(hw))
+               goto out;
+
+       /* We only need to get the lock if:
+        *  - We didn't do it already (in the read part of a read-modify-write)
+        *  - LESM is enabled.
+        */
+       if (!locked && ixgbe_verify_lesm_fw_enabled_82599(hw)) {
+               ret_val = hw->mac.ops.acquire_swfw_sync(hw,
+                                       IXGBE_GSSR_MAC_CSR_SM);
+               if (ret_val)
+                       return IXGBE_ERR_SWFW_SYNC;
+
+               locked = true;
+       }
+
+       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+       ret_val = ixgbe_reset_pipeline_82599(hw);
+
+out:
+       /* Free the SW/FW semaphore as we either grabbed it here or
+        * already had it when this function was called.
+        */
+       if (locked)
+               hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+
+       return ret_val;
+}
+
 static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
 {
        struct ixgbe_mac_info *mac = &hw->mac;
@@ -216,6 +273,7 @@ static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
        mac->mcft_size = IXGBE_82599_MC_TBL_SIZE;
        mac->vft_size = IXGBE_82599_VFT_TBL_SIZE;
        mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES;
+       mac->rx_pb_size = IXGBE_82599_RX_PB_SIZE;
        mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES;
        mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -456,12 +514,20 @@ out:
  *
  * Disables link, should be called during D3 power down sequence.
  *
- */
+ **/
 static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw)
 {
-       u32 autoc2_reg;
+       u32 autoc2_reg, fwsm;
+       u16 ee_ctrl_2 = 0;
+
+       hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_2, &ee_ctrl_2);
 
-       if (!hw->mng_fw_enabled && !hw->wol_enabled) {
+       /* Check to see if MNG FW could be enabled */
+       fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM);
+
+       if (((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT) &&
+           !hw->wol_enabled &&
+           ee_ctrl_2 & IXGBE_EEPROM_CCD_BIT) {
                autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
                autoc2_reg |= IXGBE_AUTOC2_LINK_DISABLE_ON_D3_MASK;
                IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg);
@@ -542,6 +608,10 @@ static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
 {
        u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
 
+       /* Blocked by MNG FW so bail */
+       if (ixgbe_check_reset_blocked(hw))
+               return;
+
        /* Disable tx laser; allow 100us to go dark per spec */
        esdp_reg |= IXGBE_ESDP_SDP3;
        IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
@@ -582,6 +652,10 @@ static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
  **/
 static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
 {
+       /* Blocked by MNG FW so bail */
+       if (ixgbe_check_reset_blocked(hw))
+               return;
+
        if (hw->mac.autotry_restart) {
                ixgbe_disable_tx_laser_multispeed_fiber(hw);
                ixgbe_enable_tx_laser_multispeed_fiber(hw);
@@ -589,75 +663,6 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
        }
 }
 
-/**
- *  ixgbe_set_fiber_fixed_speed - Set module link speed for fixed fiber
- *  @hw: pointer to hardware structure
- *  @speed: link speed to set
- *
- *  We set the module speed differently for fixed fiber.  For other
- *  multi-speed devices we don't have an error value so here if we
- *  detect an error we just log it and exit.
- */
-static void ixgbe_set_fiber_fixed_speed(struct ixgbe_hw *hw,
-                                       ixgbe_link_speed speed)
-{
-       s32 status;
-       u8 rs, eeprom_data;
-
-       switch (speed) {
-       case IXGBE_LINK_SPEED_10GB_FULL:
-               /* one bit mask same as setting on */
-               rs = IXGBE_SFF_SOFT_RS_SELECT_10G;
-               break;
-       case IXGBE_LINK_SPEED_1GB_FULL:
-               rs = IXGBE_SFF_SOFT_RS_SELECT_1G;
-               break;
-       default:
-               hw_dbg(hw, "Invalid fixed module speed\n");
-               return;
-       }
-
-       /* Set RS0 */
-       status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
-                                          IXGBE_I2C_EEPROM_DEV_ADDR2,
-                                          &eeprom_data);
-       if (status) {
-               hw_dbg(hw, "Failed to read Rx Rate Select RS0\n");
-               goto out;
-       }
-
-       eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) | rs;
-
-       status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB,
-                                           IXGBE_I2C_EEPROM_DEV_ADDR2,
-                                           eeprom_data);
-       if (status) {
-               hw_dbg(hw, "Failed to write Rx Rate Select RS0\n");
-               goto out;
-       }
-
-       /* Set RS1 */
-       status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
-                                          IXGBE_I2C_EEPROM_DEV_ADDR2,
-                                          &eeprom_data);
-       if (status) {
-               hw_dbg(hw, "Failed to read Rx Rate Select RS1\n");
-               goto out;
-       }
-
-       eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs;
-
-       status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB,
-                                           IXGBE_I2C_EEPROM_DEV_ADDR2,
-                                           eeprom_data);
-       if (status) {
-               hw_dbg(hw, "Failed to write Rx Rate Select RS1\n");
-               goto out;
-       }
-out:
-       return;
-}
-
 /**
  *  ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed
  *  @hw: pointer to hardware structure
@@ -768,10 +773,6 @@ static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
 
                /* Set the module link speed */
                switch (hw->phy.media_type) {
-               case ixgbe_media_type_fiber_fixed:
-                       ixgbe_set_fiber_fixed_speed(hw,
-                                               IXGBE_LINK_SPEED_1GB_FULL);
-                       break;
                case ixgbe_media_type_fiber:
                        esdp_reg &= ~IXGBE_ESDP_SDP5;
                        esdp_reg |= IXGBE_ESDP_SDP5_DIR;
@@ -941,8 +942,7 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
 
 out:
        if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
-               hw_dbg(hw, "Smartspeed has downgraded the link speed from "
-                      "the maximum advertised\n");
+               hw_dbg(hw, "Smartspeed has downgraded the link speed from the maximum advertised\n");
        return status;
 }
 
@@ -958,16 +958,19 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
                                      ixgbe_link_speed speed,
                                      bool autoneg_wait_to_complete)
 {
+       bool autoneg = false;
        s32 status = 0;
-       u32 autoc, pma_pmd_1g, link_mode, start_autoc;
+       u32 pma_pmd_1g, link_mode, links_reg, i;
        u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
-       u32 orig_autoc = 0;
        u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK;
-       u32 links_reg;
-       u32 i;
        ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
-       bool got_lock = false;
-       bool autoneg = false;
+
+       /* holds the value of AUTOC register at this current point in time */
+       u32 current_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       /* holds the cached value of AUTOC register */
+       u32 orig_autoc = 0;
+       /* temporary variable used for comparison purposes */
+       u32 autoc = current_autoc;
 
        /* Check to see if speed passed in is supported. */
        status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities,
@@ -984,12 +987,10 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
 
        /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/
        if (hw->mac.orig_link_settings_stored)
-               autoc = hw->mac.orig_autoc;
+               orig_autoc = hw->mac.orig_autoc;
        else
-               autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+               orig_autoc = autoc;
 
-       orig_autoc = autoc;
-       start_autoc = hw->mac.cached_autoc;
        link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
        pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
 
@@ -1029,28 +1030,11 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
                }
        }
 
-       if (autoc != start_autoc) {
-               /* Need SW/FW semaphore around AUTOC writes if LESM is on,
-                * likewise reset_pipeline requires us to hold this lock as
-                * it also writes to AUTOC.
-                */
-               if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
-                       status = hw->mac.ops.acquire_swfw_sync(hw,
-                                                       IXGBE_GSSR_MAC_CSR_SM);
-                       if (status != 0)
-                               goto out;
-
-                       got_lock = true;
-               }
-
+       if (autoc != current_autoc) {
                /* Restart link */
-               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
-               hw->mac.cached_autoc = autoc;
-               ixgbe_reset_pipeline_82599(hw);
-
-               if (got_lock)
-                       hw->mac.ops.release_swfw_sync(hw,
-                                                     IXGBE_GSSR_MAC_CSR_SM);
+               status = hw->mac.ops.prot_autoc_write(hw, autoc, false);
+               if (status)
+                       goto out;
 
                /* Only poll for autoneg to complete if specified to do so */
                if (autoneg_wait_to_complete) {
@@ -1068,8 +1052,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
                                if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
                                        status =
                                                IXGBE_ERR_AUTONEG_NOT_COMPLETE;
-                                       hw_dbg(hw, "Autoneg did not "
-                                              "complete.\n");
+                                       hw_dbg(hw, "Autoneg did not complete.\n");
                                }
                        }
                }
@@ -1117,7 +1100,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
 {
        ixgbe_link_speed link_speed;
        s32 status;
-       u32 ctrl, i, autoc2;
+       u32 ctrl, i, autoc, autoc2;
        u32 curr_lms;
        bool link_up = false;
 
@@ -1151,11 +1134,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
                hw->phy.ops.reset(hw);
 
        /* remember AUTOC from before we reset */
-       if (hw->mac.cached_autoc)
-               curr_lms = hw->mac.cached_autoc & IXGBE_AUTOC_LMS_MASK;
-       else
-               curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) &
-                          IXGBE_AUTOC_LMS_MASK;
+       curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) & IXGBE_AUTOC_LMS_MASK;
 
 mac_reset_top:
        /*
@@ -1205,7 +1184,7 @@ mac_reset_top:
         * stored off yet.  Otherwise restore the stored original
         * values since the reset operation sets back to defaults.
         */
-       hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
        autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
 
        /* Enable link if disabled in NVM */
@@ -1216,7 +1195,7 @@ mac_reset_top:
        }
 
        if (hw->mac.orig_link_settings_stored == false) {
-               hw->mac.orig_autoc = hw->mac.cached_autoc;
+               hw->mac.orig_autoc = autoc;
                hw->mac.orig_autoc2 = autoc2;
                hw->mac.orig_link_settings_stored = true;
        } else {
@@ -1227,34 +1206,18 @@ mac_reset_top:
                 * Likewise if we support WoL we don't want change the
                 * LMS state either.
                 */
-               if ((hw->phy.multispeed_fiber && hw->mng_fw_enabled) ||
+               if ((hw->phy.multispeed_fiber && ixgbe_mng_enabled(hw)) ||
                    hw->wol_enabled)
                        hw->mac.orig_autoc =
                                (hw->mac.orig_autoc & ~IXGBE_AUTOC_LMS_MASK) |
                                curr_lms;
 
-               if (hw->mac.cached_autoc != hw->mac.orig_autoc) {
-                       /* Need SW/FW semaphore around AUTOC writes if LESM is
-                        * on, likewise reset_pipeline requires us to hold
-                        * this lock as it also writes to AUTOC.
-                        */
-                       bool got_lock = false;
-                       if (ixgbe_verify_lesm_fw_enabled_82599(hw)) {
-                               status = hw->mac.ops.acquire_swfw_sync(hw,
-                                                       IXGBE_GSSR_MAC_CSR_SM);
-                               if (status)
-                                       goto reset_hw_out;
-
-                               got_lock = true;
-                       }
-
-                       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc);
-                       hw->mac.cached_autoc = hw->mac.orig_autoc;
-                       ixgbe_reset_pipeline_82599(hw);
-
-                       if (got_lock)
-                               hw->mac.ops.release_swfw_sync(hw,
-                                                       IXGBE_GSSR_MAC_CSR_SM);
+               if (autoc != hw->mac.orig_autoc) {
+                       status = hw->mac.ops.prot_autoc_write(hw,
+                                                       hw->mac.orig_autoc,
+                                                       false);
+                       if (status)
+                               goto reset_hw_out;
                }
 
                if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) !=
@@ -1634,35 +1597,20 @@ void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
 {
 
        u32 hi_hash_dword, lo_hash_dword, flow_vm_vlan;
-       u32 bucket_hash = 0;
+       u32 bucket_hash = 0, hi_dword = 0;
+       int i;
 
        /* Apply masks to input data */
-       input->dword_stream[0]  &= input_mask->dword_stream[0];
-       input->dword_stream[1]  &= input_mask->dword_stream[1];
-       input->dword_stream[2]  &= input_mask->dword_stream[2];
-       input->dword_stream[3]  &= input_mask->dword_stream[3];
-       input->dword_stream[4]  &= input_mask->dword_stream[4];
-       input->dword_stream[5]  &= input_mask->dword_stream[5];
-       input->dword_stream[6]  &= input_mask->dword_stream[6];
-       input->dword_stream[7]  &= input_mask->dword_stream[7];
-       input->dword_stream[8]  &= input_mask->dword_stream[8];
-       input->dword_stream[9]  &= input_mask->dword_stream[9];
-       input->dword_stream[10] &= input_mask->dword_stream[10];
+       for (i = 0; i <= 10; i++)
+               input->dword_stream[i] &= input_mask->dword_stream[i];
 
        /* record the flow_vm_vlan bits as they are a key part to the hash */
        flow_vm_vlan = ntohl(input->dword_stream[0]);
 
        /* generate common hash dword */
-       hi_hash_dword = ntohl(input->dword_stream[1] ^
-                                   input->dword_stream[2] ^
-                                   input->dword_stream[3] ^
-                                   input->dword_stream[4] ^
-                                   input->dword_stream[5] ^
-                                   input->dword_stream[6] ^
-                                   input->dword_stream[7] ^
-                                   input->dword_stream[8] ^
-                                   input->dword_stream[9] ^
-                                   input->dword_stream[10]);
+       for (i = 1; i <= 10; i++)
+               hi_dword ^= input->dword_stream[i];
+       hi_hash_dword = ntohl(hi_dword);
 
        /* low dword is word swapped version of common */
        lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
@@ -1681,21 +1629,8 @@ void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input,
        lo_hash_dword ^= flow_vm_vlan ^ (flow_vm_vlan << 16);
 
        /* Process remaining 30 bit of the key */
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(1);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(2);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(3);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(4);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(5);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(6);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(7);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(8);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(9);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(10);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(11);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(12);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(13);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(14);
-       IXGBE_COMPUTE_BKT_HASH_ITERATION(15);
+       for (i = 1; i <= 15; i++)
+               IXGBE_COMPUTE_BKT_HASH_ITERATION(i);
 
        /*
         * Limit hash to 13 bits since max bucket count is 8K.
@@ -2001,7 +1936,6 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
 
        /* We need to run link autotry after the driver loads */
        hw->mac.autotry_restart = true;
-       hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE;
 
        if (ret_val == 0)
                ret_val = ixgbe_verify_fw_version_82599(hw);
@@ -2260,7 +2194,7 @@ fw_version_err:
  *  Returns true if the LESM FW module is present and enabled. Otherwise
  *  returns false. Smart Speed must be disabled if LESM FW module is enabled.
  **/
-bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw)
+static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw)
 {
        bool lesm_enabled = false;
        u16 fw_offset, fw_lesm_param_offset, fw_lesm_state;
@@ -2366,7 +2300,7 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw,
  * full pipeline reset.  Note - We must hold the SW/FW semaphore before writing
  * to AUTOC, so this function assumes the semaphore is held.
  **/
-s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
+static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
 {
        s32 ret_val;
        u32 anlp1_reg = 0;
@@ -2380,11 +2314,12 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw)
                IXGBE_WRITE_FLUSH(hw);
        }
 
-       autoc_reg = hw->mac.cached_autoc;
+       autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
        autoc_reg |= IXGBE_AUTOC_AN_RESTART;
 
        /* Write AUTOC register with toggled LMS[2] bit and Restart_AN */
-       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg ^ IXGBE_AUTOC_LMS_1G_AN);
+       IXGBE_WRITE_REG(hw, IXGBE_AUTOC,
+                       autoc_reg ^ (0x4 << IXGBE_AUTOC_LMS_SHIFT));
 
        /* Wait for AN to leave state 0 */
        for (i = 0; i < 10; i++) {
@@ -2565,7 +2500,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
        .release_swfw_sync      = &ixgbe_release_swfw_sync,
        .get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic,
        .init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic,
-       .mng_fw_enabled         = &ixgbe_mng_enabled,
+       .prot_autoc_read        = &prot_autoc_read_82599,
+       .prot_autoc_write       = &prot_autoc_write_82599,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
index b5c434b617b129411abe676efef64f259ffc6518..24fba39e194e682640391e42e5e618907ff230d9 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -72,7 +73,6 @@ bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw)
        bool link_up;
 
        switch (hw->phy.media_type) {
-       case ixgbe_media_type_fiber_fixed:
        case ixgbe_media_type_fiber:
                hw->mac.ops.check_link(hw, &speed, &link_up, false);
                /* if link is down, assume supported */
@@ -114,7 +114,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
        s32 ret_val = 0;
        u32 reg = 0, reg_bp = 0;
        u16 reg_cu = 0;
-       bool got_lock = false;
+       bool locked = false;
 
        /*
         * Validate the requested mode.  Strict IEEE mode does not allow
@@ -139,11 +139,16 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
         * we link at 10G, the 1G advertisement is harmless and vice versa.
         */
        switch (hw->phy.media_type) {
-       case ixgbe_media_type_fiber_fixed:
-       case ixgbe_media_type_fiber:
        case ixgbe_media_type_backplane:
+               /* some MAC's need RMW protection on AUTOC */
+               ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &reg_bp);
+               if (ret_val)
+                       goto out;
+
+               /* only backplane uses autoc so fall though */
+       case ixgbe_media_type_fiber:
                reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
-               reg_bp = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
                break;
        case ixgbe_media_type_copper:
                hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE,
@@ -240,27 +245,12 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw)
                 * LESM is on, likewise reset_pipeline requries the lock as
                 * it also writes AUTOC.
                 */
-               if ((hw->mac.type == ixgbe_mac_82599EB) &&
-                   ixgbe_verify_lesm_fw_enabled_82599(hw)) {
-                       ret_val = hw->mac.ops.acquire_swfw_sync(hw,
-                                                       IXGBE_GSSR_MAC_CSR_SM);
-                       if (ret_val)
-                               goto out;
-
-                       got_lock = true;
-               }
-
-               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp);
-
-               if (hw->mac.type == ixgbe_mac_82599EB)
-                       ixgbe_reset_pipeline_82599(hw);
-
-               if (got_lock)
-                       hw->mac.ops.release_swfw_sync(hw,
-                                                     IXGBE_GSSR_MAC_CSR_SM);
+               ret_val = hw->mac.ops.prot_autoc_write(hw, reg_bp, locked);
+               if (ret_val)
+                       goto out;
 
        } else if ((hw->phy.media_type == ixgbe_media_type_copper) &&
-                   ixgbe_device_supports_autoneg_fc(hw)) {
+                  ixgbe_device_supports_autoneg_fc(hw)) {
                hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE,
                                      MDIO_MMD_AN, reg_cu);
        }
@@ -656,20 +646,17 @@ enum ixgbe_bus_speed ixgbe_convert_bus_speed(u16 link_status)
  **/
 s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw)
 {
-       struct ixgbe_adapter *adapter = hw->back;
-       struct ixgbe_mac_info *mac = &hw->mac;
        u16 link_status;
 
        hw->bus.type = ixgbe_bus_type_pci_express;
 
        /* Get the negotiated link width and speed from PCI config space */
-       pci_read_config_word(adapter->pdev, IXGBE_PCI_LINK_STATUS,
-                            &link_status);
+       link_status = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_LINK_STATUS);
 
        hw->bus.width = ixgbe_convert_bus_width(link_status);
        hw->bus.speed = ixgbe_convert_bus_speed(link_status);
 
-       mac->ops.set_lan_id(hw);
+       hw->mac.ops.set_lan_id(hw);
 
        return 0;
 }
@@ -2406,7 +2393,6 @@ void ixgbe_fc_autoneg(struct ixgbe_hw *hw)
 
        switch (hw->phy.media_type) {
        /* Autoneg flow control on fiber adapters */
-       case ixgbe_media_type_fiber_fixed:
        case ixgbe_media_type_fiber:
                if (speed == IXGBE_LINK_SPEED_1GB_FULL)
                        ret_val = ixgbe_fc_autoneg_fiber(hw);
@@ -2436,6 +2422,53 @@ out:
        }
 }
 
+/**
+ * ixgbe_pcie_timeout_poll - Return number of times to poll for completion
+ * @hw: pointer to hardware structure
+ *
+ * System-wide timeout range is encoded in PCIe Device Control2 register.
+ *
+ *  Add 10% to specified maximum and return the number of times to poll for
+ *  completion timeout, in units of 100 microsec.  Never return less than
+ *  800 = 80 millisec.
+ **/
+static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw)
+{
+       s16 devctl2;
+       u32 pollcnt;
+
+       devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2);
+       devctl2 &= IXGBE_PCIDEVCTRL2_TIMEO_MASK;
+
+       switch (devctl2) {
+       case IXGBE_PCIDEVCTRL2_65_130ms:
+                pollcnt = 1300;         /* 130 millisec */
+               break;
+       case IXGBE_PCIDEVCTRL2_260_520ms:
+               pollcnt = 5200;         /* 520 millisec */
+               break;
+       case IXGBE_PCIDEVCTRL2_1_2s:
+               pollcnt = 20000;        /* 2 sec */
+               break;
+       case IXGBE_PCIDEVCTRL2_4_8s:
+               pollcnt = 80000;        /* 8 sec */
+               break;
+       case IXGBE_PCIDEVCTRL2_17_34s:
+               pollcnt = 34000;        /* 34 sec */
+               break;
+       case IXGBE_PCIDEVCTRL2_50_100us:        /* 100 microsecs */
+       case IXGBE_PCIDEVCTRL2_1_2ms:           /* 2 millisecs */
+       case IXGBE_PCIDEVCTRL2_16_32ms:         /* 32 millisec */
+       case IXGBE_PCIDEVCTRL2_16_32ms_def:     /* 32 millisec default */
+       default:
+               pollcnt = 800;          /* 80 millisec minimum */
+               break;
+       }
+
+       /* add 10% to spec maximum */
+       return (pollcnt * 11) / 10;
+}
+
 /**
  *  ixgbe_disable_pcie_master - Disable PCI-express master access
  *  @hw: pointer to hardware structure
@@ -2447,16 +2480,16 @@ out:
  **/
 static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
 {
-       struct ixgbe_adapter *adapter = hw->back;
        s32 status = 0;
-       u32 i;
+       u32 i, poll;
        u16 value;
 
        /* Always set this bit to ensure any future transactions are blocked */
        IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS);
 
        /* Exit if master requests are blocked */
-       if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO))
+       if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) ||
+           ixgbe_removed(hw->hw_addr))
                goto out;
 
        /* Poll for master request bit to clear */
@@ -2481,10 +2514,12 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
         * Before proceeding, make sure that the PCIe block does not have
         * transactions pending.
         */
-       for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+       poll = ixgbe_pcie_timeout_poll(hw);
+       for (i = 0; i < poll; i++) {
                udelay(100);
-               pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS,
-                                                        &value);
+               value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS);
+               if (ixgbe_removed(hw->hw_addr))
+                       goto out;
                if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING))
                        goto out;
        }
@@ -2563,6 +2598,35 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
        ixgbe_release_eeprom_semaphore(hw);
 }
 
+/**
+ * prot_autoc_read_generic - Hides MAC differences needed for AUTOC read
+ * @hw: pointer to hardware structure
+ * @reg_val: Value we read from AUTOC
+ * @locked: bool to indicate whether the SW/FW lock should be taken.  Never
+ *         true in this the generic case.
+ *
+ * The default case requires no protection so just to the register read.
+ **/
+s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val)
+{
+       *locked = false;
+       *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       return 0;
+}
+
+/**
+ * prot_autoc_write_generic - Hides MAC differences needed for AUTOC write
+ * @hw: pointer to hardware structure
+ * @reg_val: value to write to AUTOC
+ * @locked: bool to indicate whether the SW/FW lock was already taken by
+ *         previous read.
+ **/
+s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked)
+{
+       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_val);
+       return 0;
+}
+
 /**
  *  ixgbe_disable_rx_buff_generic - Stops the receive data path
  *  @hw: pointer to hardware structure
@@ -2641,6 +2705,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
        u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
        u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
        s32 ret_val = 0;
+       bool locked = false;
 
        /*
         * Link must be up to auto-blink the LEDs;
@@ -2649,28 +2714,19 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
        hw->mac.ops.check_link(hw, &speed, &link_up, false);
 
        if (!link_up) {
-               /* Need the SW/FW semaphore around AUTOC writes if 82599 and
-                * LESM is on.
-                */
-               bool got_lock = false;
-
-               if ((hw->mac.type == ixgbe_mac_82599EB) &&
-                   ixgbe_verify_lesm_fw_enabled_82599(hw)) {
-                       ret_val = hw->mac.ops.acquire_swfw_sync(hw,
-                                                       IXGBE_GSSR_MAC_CSR_SM);
-                       if (ret_val)
-                               goto out;
+               ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg);
+               if (ret_val)
+                       goto out;
 
-                       got_lock = true;
-               }
                autoc_reg |= IXGBE_AUTOC_AN_RESTART;
                autoc_reg |= IXGBE_AUTOC_FLU;
-               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+               ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked);
+               if (ret_val)
+                       goto out;
+
                IXGBE_WRITE_FLUSH(hw);
 
-               if (got_lock)
-                       hw->mac.ops.release_swfw_sync(hw,
-                                                     IXGBE_GSSR_MAC_CSR_SM);
                usleep_range(10000, 20000);
        }
 
@@ -2690,33 +2746,21 @@ out:
  **/
 s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index)
 {
-       u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       u32 autoc_reg = 0;
        u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
        s32 ret_val = 0;
-       bool got_lock = false;
+       bool locked = false;
 
-       /* Need the SW/FW semaphore around AUTOC writes if 82599 and
-        * LESM is on.
-        */
-       if ((hw->mac.type == ixgbe_mac_82599EB) &&
-           ixgbe_verify_lesm_fw_enabled_82599(hw)) {
-               ret_val = hw->mac.ops.acquire_swfw_sync(hw,
-                                               IXGBE_GSSR_MAC_CSR_SM);
-               if (ret_val)
-                       goto out;
-
-               got_lock = true;
-       }
+       ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg);
+       if (ret_val)
+               goto out;
 
        autoc_reg &= ~IXGBE_AUTOC_FLU;
        autoc_reg |= IXGBE_AUTOC_AN_RESTART;
-       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
-
-       if (hw->mac.type == ixgbe_mac_82599EB)
-               ixgbe_reset_pipeline_82599(hw);
 
-       if (got_lock)
-               hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+       ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked);
+       if (ret_val)
+               goto out;
 
        led_reg &= ~IXGBE_LED_MODE_MASK(index);
        led_reg &= ~IXGBE_LED_BLINK(index);
@@ -2817,7 +2861,6 @@ san_mac_addr_clr:
  **/
 u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
 {
-       struct ixgbe_adapter *adapter = hw->back;
        u16 msix_count = 1;
        u16 max_msix_count;
        u16 pcie_offset;
@@ -2836,7 +2879,9 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw)
                return msix_count;
        }
 
-       pci_read_config_word(adapter->pdev, pcie_offset, &msix_count);
+       msix_count = ixgbe_read_pci_cfg_word(hw, pcie_offset);
+       if (ixgbe_removed(hw->hw_addr))
+               msix_count = 0;
        msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK;
 
        /* MSI-X count is zero-based in HW */
@@ -2868,6 +2913,9 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
        mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
        mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
 
+       if (ixgbe_removed(hw->hw_addr))
+               goto done;
+
        if (!mpsar_lo && !mpsar_hi)
                goto done;
 
index f2e3919750ec8ca0d7d1b6ac27d63550ab4724a3..f12c40fb5537a18604ff030f4adc4287946dbff4 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -98,6 +99,10 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw,
                                  bool *link_up, bool link_up_wait_to_complete);
 s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix,
                                  u16 *wwpn_prefix);
+
+s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *, u32 *reg_val);
+s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked);
+
 s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index);
 s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
 void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf);
@@ -106,10 +111,10 @@ s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps);
 s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min,
                                 u8 build, u8 ver);
 void ixgbe_clear_tx_pending(struct ixgbe_hw *hw);
+bool ixgbe_mng_enabled(struct ixgbe_hw *hw);
 
 void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb,
                             u32 headroom, int strategy);
-s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
 
 #define IXGBE_I2C_THERMAL_SENSOR_ADDR  0xF8
 #define IXGBE_EMC_INTERNAL_DATA                0x00
@@ -125,6 +130,11 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
 s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
 
 #define IXGBE_FAILED_READ_REG 0xffffffffU
+#define IXGBE_FAILED_READ_CFG_DWORD 0xffffffffU
+#define IXGBE_FAILED_READ_CFG_WORD 0xffffU
+
+u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg);
+void ixgbe_write_pci_cfg_word(struct ixgbe_hw *hw, u32 reg, u16 value);
 
 static inline bool ixgbe_removed(void __iomem *addr)
 {
index 05e23b80b5e37b70f1f0e18a0b3be826915623c3..bdb99b3b0f30f4ee2253e81bc72e84fb6a0d1e30 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index d71d9ce3e394b4199f297ebbcb493fa268092dd2..d5a1e3db0774a5580b8191126e682c33191f7fa6 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index c5933f6dceee928be6c225cb6eba42c48284b011..472b0f450bf90d4dc23fe5995d28d0d80c2d940e 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 043307024c4abf542b6014eb6ccbfc739e2d54c5..6c55c14d082aa6285f43941e5d96ae86acdbb21b 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -1127,10 +1128,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
                }
 
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        data[i]   = ring->stats.packets;
                        data[i+1] = ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                i += 2;
 #ifdef BP_EXTENDED_STATS
                data[i] = ring->stats.yields;
@@ -1155,10 +1156,10 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
                }
 
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        data[i]   = ring->stats.packets;
                        data[i+1] = ring->stats.bytes;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                i += 2;
 #ifdef BP_EXTENDED_STATS
                data[i] = ring->stats.yields;
@@ -1247,6 +1248,11 @@ static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data)
        struct ixgbe_hw *hw = &adapter->hw;
        bool link_up;
        u32 link_speed = 0;
+
+       if (ixgbe_removed(hw->hw_addr)) {
+               *data = 1;
+               return 1;
+       }
        *data = 0;
 
        hw->mac.ops.check_link(hw, &link_speed, &link_up, true);
@@ -1969,6 +1975,7 @@ static void ixgbe_diag_test(struct net_device *netdev,
                data[1] = 1;
                data[2] = 1;
                data[3] = 1;
+               data[4] = 1;
                eth_test->flags |= ETH_TEST_FL_FAILED;
                return;
        }
@@ -1988,6 +1995,7 @@ static void ixgbe_diag_test(struct net_device *netdev,
                                        data[1] = 1;
                                        data[2] = 1;
                                        data[3] = 1;
+                                       data[4] = 1;
                                        eth_test->flags |= ETH_TEST_FL_FAILED;
                                        clear_bit(__IXGBE_TESTING,
                                                  &adapter->state);
index f58db453a97edd8d6d6f7dfbccb2c6f8edd1f3d3..25a3dfef33e8946bfb4c8d511560a1df660f0d4d 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -407,13 +408,13 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
 
        switch (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_FCSTAT)) {
        /* return 0 to bypass going to ULD for DDPed data */
-       case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_DDP):
+       case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_DDP):
                /* update length of DDPed data */
                ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
                rc = 0;
                break;
        /* unmap the sg list when FCPRSP is received */
-       case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_FCPRSP):
+       case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_FCPRSP):
                dma_unmap_sg(&adapter->pdev->dev, ddp->sgl,
                             ddp->sgc, DMA_FROM_DEVICE);
                ddp->err = ddp_err;
@@ -421,14 +422,14 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
                ddp->sgc = 0;
                /* fall through */
        /* if DDP length is present pass it through to ULD */
-       case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NODDP):
+       case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NODDP):
                /* update length of DDPed data */
                ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
                if (ddp->len)
                        rc = ddp->len;
                break;
        /* no match will return as an error */
-       case __constant_cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NOMTCH):
+       case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NOMTCH):
        default:
                break;
        }
@@ -585,7 +586,7 @@ static int ixgbe_fcoe_dma_pool_alloc(struct ixgbe_fcoe *fcoe,
        struct dma_pool *pool;
        char pool_name[32];
 
-       snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%d", cpu);
+       snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%u", cpu);
 
        pool = dma_pool_create(pool_name, dev, IXGBE_FCPTR_MAX,
                               IXGBE_FCPTR_ALIGN, PAGE_SIZE);
index 3a02759b5e95bccb7d7101a70067531ac5f43a93..b16cc786750dec8bb7bf29749db331a31f028ec9 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 32e3eaaa160ac4c4864cae2e4e9025f56f3604ef..2067d392cc3d33850254e9a2d719a2db6491b6f5 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -698,7 +699,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
                                       int vectors)
 {
-       int err, vector_threshold;
+       int vector_threshold;
 
        /* We'll want at least 2 (vector_threshold):
         * 1) TxQ[0] + RxQ[0] handler
@@ -712,18 +713,10 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
         * Right now, we simply care about how many we'll get; we'll
         * set them up later while requesting irq's.
         */
-       while (vectors >= vector_threshold) {
-               err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-                                     vectors);
-               if (!err) /* Success in acquiring all requested vectors. */
-                       break;
-               else if (err < 0)
-                       vectors = 0; /* Nasty failure, quit now */
-               else /* err == number of vectors we should try again with */
-                       vectors = err;
-       }
+       vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                       vector_threshold, vectors);
 
-       if (vectors < vector_threshold) {
+       if (vectors < 0) {
                /* Can't allocate enough MSI-X interrupts?  Oh well.
                 * This just means we'll go with either a single MSI
                 * vector or fall back to legacy interrupts.
index 6d4ada72dfd0a79f1111ff5c48f91ba3e2c862f1..9e5a366124321afee3663fb06b1165b6e41f2649 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -67,7 +68,7 @@ static char ixgbe_default_device_descr[] =
 #define DRV_VERSION "3.19.1-k"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static const char ixgbe_copyright[] =
-                               "Copyright (c) 1999-2013 Intel Corporation.";
+                               "Copyright (c) 1999-2014 Intel Corporation.";
 
 static const struct ixgbe_info *ixgbe_info_tbl[] = {
        [board_82598] = &ixgbe_82598_info,
@@ -151,6 +152,8 @@ MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 
+static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev);
+
 static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
                                          u32 reg, u16 *value)
 {
@@ -169,6 +172,9 @@ static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter,
                return -1;
 
        pcie_capability_read_word(parent_dev, reg, value);
+       if (*value == IXGBE_FAILED_READ_CFG_WORD &&
+           ixgbe_check_cfg_remove(&adapter->hw, parent_dev))
+               return -1;
        return 0;
 }
 
@@ -313,6 +319,57 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
                ixgbe_remove_adapter(hw);
 }
 
+static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev)
+{
+       u16 value;
+
+       pci_read_config_word(pdev, PCI_VENDOR_ID, &value);
+       if (value == IXGBE_FAILED_READ_CFG_WORD) {
+               ixgbe_remove_adapter(hw);
+               return true;
+       }
+       return false;
+}
+
+u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       u16 value;
+
+       if (ixgbe_removed(hw->hw_addr))
+               return IXGBE_FAILED_READ_CFG_WORD;
+       pci_read_config_word(adapter->pdev, reg, &value);
+       if (value == IXGBE_FAILED_READ_CFG_WORD &&
+           ixgbe_check_cfg_remove(hw, adapter->pdev))
+               return IXGBE_FAILED_READ_CFG_WORD;
+       return value;
+}
+
+#ifdef CONFIG_PCI_IOV
+static u32 ixgbe_read_pci_cfg_dword(struct ixgbe_hw *hw, u32 reg)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       u32 value;
+
+       if (ixgbe_removed(hw->hw_addr))
+               return IXGBE_FAILED_READ_CFG_DWORD;
+       pci_read_config_dword(adapter->pdev, reg, &value);
+       if (value == IXGBE_FAILED_READ_CFG_DWORD &&
+           ixgbe_check_cfg_remove(hw, adapter->pdev))
+               return IXGBE_FAILED_READ_CFG_DWORD;
+       return value;
+}
+#endif /* CONFIG_PCI_IOV */
+
+void ixgbe_write_pci_cfg_word(struct ixgbe_hw *hw, u32 reg, u16 value)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+
+       if (ixgbe_removed(hw->hw_addr))
+               return;
+       pci_write_config_word(adapter->pdev, reg, value);
+}
+
 static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
 {
        BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
@@ -1264,7 +1321,9 @@ static inline void ixgbe_rx_hash(struct ixgbe_ring *ring,
                                 struct sk_buff *skb)
 {
        if (ring->netdev->features & NETIF_F_RXHASH)
-               skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+               skb_set_hash(skb,
+                            le32_to_cpu(rx_desc->wb.lower.hi_dword.rss),
+                            PKT_HASH_TYPE_L3);
 }
 
 #ifdef IXGBE_FCOE
@@ -1480,7 +1539,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
        hdr.network += ETH_HLEN;
 
        /* handle any vlan tag if present */
-       if (protocol == __constant_htons(ETH_P_8021Q)) {
+       if (protocol == htons(ETH_P_8021Q)) {
                if ((hdr.network - data) > (max_len - VLAN_HLEN))
                        return max_len;
 
@@ -1489,7 +1548,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
        }
 
        /* handle L3 protocols */
-       if (protocol == __constant_htons(ETH_P_IP)) {
+       if (protocol == htons(ETH_P_IP)) {
                if ((hdr.network - data) > (max_len - sizeof(struct iphdr)))
                        return max_len;
 
@@ -1503,7 +1562,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
                /* record next protocol if header is present */
                if (!(hdr.ipv4->frag_off & htons(IP_OFFSET)))
                        nexthdr = hdr.ipv4->protocol;
-       } else if (protocol == __constant_htons(ETH_P_IPV6)) {
+       } else if (protocol == htons(ETH_P_IPV6)) {
                if ((hdr.network - data) > (max_len - sizeof(struct ipv6hdr)))
                        return max_len;
 
@@ -1511,7 +1570,7 @@ static unsigned int ixgbe_get_headlen(unsigned char *data,
                nexthdr = hdr.ipv6->nexthdr;
                hlen = sizeof(struct ipv6hdr);
 #ifdef IXGBE_FCOE
-       } else if (protocol == __constant_htons(ETH_P_FCOE)) {
+       } else if (protocol == htons(ETH_P_FCOE)) {
                if ((hdr.network - data) > (max_len - FCOE_HEADER_LEN))
                        return max_len;
                hlen = FCOE_HEADER_LEN;
@@ -2026,7 +2085,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 #endif /* IXGBE_FCOE */
        u16 cleaned_count = ixgbe_desc_unused(rx_ring);
 
-       do {
+       while (likely(total_rx_packets < budget)) {
                union ixgbe_adv_rx_desc *rx_desc;
                struct sk_buff *skb;
 
@@ -2101,7 +2160,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
 
                /* update budget accounting */
                total_rx_packets++;
-       } while (likely(total_rx_packets < budget));
+       }
 
        u64_stats_update_begin(&rx_ring->syncp);
        rx_ring->stats.packets += total_rx_packets;
@@ -2630,9 +2689,12 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data)
        switch (hw->mac.type) {
        case ixgbe_mac_82599EB:
        case ixgbe_mac_X540:
-               if (eicr & IXGBE_EICR_ECC)
-                       e_info(link, "Received unrecoverable ECC Err, please "
-                              "reboot\n");
+               if (eicr & IXGBE_EICR_ECC) {
+                       e_info(link, "Received ECC Err, initiating reset\n");
+                       adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+                       ixgbe_service_event_schedule(adapter);
+                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
+               }
                /* Handle Flow Director Full threshold interrupt */
                if (eicr & IXGBE_EICR_FLOW_DIR) {
                        int reinit_count = 0;
@@ -2846,9 +2908,12 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
                ixgbe_check_sfp_event(adapter, eicr);
                /* Fall through */
        case ixgbe_mac_X540:
-               if (eicr & IXGBE_EICR_ECC)
-                       e_info(link, "Received unrecoverable ECC err, please "
-                                    "reboot\n");
+               if (eicr & IXGBE_EICR_ECC) {
+                       e_info(link, "Received ECC Err, initiating reset\n");
+                       adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+                       ixgbe_service_event_schedule(adapter);
+                       IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC);
+               }
                ixgbe_check_overtemp_event(adapter, eicr);
                break;
        default:
@@ -4590,8 +4655,6 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
 static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
-       struct net_device *upper;
-       struct list_head *iter;
        int err;
        u32 ctrl_ext;
 
@@ -4633,19 +4696,6 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter)
                        e_crit(drv, "Fan has stopped, replace the adapter\n");
        }
 
-       /* enable transmits */
-       netif_tx_start_all_queues(adapter->netdev);
-
-       /* enable any upper devices */
-       netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
-               if (netif_is_macvlan(upper)) {
-                       struct macvlan_dev *vlan = netdev_priv(upper);
-
-                       if (vlan->fwd_priv)
-                               netif_tx_start_all_queues(upper);
-               }
-       }
-
        /* bring the link up in the watchdog, this could race with our first
         * link up interrupt but shouldn't be a problem */
        adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -5502,6 +5552,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
        struct net_device *netdev = adapter->netdev;
        u32 err;
 
+       adapter->hw.hw_addr = adapter->io_addr;
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        /*
@@ -6016,6 +6067,8 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
+       struct net_device *upper;
+       struct list_head *iter;
        u32 link_speed = adapter->link_speed;
        bool flow_rx, flow_tx;
 
@@ -6067,6 +6120,21 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
        netif_carrier_on(netdev);
        ixgbe_check_vf_rate_limit(adapter);
 
+       /* enable transmits */
+       netif_tx_wake_all_queues(adapter->netdev);
+
+       /* enable any upper devices */
+       rtnl_lock();
+       netdev_for_each_all_upper_dev_rcu(adapter->netdev, upper, iter) {
+               if (netif_is_macvlan(upper)) {
+                       struct macvlan_dev *vlan = netdev_priv(upper);
+
+                       if (vlan->fwd_priv)
+                               netif_tx_wake_all_queues(upper);
+               }
+       }
+       rtnl_unlock();
+
        /* update the default user priority for VFs */
        ixgbe_update_default_up(adapter);
 
@@ -6454,7 +6522,7 @@ static int ixgbe_tso(struct ixgbe_ring *tx_ring,
        /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
        type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
 
-       if (first->protocol == __constant_htons(ETH_P_IP)) {
+       if (first->protocol == htons(ETH_P_IP)) {
                struct iphdr *iph = ip_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
@@ -6514,12 +6582,12 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring,
        } else {
                u8 l4_hdr = 0;
                switch (first->protocol) {
-               case __constant_htons(ETH_P_IP):
+               case htons(ETH_P_IP):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
                        l4_hdr = ip_hdr(skb)->protocol;
                        break;
-               case __constant_htons(ETH_P_IPV6):
+               case htons(ETH_P_IPV6):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        l4_hdr = ipv6_hdr(skb)->nexthdr;
                        break;
@@ -6794,9 +6862,9 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
        hdr.network = skb_network_header(first->skb);
 
        /* Currently only IPv4/IPv6 with TCP is supported */
-       if ((first->protocol != __constant_htons(ETH_P_IPV6) ||
+       if ((first->protocol != htons(ETH_P_IPV6) ||
             hdr.ipv6->nexthdr != IPPROTO_TCP) &&
-           (first->protocol != __constant_htons(ETH_P_IP) ||
+           (first->protocol != htons(ETH_P_IP) ||
             hdr.ipv4->protocol != IPPROTO_TCP))
                return;
 
@@ -6829,12 +6897,12 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
         * and write the value to source port portion of compressed dword
         */
        if (first->tx_flags & (IXGBE_TX_FLAGS_SW_VLAN | IXGBE_TX_FLAGS_HW_VLAN))
-               common.port.src ^= th->dest ^ __constant_htons(ETH_P_8021Q);
+               common.port.src ^= th->dest ^ htons(ETH_P_8021Q);
        else
                common.port.src ^= th->dest ^ first->protocol;
        common.port.dst ^= th->source;
 
-       if (first->protocol == __constant_htons(ETH_P_IP)) {
+       if (first->protocol == htons(ETH_P_IP)) {
                input.formatted.flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4;
                common.ip ^= hdr.ipv4->saddr ^ hdr.ipv4->daddr;
        } else {
@@ -6881,7 +6949,7 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
 }
 
 static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
-                             void *accel_priv)
+                             void *accel_priv, select_queue_fallback_t fallback)
 {
        struct ixgbe_fwd_adapter *fwd_adapter = accel_priv;
 #ifdef IXGBE_FCOE
@@ -6900,14 +6968,14 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
         * or FIP and we have FCoE enabled on the adapter
         */
        switch (vlan_get_protocol(skb)) {
-       case __constant_htons(ETH_P_FCOE):
-       case __constant_htons(ETH_P_FIP):
+       case htons(ETH_P_FCOE):
+       case htons(ETH_P_FIP):
                adapter = netdev_priv(dev);
 
                if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
                        break;
        default:
-               return __netdev_pick_tx(dev, skb);
+               return fallback(dev, skb);
        }
 
        f = &adapter->ring_feature[RING_F_FCOE];
@@ -6920,7 +6988,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
 
        return txq + f->offset;
 #else
-       return __netdev_pick_tx(dev, skb);
+       return fallback(dev, skb);
 #endif
 }
 
@@ -6962,7 +7030,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
                tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
                tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
        /* else if it is a SW VLAN check the next protocol and store the tag */
-       } else if (protocol == __constant_htons(ETH_P_8021Q)) {
+       } else if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_hdr *vhdr, _vhdr;
                vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
                if (!vhdr)
@@ -7021,7 +7089,7 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
 
 #ifdef IXGBE_FCOE
        /* setup tx offload for FCoE */
-       if ((protocol == __constant_htons(ETH_P_FCOE)) &&
+       if ((protocol == htons(ETH_P_FCOE)) &&
            (tx_ring->netdev->features & (NETIF_F_FSO | NETIF_F_FCOE_CRC))) {
                tso = ixgbe_fso(tx_ring, first, &hdr_len);
                if (tso < 0)
@@ -7143,7 +7211,9 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd)
 
        switch (cmd) {
        case SIOCSHWTSTAMP:
-               return ixgbe_ptp_hwtstamp_ioctl(adapter, req, cmd);
+               return ixgbe_ptp_set_ts_config(adapter, req);
+       case SIOCGHWTSTAMP:
+               return ixgbe_ptp_get_ts_config(adapter, req);
        default:
                return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd);
        }
@@ -7234,10 +7304,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
 
                if (ring) {
                        do {
-                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               start = u64_stats_fetch_begin_irq(&ring->syncp);
                                packets = ring->stats.packets;
                                bytes   = ring->stats.bytes;
-                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                        stats->rx_packets += packets;
                        stats->rx_bytes   += bytes;
                }
@@ -7250,10 +7320,10 @@ static struct rtnl_link_stats64 *ixgbe_get_stats64(struct net_device *netdev,
 
                if (ring) {
                        do {
-                               start = u64_stats_fetch_begin_bh(&ring->syncp);
+                               start = u64_stats_fetch_begin_irq(&ring->syncp);
                                packets = ring->stats.packets;
                                bytes   = ring->stats.bytes;
-                       } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                        stats->tx_packets += packets;
                        stats->tx_bytes   += bytes;
                }
@@ -7792,6 +7862,7 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
        case IXGBE_DEV_ID_82599_SFP:
                /* Only these subdevices could supports WOL */
                switch (subdevice_id) {
+               case IXGBE_SUBDEV_ID_82599_SFP_WOL0:
                case IXGBE_SUBDEV_ID_82599_560FLR:
                        /* only support first port */
                        if (hw->bus.func != 0)
@@ -7969,10 +8040,6 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                goto err_sw_init;
 
-       /* Cache if MNG FW is up so we don't have to read the REG later */
-       if (hw->mac.ops.mng_fw_enabled)
-               hw->mng_fw_enabled = hw->mac.ops.mng_fw_enabled(hw);
-
        /* Make it possible the adapter to be woken up via WOL */
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_82599EB:
@@ -8223,7 +8290,7 @@ skip_sriov:
        ixgbe_dbg_adapter_init(adapter);
 
        /* Need link setup for MNG FW, else wait for IXGBE_UP */
-       if (hw->mng_fw_enabled && hw->mac.ops.setup_link)
+       if (ixgbe_mng_enabled(hw) && hw->mac.ops.setup_link)
                hw->mac.ops.setup_link(hw,
                        IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL,
                        true);
@@ -8331,6 +8398,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
        struct net_device *netdev = adapter->netdev;
 
 #ifdef CONFIG_PCI_IOV
+       struct ixgbe_hw *hw = &adapter->hw;
        struct pci_dev *bdev, *vfdev;
        u32 dw0, dw1, dw2, dw3;
        int vf, pos;
@@ -8351,10 +8419,12 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
        if (!pos)
                goto skip_bad_vf_detection;
 
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG, &dw0);
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 4, &dw1);
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 8, &dw2);
-       pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 12, &dw3);
+       dw0 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG);
+       dw1 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 4);
+       dw2 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 8);
+       dw3 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 12);
+       if (ixgbe_removed(hw->hw_addr))
+               goto skip_bad_vf_detection;
 
        req_id = dw1 >> 16;
        /* On the 82599 if bit 7 of the requestor ID is set then it's a VF */
@@ -8446,6 +8516,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
                e_err(probe, "Cannot re-enable PCI device after reset.\n");
                result = PCI_ERS_RESULT_DISCONNECT;
        } else {
+               adapter->hw.hw_addr = adapter->io_addr;
                pci_set_master(pdev);
                pci_restore_state(pdev);
                pci_save_state(pdev);
index cc3101afd29fe8745d0cd870271b3f5246ee88fa..f5c6af2b891bd3dc797e7c4f5640b006eac78810 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index e44ff47659b50b733cce7a17ce7a06ba010d7ce8..a9b9ad69ed0ec315d22d38c92eb1885c2900c9c3 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 132557c318f810b5f8bce65b4b0f2ebac613fdfd..ad51c12cb26a63fc3a8975e7527450e675f4133c 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -97,6 +98,32 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
        return status;
 }
 
+/**
+ * ixgbe_check_reset_blocked - check status of MNG FW veto bit
+ * @hw: pointer to the hardware structure
+ *
+ * This function checks the MMNGC.MNG_VETO bit to see if there are
+ * any constraints on link from manageability.  For MAC's that don't
+ * have this bit just return false since the link can not be blocked
+ * via this method.
+ **/
+s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw)
+{
+       u32 mmngc;
+
+       /* If we don't have this bit, it can't be blocking */
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               return false;
+
+       mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC);
+       if (mmngc & IXGBE_MMNGC_MNG_VETO) {
+               hw_dbg(hw, "MNG_VETO bit detected.\n");
+               return true;
+       }
+
+       return false;
+}
+
 /**
  *  ixgbe_get_phy_id - Get the phy type
  *  @hw: pointer to hardware structure
@@ -172,6 +199,10 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
            (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw)))
                goto out;
 
+       /* Blocked by MNG FW so bail */
+       if (ixgbe_check_reset_blocked(hw))
+               goto out;
+
        /*
         * Perform soft PHY reset to the PHY_XS.
         * This will cause a soft reset to the PHY
@@ -476,6 +507,10 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
                                      autoneg_reg);
        }
 
+       /* Blocked by MNG FW so don't reset PHY */
+       if (ixgbe_check_reset_blocked(hw))
+               return status;
+
        /* Restart PHY autonegotiation and wait for completion */
        hw->phy.ops.read_reg(hw, MDIO_CTRL1,
                             MDIO_MMD_AN, &autoneg_reg);
@@ -682,6 +717,10 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
                                      autoneg_reg);
        }
 
+       /* Blocked by MNG FW so don't reset PHY */
+       if (ixgbe_check_reset_blocked(hw))
+               return status;
+
        /* Restart PHY autonegotiation and wait for completion */
        hw->phy.ops.read_reg(hw, MDIO_CTRL1,
                             MDIO_MMD_AN, &autoneg_reg);
@@ -759,6 +798,10 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
        s32 ret_val = 0;
        u32 i;
 
+       /* Blocked by MNG FW so bail */
+       if (ixgbe_check_reset_blocked(hw))
+               goto out;
+
        hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data);
 
        /* reset the PHY and poll for completion */
index fffcbdd2bf0e49ab129abf04cd16a650a4d5cb91..4a456c974ef2c9d371f1528a5cde1d92c4bd9cfb 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -65,9 +66,6 @@
 #define IXGBE_SFF_1GBASET_CAPABLE              0x8
 #define IXGBE_SFF_10GBASESR_CAPABLE            0x10
 #define IXGBE_SFF_10GBASELR_CAPABLE            0x20
-#define IXGBE_SFF_SOFT_RS_SELECT_MASK          0x8
-#define IXGBE_SFF_SOFT_RS_SELECT_10G           0x8
-#define IXGBE_SFF_SOFT_RS_SELECT_1G            0x0
 #define IXGBE_SFF_ADDRESSING_MODE              0x4
 #define IXGBE_SFF_QSFP_DA_ACTIVE_CABLE         0x1
 #define IXGBE_SFF_QSFP_DA_PASSIVE_CABLE                0x8
@@ -79,7 +77,6 @@
 #define IXGBE_I2C_EEPROM_STATUS_PASS           0x1
 #define IXGBE_I2C_EEPROM_STATUS_FAIL           0x2
 #define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS    0x3
-
 /* Flow control defines */
 #define IXGBE_TAF_SYM_PAUSE                  0x400
 #define IXGBE_TAF_ASM_PAUSE                  0x800
@@ -131,6 +128,7 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
 s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw,
                                                ixgbe_link_speed *speed,
                                                bool *autoneg);
+s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw);
 
 /* PHY specific */
 s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw,
index 5184e2a1a7d8249bc746ce6496e55f5789a0e949..44ac9aef6a8d51d0371368525c4038e5faa0b2e1 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -576,14 +577,21 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
        shhwtstamps->hwtstamp = ns_to_ktime(ns);
 }
 
+int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
+{
+       struct hwtstamp_config *config = &adapter->tstamp_config;
+
+       return copy_to_user(ifr->ifr_data, config,
+                           sizeof(*config)) ? -EFAULT : 0;
+}
+
 /**
- * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping
+ * ixgbe_ptp_set_ts_config - control hardware time stamping
  * @adapter: pointer to adapter struct
  * @ifreq: ioctl data
- * @cmd: particular ioctl requested
  *
  * Outgoing time stamping can be enabled and disabled. Play nice and
- * disable it when requested, although it shouldn't case any overhead
+ * disable it when requested, although it shouldn't cause any overhead
  * when no packet needs it. At most one packet in the queue may be
  * marked for time stamping, otherwise it would be impossible to tell
  * for sure to which packet the hardware time stamp belongs.
@@ -599,8 +607,7 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector,
  * Event mode. This more accurately tells the user what the hardware is going
  * to do anyways.
  */
-int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
-                            struct ifreq *ifr, int cmd)
+int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        struct hwtstamp_config config;
@@ -702,6 +709,10 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter,
        regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH);
        regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
 
+       /* save these settings for future reference */
+       memcpy(&adapter->tstamp_config, &config,
+              sizeof(adapter->tstamp_config));
+
        return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
                -EFAULT : 0;
 }
@@ -809,6 +820,9 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000);
        IXGBE_WRITE_FLUSH(hw);
 
+       /* Reset the saved tstamp_config */
+       memset(&adapter->tstamp_config, 0, sizeof(adapter->tstamp_config));
+
        ixgbe_ptp_start_cyclecounter(adapter);
 
        spin_lock_irqsave(&adapter->tmreg_lock, flags);
@@ -840,7 +854,9 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
 
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_X540:
-               snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name);
+               snprintf(adapter->ptp_caps.name,
+                        sizeof(adapter->ptp_caps.name),
+                        "%s", netdev->name);
                adapter->ptp_caps.owner = THIS_MODULE;
                adapter->ptp_caps.max_adj = 250000000;
                adapter->ptp_caps.n_alarm = 0;
@@ -854,7 +870,9 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter)
                adapter->ptp_caps.enable = ixgbe_ptp_enable;
                break;
        case ixgbe_mac_82599EB:
-               snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name);
+               snprintf(adapter->ptp_caps.name,
+                        sizeof(adapter->ptp_caps.name),
+                        "%s", netdev->name);
                adapter->ptp_caps.owner = THIS_MODULE;
                adapter->ptp_caps.max_adj = 250000000;
                adapter->ptp_caps.n_alarm = 0;
index dff0977876f75448ee67ef6e1305bdc8b5e8be22..e6c68d396c992fffb329a1cca4daadb47169faab 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 8bd29190514e4a7be7fd498cb28a0bef1336d082..139eaddfb2ed5c8c14a3891137a313b4fcaa3a6a 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index e74ae3682733df328b8b9f85631da133778bc9ee..ef6df3d6437e3102224adef7033a3b26f058ef7e 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
index 0d39cfc4a3bf2aa84294b4a12cf91b4a3a5353da..8a6ff2423f076974d1c3c408b97c497d00bdc277 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -54,6 +55,7 @@
 #define IXGBE_DEV_ID_82599_BACKPLANE_FCOE       0x152a
 #define IXGBE_DEV_ID_82599_SFP_FCOE      0x1529
 #define IXGBE_SUBDEV_ID_82599_SFP        0x11A9
+#define IXGBE_SUBDEV_ID_82599_SFP_WOL0   0x1071
 #define IXGBE_SUBDEV_ID_82599_RNDC       0x1F72
 #define IXGBE_SUBDEV_ID_82599_560FLR     0x17D0
 #define IXGBE_SUBDEV_ID_82599_SP_560FLR  0x211B
@@ -1609,6 +1611,9 @@ enum {
 #define IXGBE_MACC_FS        0x00040000
 #define IXGBE_MAC_RX2TX_LPBK 0x00000002
 
+/* Veto Bit definiton */
+#define IXGBE_MMNGC_MNG_VETO  0x00000001
+
 /* LINKS Bit Masks */
 #define IXGBE_LINKS_KX_AN_COMP  0x80000000
 #define IXGBE_LINKS_UP          0x40000000
@@ -1788,6 +1793,9 @@ enum {
 #define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */
 #define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */
 
+#define IXGBE_EEPROM_CTRL_2    1 /* EEPROM CTRL word 2 */
+#define IXGBE_EEPROM_CCD_BIT   2 /* EEPROM Core Clock Disable bit */
+
 #ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
 #define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
 #endif
@@ -1853,8 +1861,19 @@ enum {
 #define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80
 #define IXGBE_PCI_DEVICE_CONTROL2_16ms  0x0005
 
+#define IXGBE_PCIDEVCTRL2_TIMEO_MASK   0xf
+#define IXGBE_PCIDEVCTRL2_16_32ms_def  0x0
+#define IXGBE_PCIDEVCTRL2_50_100us     0x1
+#define IXGBE_PCIDEVCTRL2_1_2ms                0x2
+#define IXGBE_PCIDEVCTRL2_16_32ms      0x5
+#define IXGBE_PCIDEVCTRL2_65_130ms     0x6
+#define IXGBE_PCIDEVCTRL2_260_520ms    0x9
+#define IXGBE_PCIDEVCTRL2_1_2s         0xa
+#define IXGBE_PCIDEVCTRL2_4_8s         0xd
+#define IXGBE_PCIDEVCTRL2_17_34s       0xe
+
 /* Number of 100 microseconds we wait for PCI Express master disable */
-#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
+#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT       800
 
 /* RAH */
 #define IXGBE_RAH_VIND_MASK     0x003C0000
@@ -2645,7 +2664,6 @@ enum ixgbe_sfp_type {
 enum ixgbe_media_type {
        ixgbe_media_type_unknown = 0,
        ixgbe_media_type_fiber,
-       ixgbe_media_type_fiber_fixed,
        ixgbe_media_type_fiber_qsfp,
        ixgbe_media_type_fiber_lco,
        ixgbe_media_type_copper,
@@ -2858,6 +2876,8 @@ struct ixgbe_mac_operations {
        s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);
        s32 (*acquire_swfw_sync)(struct ixgbe_hw *, u16);
        void (*release_swfw_sync)(struct ixgbe_hw *, u16);
+       s32 (*prot_autoc_read)(struct ixgbe_hw *, bool *, u32 *);
+       s32 (*prot_autoc_write)(struct ixgbe_hw *, u32, bool);
 
        /* Link */
        void (*disable_tx_laser)(struct ixgbe_hw *);
@@ -2901,7 +2921,6 @@ struct ixgbe_mac_operations {
        s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8);
        s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
        s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
-       bool (*mng_fw_enabled)(struct ixgbe_hw *hw);
 };
 
 struct ixgbe_phy_operations {
@@ -2957,7 +2976,6 @@ struct ixgbe_mac_info {
        u32                             max_tx_queues;
        u32                             max_rx_queues;
        u32                             orig_autoc;
-       u32                             cached_autoc;
        u32                             orig_autoc2;
        bool                            orig_link_settings_stored;
        bool                            autotry_restart;
@@ -3033,7 +3051,6 @@ struct ixgbe_hw {
        bool                            adapter_stopped;
        bool                            force_full_reset;
        bool                            allow_unsupported_sfp;
-       bool                            mng_fw_enabled;
        bool                            wol_enabled;
 };
 
index 24b80a6cfca4ec593f7bed4bf2e1423213125d90..188a5974b85c41f7b8279b6128f72f749e845f76 100644 (file)
@@ -20,6 +20,7 @@
   the file called "COPYING".
 
   Contact Information:
+  Linux NICS <linux.nics@intel.com>
   e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
   Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 
@@ -61,6 +62,7 @@ static s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw)
        mac->mcft_size = IXGBE_X540_MC_TBL_SIZE;
        mac->vft_size = IXGBE_X540_VFT_TBL_SIZE;
        mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES;
+       mac->rx_pb_size = IXGBE_X540_RX_PB_SIZE;
        mac->max_rx_queues = IXGBE_X540_MAX_RX_QUEUES;
        mac->max_tx_queues = IXGBE_X540_MAX_TX_QUEUES;
        mac->max_msix_vectors = ixgbe_get_pcie_msix_count_generic(hw);
@@ -187,7 +189,6 @@ static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw)
                goto out;
 
        ret_val = ixgbe_start_hw_gen2(hw);
-       hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE;
 out:
        return ret_val;
 }
@@ -854,7 +855,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
        .enable_rx_buff         = &ixgbe_enable_rx_buff_generic,
        .get_thermal_sensor_data = NULL,
        .init_thermal_sensor_thresh = NULL,
-       .mng_fw_enabled         = NULL,
+       .prot_autoc_read        = &prot_autoc_read_generic,
+       .prot_autoc_write       = &prot_autoc_write_generic,
 };
 
 static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
index f68b78c732a8626c3c011a6d83329c3779fccc51..b2d002394e5d6a8eaa5a78bf9ffdab5c0a86083f 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 82599 Virtual Function driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -530,41 +530,55 @@ static const u32 register_test_patterns[] = {
        0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
 };
 
-#define REG_PATTERN_TEST(R, M, W)                                             \
-{                                                                             \
-       u32 pat, val, before;                                                 \
-       for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) {      \
-               before = readl(adapter->hw.hw_addr + R);                      \
-               writel((register_test_patterns[pat] & W),                     \
-                      (adapter->hw.hw_addr + R));                            \
-               val = readl(adapter->hw.hw_addr + R);                         \
-               if (val != (register_test_patterns[pat] & W & M)) {           \
-                       hw_dbg(&adapter->hw,                                  \
-                       "pattern test reg %04X failed: got "                  \
-                       "0x%08X expected 0x%08X\n",                           \
-                       R, val, (register_test_patterns[pat] & W & M));       \
-                       *data = R;                                            \
-                       writel(before, adapter->hw.hw_addr + R);              \
-                       return 1;                                             \
-               }                                                             \
-               writel(before, adapter->hw.hw_addr + R);                      \
-       }                                                                     \
+static bool reg_pattern_test(struct ixgbevf_adapter *adapter, u64 *data,
+                            int reg, u32 mask, u32 write)
+{
+       u32 pat, val, before;
+
+       if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+               *data = 1;
+               return true;
+       }
+       for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) {
+               before = ixgbe_read_reg(&adapter->hw, reg);
+               ixgbe_write_reg(&adapter->hw, reg,
+                               register_test_patterns[pat] & write);
+               val = ixgbe_read_reg(&adapter->hw, reg);
+               if (val != (register_test_patterns[pat] & write & mask)) {
+                       hw_dbg(&adapter->hw,
+                              "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
+                              reg, val,
+                              register_test_patterns[pat] & write & mask);
+                       *data = reg;
+                       ixgbe_write_reg(&adapter->hw, reg, before);
+                       return true;
+               }
+               ixgbe_write_reg(&adapter->hw, reg, before);
+       }
+       return false;
 }
 
-#define REG_SET_AND_CHECK(R, M, W)                                            \
-{                                                                             \
-       u32 val, before;                                                      \
-       before = readl(adapter->hw.hw_addr + R);                              \
-       writel((W & M), (adapter->hw.hw_addr + R));                           \
-       val = readl(adapter->hw.hw_addr + R);                                 \
-       if ((W & M) != (val & M)) {                                           \
-               pr_err("set/check reg %04X test failed: got 0x%08X expected " \
-                      "0x%08X\n", R, (val & M), (W & M));                    \
-               *data = R;                                                    \
-               writel(before, (adapter->hw.hw_addr + R));                    \
-               return 1;                                                     \
-       }                                                                     \
-       writel(before, (adapter->hw.hw_addr + R));                            \
+static bool reg_set_and_check(struct ixgbevf_adapter *adapter, u64 *data,
+                             int reg, u32 mask, u32 write)
+{
+       u32 val, before;
+
+       if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+               *data = 1;
+               return true;
+       }
+       before = ixgbe_read_reg(&adapter->hw, reg);
+       ixgbe_write_reg(&adapter->hw, reg, write & mask);
+       val = ixgbe_read_reg(&adapter->hw, reg);
+       if ((write & mask) != (val & mask)) {
+               pr_err("set/check reg %04X test failed: got 0x%08X expected 0x%08X\n",
+                      reg, (val & mask), write & mask);
+               *data = reg;
+               ixgbe_write_reg(&adapter->hw, reg, before);
+               return true;
+       }
+       ixgbe_write_reg(&adapter->hw, reg, before);
+       return false;
 }
 
 static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
@@ -572,6 +586,12 @@ static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
        const struct ixgbevf_reg_test *test;
        u32 i;
 
+       if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+               dev_err(&adapter->pdev->dev,
+                       "Adapter removed - register test blocked\n");
+               *data = 1;
+               return 1;
+       }
        test = reg_test_vf;
 
        /*
@@ -580,38 +600,47 @@ static int ixgbevf_reg_test(struct ixgbevf_adapter *adapter, u64 *data)
         */
        while (test->reg) {
                for (i = 0; i < test->array_len; i++) {
+                       bool b = false;
+
                        switch (test->test_type) {
                        case PATTERN_TEST:
-                               REG_PATTERN_TEST(test->reg + (i * 0x40),
-                                               test->mask,
-                                               test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + (i * 0x40),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        case SET_READ_TEST:
-                               REG_SET_AND_CHECK(test->reg + (i * 0x40),
-                                               test->mask,
-                                               test->write);
+                               b = reg_set_and_check(adapter, data,
+                                                     test->reg + (i * 0x40),
+                                                     test->mask,
+                                                     test->write);
                                break;
                        case WRITE_NO_TEST:
-                               writel(test->write,
-                                      (adapter->hw.hw_addr + test->reg)
-                                      + (i * 0x40));
+                               ixgbe_write_reg(&adapter->hw,
+                                                 test->reg + (i * 0x40),
+                                                 test->write);
                                break;
                        case TABLE32_TEST:
-                               REG_PATTERN_TEST(test->reg + (i * 4),
-                                               test->mask,
-                                               test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + (i * 4),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        case TABLE64_TEST_LO:
-                               REG_PATTERN_TEST(test->reg + (i * 8),
-                                               test->mask,
-                                               test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + (i * 8),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        case TABLE64_TEST_HI:
-                               REG_PATTERN_TEST((test->reg + 4) + (i * 8),
-                                               test->mask,
-                                               test->write);
+                               b = reg_pattern_test(adapter, data,
+                                                    test->reg + 4 + (i * 8),
+                                                    test->mask,
+                                                    test->write);
                                break;
                        }
+                       if (b)
+                               return 1;
                }
                test++;
        }
@@ -626,6 +655,14 @@ static void ixgbevf_diag_test(struct net_device *netdev,
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
        bool if_running = netif_running(netdev);
 
+       if (IXGBE_REMOVED(adapter->hw.hw_addr)) {
+               dev_err(&adapter->pdev->dev,
+                       "Adapter removed - test blocked\n");
+               data[0] = 1;
+               data[1] = 1;
+               eth_test->flags |= ETH_TEST_FL_FAILED;
+               return;
+       }
        set_bit(__IXGBEVF_TESTING, &adapter->state);
        if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
                /* Offline tests */
index 54829326bb09fc7196f78a4b5d9758b65c45f1e6..a08bd7c46766dd84253a116748b29086bda6a1d8 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 82599 Virtual Function driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -315,6 +315,11 @@ static inline u16 ixgbevf_desc_unused(struct ixgbevf_ring *ring)
        return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
 }
 
+static inline void ixgbevf_write_tail(struct ixgbevf_ring *ring, u32 value)
+{
+       writel(value, ring->tail);
+}
+
 #define IXGBEVF_RX_DESC(R, i)      \
        (&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
 #define IXGBEVF_TX_DESC(R, i)      \
@@ -401,6 +406,7 @@ struct ixgbevf_adapter {
        u64 bp_tx_missed;
 #endif
 
+       u8 __iomem *io_addr; /* Mainly for iounmap use */
        u32 link_speed;
        bool link_up;
 
@@ -412,7 +418,8 @@ struct ixgbevf_adapter {
 enum ixbgevf_state_t {
        __IXGBEVF_TESTING,
        __IXGBEVF_RESETTING,
-       __IXGBEVF_DOWN
+       __IXGBEVF_DOWN,
+       __IXGBEVF_REMOVING,
 };
 
 struct ixgbevf_cb {
index 9df28985eba7cf45acfcfc232520915854279151..a50e892a5d21734de8d8f733d19693d98c99a257 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 82599 Virtual Function driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -99,6 +99,49 @@ static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter);
 static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector);
 static void ixgbevf_free_all_rx_resources(struct ixgbevf_adapter *adapter);
 
+static void ixgbevf_remove_adapter(struct ixgbe_hw *hw)
+{
+       struct ixgbevf_adapter *adapter = hw->back;
+
+       if (!hw->hw_addr)
+               return;
+       hw->hw_addr = NULL;
+       dev_err(&adapter->pdev->dev, "Adapter removed\n");
+       schedule_work(&adapter->watchdog_task);
+}
+
+static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg)
+{
+       u32 value;
+
+       /* The following check not only optimizes a bit by not
+        * performing a read on the status register when the
+        * register just read was a status register read that
+        * returned IXGBE_FAILED_READ_REG. It also blocks any
+        * potential recursion.
+        */
+       if (reg == IXGBE_VFSTATUS) {
+               ixgbevf_remove_adapter(hw);
+               return;
+       }
+       value = ixgbe_read_reg(hw, IXGBE_VFSTATUS);
+       if (value == IXGBE_FAILED_READ_REG)
+               ixgbevf_remove_adapter(hw);
+}
+
+u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
+{
+       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+       u32 value;
+
+       if (IXGBE_REMOVED(reg_addr))
+               return IXGBE_FAILED_READ_REG;
+       value = readl(reg_addr + reg);
+       if (unlikely(value == IXGBE_FAILED_READ_REG))
+               ixgbevf_check_remove(hw, reg);
+       return value;
+}
+
 static inline void ixgbevf_release_rx_desc(struct ixgbevf_ring *rx_ring,
                                           u32 val)
 {
@@ -111,7 +154,7 @@ static inline void ixgbevf_release_rx_desc(struct ixgbevf_ring *rx_ring,
         * such as IA-64).
         */
        wmb();
-       writel(val, rx_ring->tail);
+       ixgbevf_write_tail(rx_ring, val);
 }
 
 /**
@@ -516,7 +559,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector,
                /* Workaround hardware that can't do proper VEPA multicast
                 * source pruning.
                 */
-               if ((skb->pkt_type & (PACKET_BROADCAST | PACKET_MULTICAST)) &&
+               if ((skb->pkt_type == PACKET_BROADCAST ||
+                   skb->pkt_type == PACKET_MULTICAST) &&
                    ether_addr_equal(rx_ring->netdev->dev_addr,
                                     eth_hdr(skb)->h_source)) {
                        dev_kfree_skb_irq(skb);
@@ -607,7 +651,8 @@ static int ixgbevf_poll(struct napi_struct *napi, int budget)
        napi_complete(napi);
        if (adapter->rx_itr_setting & 1)
                ixgbevf_set_itr(q_vector);
-       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+       if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+           !test_bit(__IXGBEVF_REMOVING, &adapter->state))
                ixgbevf_irq_enable_queues(adapter,
                                          1 << q_vector->v_idx);
 
@@ -832,7 +877,8 @@ static irqreturn_t ixgbevf_msix_other(int irq, void *data)
 
        hw->mac.get_link_status = 1;
 
-       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+       if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+           !test_bit(__IXGBEVF_REMOVING, &adapter->state))
                mod_timer(&adapter->watchdog_timer, jiffies);
 
        IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other);
@@ -1136,7 +1182,7 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
        /* reset head and tail pointers */
        IXGBE_WRITE_REG(hw, IXGBE_VFTDH(reg_idx), 0);
        IXGBE_WRITE_REG(hw, IXGBE_VFTDT(reg_idx), 0);
-       ring->tail = hw->hw_addr + IXGBE_VFTDT(reg_idx);
+       ring->tail = adapter->io_addr + IXGBE_VFTDT(reg_idx);
 
        /* reset ntu and ntc to place SW in sync with hardwdare */
        ring->next_to_clean = 0;
@@ -1256,6 +1302,8 @@ static void ixgbevf_disable_rx_queue(struct ixgbevf_adapter *adapter,
        u32 rxdctl;
        u8 reg_idx = ring->reg_idx;
 
+       if (IXGBE_REMOVED(hw->hw_addr))
+               return;
        rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(reg_idx));
        rxdctl &= ~IXGBE_RXDCTL_ENABLE;
 
@@ -1281,6 +1329,8 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,
        u32 rxdctl;
        u8 reg_idx = ring->reg_idx;
 
+       if (IXGBE_REMOVED(hw->hw_addr))
+               return;
        do {
                usleep_range(1000, 2000);
                rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(reg_idx));
@@ -1315,7 +1365,7 @@ static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
        /* reset head and tail pointers */
        IXGBE_WRITE_REG(hw, IXGBE_VFRDH(reg_idx), 0);
        IXGBE_WRITE_REG(hw, IXGBE_VFRDT(reg_idx), 0);
-       ring->tail = hw->hw_addr + IXGBE_VFRDT(reg_idx);
+       ring->tail = adapter->io_addr + IXGBE_VFRDT(reg_idx);
 
        /* reset ntu and ntc to place SW in sync with hardwdare */
        ring->next_to_clean = 0;
@@ -1617,6 +1667,7 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
 
        spin_unlock_bh(&adapter->mbx_lock);
 
+       smp_mb__before_clear_bit();
        clear_bit(__IXGBEVF_DOWN, &adapter->state);
        ixgbevf_napi_enable_all(adapter);
 
@@ -1741,7 +1792,8 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter)
        int i;
 
        /* signal that we are down to the interrupt handler */
-       set_bit(__IXGBEVF_DOWN, &adapter->state);
+       if (test_and_set_bit(__IXGBEVF_DOWN, &adapter->state))
+               return; /* do nothing if already down */
 
        /* disable all enabled rx queues */
        for (i = 0; i < adapter->num_rx_queues; i++)
@@ -1817,7 +1869,6 @@ void ixgbevf_reset(struct ixgbevf_adapter *adapter)
 static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
                                        int vectors)
 {
-       int err = 0;
        int vector_threshold;
 
        /* We'll want at least 2 (vector_threshold):
@@ -1831,33 +1882,24 @@ static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
         * Right now, we simply care about how many we'll get; we'll
         * set them up later while requesting irq's.
         */
-       while (vectors >= vector_threshold) {
-               err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
-                                     vectors);
-               if (!err || err < 0) /* Success or a nasty failure. */
-                       break;
-               else /* err == number of vectors we should try again with */
-                       vectors = err;
-       }
-
-       if (vectors < vector_threshold)
-               err = -ENOMEM;
+       vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries,
+                                       vector_threshold, vectors);
 
-       if (err) {
+       if (vectors < 0) {
                dev_err(&adapter->pdev->dev,
                        "Unable to allocate MSI-X interrupts\n");
                kfree(adapter->msix_entries);
                adapter->msix_entries = NULL;
-       } else {
-               /*
-                * Adjust for only the vectors we'll use, which is minimum
-                * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
-                * vectors we were allocated.
-                */
-               adapter->num_msix_vectors = vectors;
+               return vectors;
        }
 
-       return err;
+       /* Adjust for only the vectors we'll use, which is minimum
+        * of max_msix_q_vectors + NON_Q_VECTORS, or the number of
+        * vectors we were allocated.
+        */
+       adapter->num_msix_vectors = vectors;
+
+       return 0;
 }
 
 /**
@@ -2338,6 +2380,7 @@ static void ixgbevf_reset_task(struct work_struct *work)
 
        /* If we're already down or resetting, just bail */
        if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+           test_bit(__IXGBEVF_REMOVING, &adapter->state) ||
            test_bit(__IXGBEVF_RESETTING, &adapter->state))
                return;
 
@@ -2361,6 +2404,14 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
        bool link_up = adapter->link_up;
        s32 need_reset;
 
+       if (IXGBE_REMOVED(hw->hw_addr)) {
+               if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+                       rtnl_lock();
+                       ixgbevf_down(adapter);
+                       rtnl_unlock();
+               }
+               return;
+       }
        ixgbevf_queue_reset_subtask(adapter);
 
        adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
@@ -2422,7 +2473,8 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
 
 pf_has_reset:
        /* Reset the timer */
-       if (!test_bit(__IXGBEVF_DOWN, &adapter->state))
+       if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+           !test_bit(__IXGBEVF_REMOVING, &adapter->state))
                mod_timer(&adapter->watchdog_timer,
                          round_jiffies(jiffies + (2 * HZ)));
 
@@ -2787,6 +2839,9 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
        u32 vlan_macip_lens, type_tucmd;
        u32 mss_l4len_idx, l4len;
 
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return 0;
+
        if (!skb_is_gso(skb))
                return 0;
 
@@ -2857,12 +2912,12 @@ static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 l4_hdr = 0;
                switch (skb->protocol) {
-               case __constant_htons(ETH_P_IP):
+               case htons(ETH_P_IP):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
                        l4_hdr = ip_hdr(skb)->protocol;
                        break;
-               case __constant_htons(ETH_P_IPV6):
+               case htons(ETH_P_IPV6):
                        vlan_macip_lens |= skb_network_header_len(skb);
                        l4_hdr = ipv6_hdr(skb)->nexthdr;
                        break;
@@ -3060,7 +3115,7 @@ static void ixgbevf_tx_map(struct ixgbevf_ring *tx_ring,
        tx_ring->next_to_use = i;
 
        /* notify HW of packet */
-       writel(i, tx_ring->tail);
+       ixgbevf_write_tail(tx_ring, i);
 
        return;
 dma_error:
@@ -3165,7 +3220,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        tso = ixgbevf_tso(tx_ring, first, &hdr_len);
        if (tso < 0)
                goto out_drop;
-       else
+       else if (!tso)
                ixgbevf_tx_csum(tx_ring, first);
 
        ixgbevf_tx_map(tx_ring, first, hdr_len);
@@ -3286,7 +3341,6 @@ static int ixgbevf_resume(struct pci_dev *pdev)
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
        u32 err;
 
-       pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        /*
         * pci_restore_state clears dev->state_saved so call
@@ -3344,10 +3398,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
        for (i = 0; i < adapter->num_rx_queues; i++) {
                ring = adapter->rx_ring[i];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        bytes = ring->stats.bytes;
                        packets = ring->stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                stats->rx_bytes += bytes;
                stats->rx_packets += packets;
        }
@@ -3355,10 +3409,10 @@ static struct rtnl_link_stats64 *ixgbevf_get_stats(struct net_device *netdev,
        for (i = 0; i < adapter->num_tx_queues; i++) {
                ring = adapter->tx_ring[i];
                do {
-                       start = u64_stats_fetch_begin_bh(&ring->syncp);
+                       start = u64_stats_fetch_begin_irq(&ring->syncp);
                        bytes = ring->stats.bytes;
                        packets = ring->stats.packets;
-               } while (u64_stats_fetch_retry_bh(&ring->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
                stats->tx_bytes += bytes;
                stats->tx_packets += packets;
        }
@@ -3460,6 +3514,7 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
                              pci_resource_len(pdev, 0));
+       adapter->io_addr = hw->hw_addr;
        if (!hw->hw_addr) {
                err = -EIO;
                goto err_ioremap;
@@ -3545,7 +3600,7 @@ err_register:
        ixgbevf_clear_interrupt_scheme(adapter);
 err_sw_init:
        ixgbevf_reset_interrupt_capability(adapter);
-       iounmap(hw->hw_addr);
+       iounmap(adapter->io_addr);
 err_ioremap:
        free_netdev(netdev);
 err_alloc_etherdev:
@@ -3570,7 +3625,7 @@ static void ixgbevf_remove(struct pci_dev *pdev)
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct ixgbevf_adapter *adapter = netdev_priv(netdev);
 
-       set_bit(__IXGBEVF_DOWN, &adapter->state);
+       set_bit(__IXGBEVF_REMOVING, &adapter->state);
 
        del_timer_sync(&adapter->watchdog_timer);
 
@@ -3583,7 +3638,7 @@ static void ixgbevf_remove(struct pci_dev *pdev)
        ixgbevf_clear_interrupt_scheme(adapter);
        ixgbevf_reset_interrupt_capability(adapter);
 
-       iounmap(adapter->hw.hw_addr);
+       iounmap(adapter->io_addr);
        pci_release_regions(pdev);
 
        hw_dbg(&adapter->hw, "Remove complete\n");
index debd8c0e1f28df74db51c04809beeff3f2a9855c..09dd8f698beacc4b91979f149354352b586ffe74 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 82599 Virtual Function driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
 #define IXGBE_VFGOTC_MSB       0x02024
 #define IXGBE_VFMPRC           0x01034
 
-#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
-
-#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
-
-#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) ( \
-    writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
-
-#define IXGBE_READ_REG_ARRAY(a, reg, offset) ( \
-    readl((a)->hw_addr + (reg) + ((offset) << 2)))
-
 #define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS))
 
 #endif /* _IXGBEVF_REGS_H_ */
index 7b1f502d171606366c06c767a65eb7ead6add2aa..096d33a59def24fce47028314dd406c8ba97436f 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
 
   Intel 82599 Virtual Function driver
-  Copyright(c) 1999 - 2012 Intel Corporation.
+  Copyright(c) 1999 - 2014 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
@@ -172,6 +172,37 @@ struct ixgbevf_info {
        const struct ixgbe_mac_operations *mac_ops;
 };
 
+#define IXGBE_FAILED_READ_REG 0xffffffffU
+
+#define IXGBE_REMOVED(a) unlikely(!(a))
+
+static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
+{
+       u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
+
+       if (IXGBE_REMOVED(reg_addr))
+               return;
+       writel(value, reg_addr + reg);
+}
+#define IXGBE_WRITE_REG(h, r, v) ixgbe_write_reg(h, r, v)
+
+u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg);
+#define IXGBE_READ_REG(h, r) ixgbe_read_reg(h, r)
+
+static inline void ixgbe_write_reg_array(struct ixgbe_hw *hw, u32 reg,
+                                         u32 offset, u32 value)
+{
+       ixgbe_write_reg(hw, reg + (offset << 2), value);
+}
+#define IXGBE_WRITE_REG_ARRAY(h, r, o, v) ixgbe_write_reg_array(h, r, o, v)
+
+static inline u32 ixgbe_read_reg_array(struct ixgbe_hw *hw, u32 reg,
+                                       u32 offset)
+{
+       return ixgbe_read_reg(hw, reg + (offset << 2));
+}
+#define IXGBE_READ_REG_ARRAY(h, r, o) ixgbe_read_reg_array(h, r, o)
+
 void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size);
 int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api);
 int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs,
index f5685c0d057911c6c2f59dd982f21f869d1b978c..b0c6050479eb460ae306cccaa93926f738e64c2e 100644 (file)
@@ -2053,19 +2053,6 @@ jme_map_tx_skb(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 
 }
 
-static int
-jme_expand_header(struct jme_adapter *jme, struct sk_buff *skb)
-{
-       if (unlikely(skb_shinfo(skb)->gso_size &&
-                       skb_header_cloned(skb) &&
-                       pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) {
-               dev_kfree_skb(skb);
-               return -1;
-       }
-
-       return 0;
-}
-
 static int
 jme_tx_tso(struct sk_buff *skb, __le16 *mss, u8 *flags)
 {
@@ -2225,7 +2212,8 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        struct jme_adapter *jme = netdev_priv(netdev);
        int idx;
 
-       if (unlikely(jme_expand_header(jme, skb))) {
+       if (unlikely(skb_is_gso(skb) && skb_cow_head(skb, 0))) {
+               dev_kfree_skb_any(skb);
                ++(NET_STAT(jme).tx_dropped);
                return NETDEV_TX_OK;
        }
index 8f9266c64c7589902c62443f79cc65a00895785f..fd4b6aecf6ee85d8f135cd6491582b417e1f3f1a 100644 (file)
@@ -619,7 +619,7 @@ ltq_etop_set_multicast_list(struct net_device *dev)
 
 static u16
 ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb,
-                     void *accel_priv)
+                     void *accel_priv, select_queue_fallback_t fallback)
 {
        /* we are currently only using the first queue */
        return 0;
index 6300fd27f2dbcc51157e362db65510c501b3ca6a..68e6a6613e9a1ccfd6a45f10d0ca0fb53c4c3dd6 100644 (file)
@@ -43,12 +43,12 @@ config MVMDIO
          This driver is used by the MV643XX_ETH and MVNETA drivers.
 
 config MVNETA
-       tristate "Marvell Armada 370/XP network interface support"
-       depends on MACH_ARMADA_370_XP
+       tristate "Marvell Armada 370/38x/XP network interface support"
+       depends on PLAT_ORION
        select MVMDIO
        ---help---
          This driver supports the network interface units in the
-         Marvell ARMADA XP and ARMADA 370 SoC family.
+         Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
 
          Note that this driver is distinct from the mv643xx_eth
          driver, which should be used for the older Marvell SoCs
index a2565ce22b7c9af32d6c34ac011f468e36153296..b7b8d74c22d9c6f7e7f9aaa7c9211722ec5929fd 100644 (file)
@@ -730,7 +730,7 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb)
                    unlikely(tag_bytes & ~12)) {
                        if (skb_checksum_help(skb) == 0)
                                goto no_csum;
-                       kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        return 1;
                }
 
@@ -819,7 +819,7 @@ static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        if (txq->tx_ring_size - txq->tx_desc_count < MAX_SKB_FRAGS + 1) {
                if (net_ratelimit())
                        netdev_err(dev, "tx queue full?!\n");
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index fd409d76b811487673c1cf038d9572c5f507f62a..b161a525fc5bd8accb44b002b64776f05d8d0319 100644 (file)
@@ -167,11 +167,6 @@ out:
        return ret;
 }
 
-static int orion_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static irqreturn_t orion_mdio_err_irq(int irq, void *dev_id)
 {
        struct orion_mdio_dev *dev = dev_id;
@@ -209,7 +204,6 @@ static int orion_mdio_probe(struct platform_device *pdev)
        bus->name = "orion_mdio_bus";
        bus->read = orion_mdio_read;
        bus->write = orion_mdio_write;
-       bus->reset = orion_mdio_reset;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii",
                 dev_name(&pdev->dev));
        bus->parent = &pdev->dev;
index f418f4f20f94a0f22524a6d5c1c878c2a40f7146..d04b1c3c9b85ba8ce23e52cf3fb85b2a9b1a897d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <net/ip.h>
 #include <net/ipv6.h>
+#include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_mdio.h>
@@ -88,8 +89,9 @@
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
-#define MVNETA_SGMII_SERDES_CFG                         0x24A0
+#define MVNETA_SERDES_CFG                       0x24A0
 #define      MVNETA_SGMII_SERDES_PROTO          0x0cc7
+#define      MVNETA_RGMII_SERDES_PROTO          0x0667
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
 #define      MVNETA_GMAC_MAX_RX_SIZE_MASK        0x7ffc
 #define      MVNETA_GMAC0_PORT_ENABLE            BIT(0)
 #define MVNETA_GMAC_CTRL_2                       0x2c08
-#define      MVNETA_GMAC2_PSC_ENABLE             BIT(3)
+#define      MVNETA_GMAC2_PCS_ENABLE             BIT(3)
 #define      MVNETA_GMAC2_PORT_RGMII             BIT(4)
 #define      MVNETA_GMAC2_PORT_RESET             BIT(6)
 #define MVNETA_GMAC_STATUS                       0x2c10
@@ -508,12 +510,12 @@ struct rtnl_link_stats64 *mvneta_get_stats64(struct net_device *dev,
 
                cpu_stats = per_cpu_ptr(pp->stats, cpu);
                do {
-                       start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
                        rx_packets = cpu_stats->rx_packets;
                        rx_bytes   = cpu_stats->rx_bytes;
                        tx_packets = cpu_stats->tx_packets;
                        tx_bytes   = cpu_stats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
                stats->rx_packets += rx_packets;
                stats->rx_bytes   += rx_bytes;
@@ -710,35 +712,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp,
        mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val);
 }
 
-
-
-/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */
-static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable)
-{
-       u32  val;
-
-       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-
-       if (enable)
-               val |= MVNETA_GMAC2_PORT_RGMII;
-       else
-               val &= ~MVNETA_GMAC2_PORT_RGMII;
-
-       mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-}
-
-/* Config SGMII port */
-static void mvneta_port_sgmii_config(struct mvneta_port *pp)
-{
-       u32 val;
-
-       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
-       val |= MVNETA_GMAC2_PSC_ENABLE;
-       mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
-
-       mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
-}
-
 /* Start the Ethernet port RX and TX activity */
 static void mvneta_port_up(struct mvneta_port *pp)
 {
@@ -2756,12 +2729,15 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
        mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0);
 
        if (phy_mode == PHY_INTERFACE_MODE_SGMII)
-               mvneta_port_sgmii_config(pp);
+               mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
+       else
+               mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO);
+
+       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
 
-       mvneta_gmac_rgmii_set(pp, 1);
+       val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII;
 
        /* Cancel Port Reset */
-       val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
        val &= ~MVNETA_GMAC2_PORT_RESET;
        mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
 
@@ -2774,6 +2750,7 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
 static int mvneta_probe(struct platform_device *pdev)
 {
        const struct mbus_dram_target_info *dram_target_info;
+       struct resource *res;
        struct device_node *dn = pdev->dev.of_node;
        struct device_node *phy_node;
        u32 phy_addr;
@@ -2784,7 +2761,6 @@ static int mvneta_probe(struct platform_device *pdev)
        const char *mac_from;
        int phy_mode;
        int err;
-       int cpu;
 
        /* Our multiqueue support is not complete, so for now, only
         * allow the usage of the first RX queue
@@ -2838,23 +2814,18 @@ static int mvneta_probe(struct platform_device *pdev)
 
        clk_prepare_enable(pp->clk);
 
-       pp->base = of_iomap(dn, 0);
-       if (pp->base == NULL) {
-               err = -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pp->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pp->base)) {
+               err = PTR_ERR(pp->base);
                goto err_clk;
        }
 
        /* Alloc per-cpu stats */
-       pp->stats = alloc_percpu(struct mvneta_pcpu_stats);
+       pp->stats = netdev_alloc_pcpu_stats(struct mvneta_pcpu_stats);
        if (!pp->stats) {
                err = -ENOMEM;
-               goto err_unmap;
-       }
-
-       for_each_possible_cpu(cpu) {
-               struct mvneta_pcpu_stats *stats;
-               stats = per_cpu_ptr(pp->stats, cpu);
-               u64_stats_init(&stats->syncp);
+               goto err_clk;
        }
 
        dt_mac_addr = of_get_mac_address(dn);
@@ -2913,8 +2884,6 @@ err_deinit:
        mvneta_deinit(pp);
 err_free_stats:
        free_percpu(pp->stats);
-err_unmap:
-       iounmap(pp->base);
 err_clk:
        clk_disable_unprepare(pp->clk);
 err_free_irq:
@@ -2934,7 +2903,6 @@ static int mvneta_remove(struct platform_device *pdev)
        mvneta_deinit(pp);
        clk_disable_unprepare(pp->clk);
        free_percpu(pp->stats);
-       iounmap(pp->base);
        irq_dispose_mapping(dev->irq);
        free_netdev(dev);
 
index 5978461938699f098f7927c7d439cd9134fbc6a7..7f81ae66cc892d664fc007feaa9fd6f447baea42 100644 (file)
@@ -2845,7 +2845,7 @@ mapping_unwind:
 mapping_error:
        if (net_ratelimit())
                dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
@@ -3172,7 +3172,7 @@ static void skge_tx_done(struct net_device *dev)
                        pkts_compl++;
                        bytes_compl += e->skb->len;
 
-                       dev_kfree_skb(e->skb);
+                       dev_consume_skb_any(e->skb);
                }
        }
        netdev_completed_queue(dev, pkts_compl, bytes_compl);
index 55a37ae11440791d78e5dd69bf486cb5b4f976f3..b81106451a0a4d2d46d831d9e629d3a24212aada 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/prefetch.h>
 #include <linux/debugfs.h>
 #include <linux/mii.h>
+#include <linux/of_device.h>
+#include <linux/of_net.h>
 
 #include <asm/irq.h>
 
@@ -2000,7 +2002,7 @@ mapping_unwind:
 mapping_error:
        if (net_ratelimit())
                dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
@@ -2733,6 +2735,9 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
        unsigned int total_bytes[2] = { 0 };
        unsigned int total_packets[2] = { 0 };
 
+       if (to_do <= 0)
+               return work_done;
+
        rmb();
        do {
                struct sky2_port *sky2;
@@ -3906,19 +3911,19 @@ static struct rtnl_link_stats64 *sky2_get_stats(struct net_device *dev,
        u64 _bytes, _packets;
 
        do {
-               start = u64_stats_fetch_begin_bh(&sky2->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&sky2->rx_stats.syncp);
                _bytes = sky2->rx_stats.bytes;
                _packets = sky2->rx_stats.packets;
-       } while (u64_stats_fetch_retry_bh(&sky2->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&sky2->rx_stats.syncp, start));
 
        stats->rx_packets = _packets;
        stats->rx_bytes = _bytes;
 
        do {
-               start = u64_stats_fetch_begin_bh(&sky2->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&sky2->tx_stats.syncp);
                _bytes = sky2->tx_stats.bytes;
                _packets = sky2->tx_stats.packets;
-       } while (u64_stats_fetch_retry_bh(&sky2->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&sky2->tx_stats.syncp, start));
 
        stats->tx_packets = _packets;
        stats->tx_bytes = _bytes;
@@ -4748,6 +4753,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
 {
        struct sky2_port *sky2;
        struct net_device *dev = alloc_etherdev(sizeof(*sky2));
+       const void *iap;
 
        if (!dev)
                return NULL;
@@ -4805,8 +4811,16 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port,
 
        dev->features |= dev->hw_features;
 
-       /* read the mac address */
-       memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
+       /* try to get mac address in the following order:
+        * 1) from device tree data
+        * 2) from internal registers set by bootloader
+        */
+       iap = of_get_mac_address(hw->pdev->dev.of_node);
+       if (iap)
+               memcpy(dev->dev_addr, iap, ETH_ALEN);
+       else
+               memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8,
+                             ETH_ALEN);
 
        return dev;
 }
index 563495d8975a5399c44140f94e096f199ca1a350..1a6e1887a17174ca0318271f8ed0286cfe54adfc 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 config MLX4_EN
-       tristate "Mellanox Technologies 10Gbit Ethernet support"
+       tristate "Mellanox Technologies 1/10/40Gbit Ethernet support"
        depends on PCI
        select MLX4_CORE
        select PTP_1588_CLOCK
index 0d02fba9453657588b5f3db7b2e90e7e5410b010..78099eab767374319c7e258bfa1f0d6df4c64fa3 100644 (file)
@@ -800,16 +800,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
                                    vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
 }
 
-static int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave,
-                    struct mlx4_vhcr *vhcr,
-                    struct mlx4_cmd_mailbox *inbox,
-                    struct mlx4_cmd_mailbox *outbox,
-                    struct mlx4_cmd_info *cmd)
-{
-       return -EPERM;
-}
-
-static int MLX4_CMD_GET_OP_REQ_wrapper(struct mlx4_dev *dev, int slave,
+static int mlx4_CMD_EPERM_wrapper(struct mlx4_dev *dev, int slave,
                     struct mlx4_vhcr *vhcr,
                     struct mlx4_cmd_mailbox *inbox,
                     struct mlx4_cmd_mailbox *outbox,
@@ -963,6 +954,15 @@ static struct mlx4_cmd_info cmd_info[] = {
                .verify = NULL,
                .wrapper = NULL
        },
+       {
+               .opcode = MLX4_CMD_CONFIG_DEV,
+               .has_inbox = false,
+               .has_outbox = false,
+               .out_is_imm = false,
+               .encode_slave_id = false,
+               .verify = NULL,
+               .wrapper = mlx4_CMD_EPERM_wrapper
+       },
        {
                .opcode = MLX4_CMD_ALLOC_RES,
                .has_inbox = false,
@@ -1258,7 +1258,7 @@ static struct mlx4_cmd_info cmd_info[] = {
                .out_is_imm = false,
                .encode_slave_id = false,
                .verify = NULL,
-               .wrapper = MLX4_CMD_UPDATE_QP_wrapper
+               .wrapper = mlx4_CMD_EPERM_wrapper
        },
        {
                .opcode = MLX4_CMD_GET_OP_REQ,
@@ -1267,7 +1267,7 @@ static struct mlx4_cmd_info cmd_info[] = {
                .out_is_imm = false,
                .encode_slave_id = false,
                .verify = NULL,
-               .wrapper = MLX4_CMD_GET_OP_REQ_wrapper,
+               .wrapper = mlx4_CMD_EPERM_wrapper,
        },
        {
                .opcode = MLX4_CMD_CONF_SPECIAL_QP,
@@ -1378,7 +1378,7 @@ static struct mlx4_cmd_info cmd_info[] = {
                .out_is_imm = false,
                .encode_slave_id = false,
                .verify = NULL,
-               .wrapper = mlx4_FLOW_STEERING_IB_UC_QP_RANGE_wrapper
+               .wrapper = mlx4_CMD_EPERM_wrapper
        },
 };
 
@@ -1643,8 +1643,16 @@ static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
        int port, err;
        struct mlx4_vport_state *vp_admin;
        struct mlx4_vport_oper_state *vp_oper;
-
-       for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
+                       &priv->dev, slave);
+       int min_port = find_first_bit(actv_ports.ports,
+                                     priv->dev.caps.num_ports) + 1;
+       int max_port = min_port - 1 +
+               bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
+
+       for (port = min_port; port <= max_port; port++) {
+               if (!test_bit(port - 1, actv_ports.ports))
+                       continue;
                vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
                vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
                vp_oper->state = *vp_admin;
@@ -1685,8 +1693,17 @@ static void mlx4_master_deactivate_admin_state(struct mlx4_priv *priv, int slave
 {
        int port;
        struct mlx4_vport_oper_state *vp_oper;
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(
+                       &priv->dev, slave);
+       int min_port = find_first_bit(actv_ports.ports,
+                                     priv->dev.caps.num_ports) + 1;
+       int max_port = min_port - 1 +
+               bitmap_weight(actv_ports.ports, priv->dev.caps.num_ports);
+
 
-       for (port = 1; port <= MLX4_MAX_PORTS; port++) {
+       for (port = min_port; port <= max_port; port++) {
+               if (!test_bit(port - 1, actv_ports.ports))
+                       continue;
                vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
                if (NO_INDX != vp_oper->vlan_idx) {
                        __mlx4_unregister_vlan(&priv->dev,
@@ -2234,6 +2251,112 @@ static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
        return vf+1;
 }
 
+int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave)
+{
+       if (slave < 1 || slave > dev->num_vfs) {
+               mlx4_err(dev,
+                        "Bad slave number:%d (number of activated slaves: %lu)\n",
+                        slave, dev->num_slaves);
+               return -EINVAL;
+       }
+       return slave - 1;
+}
+
+struct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave)
+{
+       struct mlx4_active_ports actv_ports;
+       int vf;
+
+       bitmap_zero(actv_ports.ports, MLX4_MAX_PORTS);
+
+       if (slave == 0) {
+               bitmap_fill(actv_ports.ports, dev->caps.num_ports);
+               return actv_ports;
+       }
+
+       vf = mlx4_get_vf_indx(dev, slave);
+       if (vf < 0)
+               return actv_ports;
+
+       bitmap_set(actv_ports.ports, dev->dev_vfs[vf].min_port - 1,
+                  min((int)dev->dev_vfs[mlx4_get_vf_indx(dev, slave)].n_ports,
+                  dev->caps.num_ports));
+
+       return actv_ports;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_active_ports);
+
+int mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port)
+{
+       unsigned n;
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
+       unsigned m = bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+
+       if (port <= 0 || port > m)
+               return -EINVAL;
+
+       n = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+       if (port <= n)
+               port = n + 1;
+
+       return port;
+}
+EXPORT_SYMBOL_GPL(mlx4_slave_convert_port);
+
+int mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port)
+{
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
+       if (test_bit(port - 1, actv_ports.ports))
+               return port -
+                       find_first_bit(actv_ports.ports, dev->caps.num_ports);
+
+       return -1;
+}
+EXPORT_SYMBOL_GPL(mlx4_phys_to_slave_port);
+
+struct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev,
+                                                  int port)
+{
+       unsigned i;
+       struct mlx4_slaves_pport slaves_pport;
+
+       bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
+
+       if (port <= 0 || port > dev->caps.num_ports)
+               return slaves_pport;
+
+       for (i = 0; i < dev->num_vfs + 1; i++) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev, i);
+               if (test_bit(port - 1, actv_ports.ports))
+                       set_bit(i, slaves_pport.slaves);
+       }
+
+       return slaves_pport;
+}
+EXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport);
+
+struct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv(
+               struct mlx4_dev *dev,
+               const struct mlx4_active_ports *crit_ports)
+{
+       unsigned i;
+       struct mlx4_slaves_pport slaves_pport;
+
+       bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
+
+       for (i = 0; i < dev->num_vfs + 1; i++) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev, i);
+               if (bitmap_equal(crit_ports->ports, actv_ports.ports,
+                                dev->caps.num_ports))
+                       set_bit(i, slaves_pport.slaves);
+       }
+
+       return slaves_pport;
+}
+EXPORT_SYMBOL_GPL(mlx4_phys_to_slaves_pport_actv);
+
 int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2289,6 +2412,30 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
 }
 EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
 
+ /* mlx4_get_slave_default_vlan -
+ * return true if VST ( default vlan)
+ * if VST, will return vlan & qos (if not NULL)
+ */
+bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
+                                u16 *vlan, u8 *qos)
+{
+       struct mlx4_vport_oper_state *vp_oper;
+       struct mlx4_priv *priv;
+
+       priv = mlx4_priv(dev);
+       vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
+
+       if (MLX4_VGT != vp_oper->state.default_vlan) {
+               if (vlan)
+                       *vlan = vp_oper->state.default_vlan;
+               if (qos)
+                       *qos = vp_oper->state.default_qos;
+               return true;
+       }
+       return false;
+}
+EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan);
+
 int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
index abaf6bb22416232fc055f3ef8b6c414be701734d..57dda95b67d8d4325e19f03b6d01f982cfc54cb7 100644 (file)
@@ -276,6 +276,7 @@ static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
        .n_alarm        = 0,
        .n_ext_ts       = 0,
        .n_per_out      = 0,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = mlx4_en_phc_adjfreq,
        .adjtime        = mlx4_en_phc_adjtime,
index b4881b6861590c16c55644fd2752abfcf569ad8e..c95ca252187c333719fe4141225cea020909c723 100644 (file)
@@ -62,7 +62,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets)
        int has_ets_tc = 0;
 
        for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
-               if (ets->prio_tc[i] > MLX4_EN_NUM_UP) {
+               if (ets->prio_tc[i] >= MLX4_EN_NUM_UP) {
                        en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n",
                                        i, ets->prio_tc[i]);
                        return -EINVAL;
index d357bf5a46860314a4c74ae10c630bae8f61f096..0c59d4fe7e3aae56afee09b7e279601192c9e26e 100644 (file)
@@ -72,6 +72,12 @@ MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]."
 MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]."
                           " Per priority bit mask");
 
+MLX4_EN_PARM_INT(inline_thold, MAX_INLINE,
+                "Threshold for using inline data (range: 17-104, default: 104)");
+
+#define MAX_PFC_TX     0xff
+#define MAX_PFC_RX     0xff
+
 int en_print(const char *level, const struct mlx4_en_priv *priv,
             const char *format, ...)
 {
@@ -140,6 +146,7 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                params->prof[i].tx_ring_num = params->num_tx_rings_p_up *
                        MLX4_EN_NUM_UP;
                params->prof[i].rss_rings = 0;
+               params->prof[i].inline_thold = inline_thold;
        }
 
        return 0;
@@ -274,19 +281,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
        if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
                mlx4_en_init_timestamp(mdev);
 
-       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
-               if (!dev->caps.comp_pool) {
-                       mdev->profile.prof[i].rx_ring_num =
-                               rounddown_pow_of_two(max_t(int, MIN_RX_RINGS,
-                                                          min_t(int,
-                                                                dev->caps.num_comp_vectors,
-                                                                DEF_RX_RINGS)));
-               } else {
-                       mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two(
-                               min_t(int, dev->caps.comp_pool/
-                                     dev->caps.num_ports - 1 , MAX_MSIX_P_PORT - 1));
-               }
-       }
+       /* Set default number of RX rings*/
+       mlx4_en_set_num_rx_rings(mdev);
 
        /* Create our own workqueue for reset/multicast tasks
         * Note: we cannot use the shared workqueue because of deadlocks caused
@@ -336,8 +332,31 @@ static struct mlx4_interface mlx4_en_interface = {
        .protocol       = MLX4_PROT_ETH,
 };
 
+static void mlx4_en_verify_params(void)
+{
+       if (pfctx > MAX_PFC_TX) {
+               pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
+                       pfctx, MAX_PFC_TX);
+               pfctx = 0;
+       }
+
+       if (pfcrx > MAX_PFC_RX) {
+               pr_warn("mlx4_en: WARNING: illegal module parameter pfcrx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n",
+                       pfcrx, MAX_PFC_RX);
+               pfcrx = 0;
+       }
+
+       if (inline_thold < MIN_PKT_LEN || inline_thold > MAX_INLINE) {
+               pr_warn("mlx4_en: WARNING: illegal module parameter inline_thold %d - should be in range %d-%d, will be changed to default (%d)\n",
+                       inline_thold, MIN_PKT_LEN, MAX_INLINE, MAX_INLINE);
+               inline_thold = MAX_INLINE;
+       }
+}
+
 static int __init mlx4_en_init(void)
 {
+       mlx4_en_verify_params();
+
        return mlx4_register_interface(&mlx4_en_interface);
 }
 
index fad45316200aa0fbcb115e3f6b4ec56a24ca29cd..82d7eb5b79cc167c1f1a726ba4b15b1074f69ec0 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/hash.h>
 #include <net/ip.h>
 #include <net/busy_poll.h>
+#include <net/vxlan.h>
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/device.h>
@@ -603,7 +604,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
        int err = 0;
        u64 reg_id;
        int *qpn = &priv->base_qpn;
-       u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+       u64 mac = mlx4_mac_to_u64(priv->dev->dev_addr);
 
        en_dbg(DRV, priv, "Registering MAC: %pM for adding\n",
               priv->dev->dev_addr);
@@ -672,7 +673,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
        u64 mac;
 
        if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) {
-               mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
+               mac = mlx4_mac_to_u64(priv->dev->dev_addr);
                en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
                       priv->dev->dev_addr);
                mlx4_unregister_mac(dev, priv->port, mac);
@@ -685,7 +686,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
                for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
                        bucket = &priv->mac_hash[i];
                        hlist_for_each_entry_safe(entry, tmp, bucket, hlist) {
-                               mac = mlx4_en_mac_to_u64(entry->mac);
+                               mac = mlx4_mac_to_u64(entry->mac);
                                en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n",
                                       entry->mac);
                                mlx4_en_uc_steer_release(priv, entry->mac,
@@ -715,14 +716,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
        struct mlx4_en_dev *mdev = priv->mdev;
        struct mlx4_dev *dev = mdev->dev;
        int err = 0;
-       u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
+       u64 new_mac_u64 = mlx4_mac_to_u64(new_mac);
 
        if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
                struct hlist_head *bucket;
                unsigned int mac_hash;
                struct mlx4_mac_entry *entry;
                struct hlist_node *tmp;
-               u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac);
+               u64 prev_mac_u64 = mlx4_mac_to_u64(prev_mac);
 
                bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
                hlist_for_each_entry_safe(entry, tmp, bucket, hlist) {
@@ -742,6 +743,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
                                err = mlx4_en_uc_steer_add(priv, new_mac,
                                                           &qpn,
                                                           &entry->reg_id);
+                               if (err)
+                                       return err;
+                               if (priv->tunnel_reg_id) {
+                                       mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id);
+                                       priv->tunnel_reg_id = 0;
+                               }
+                               err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn,
+                                                              &priv->tunnel_reg_id);
                                return err;
                        }
                }
@@ -751,18 +760,6 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
        return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
 }
 
-u64 mlx4_en_mac_to_u64(u8 *addr)
-{
-       u64 mac = 0;
-       int i;
-
-       for (i = 0; i < ETH_ALEN; i++) {
-               mac <<= 8;
-               mac |= addr[i];
-       }
-       return mac;
-}
-
 static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv)
 {
        int err = 0;
@@ -1081,7 +1078,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
                mlx4_en_cache_mclist(dev);
                netif_addr_unlock_bh(dev);
                list_for_each_entry(mclist, &priv->mc_list, list) {
-                       mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
+                       mcast_addr = mlx4_mac_to_u64(mclist->addr);
                        mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
                                            mcast_addr, 0, MLX4_MCAST_CONFIG);
                }
@@ -1173,7 +1170,7 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
                                found = true;
 
                        if (!found) {
-                               mac = mlx4_en_mac_to_u64(entry->mac);
+                               mac = mlx4_mac_to_u64(entry->mac);
                                mlx4_en_uc_steer_release(priv, entry->mac,
                                                         priv->base_qpn,
                                                         entry->reg_id);
@@ -1216,7 +1213,7 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
                                priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
                                break;
                        }
-                       mac = mlx4_en_mac_to_u64(ha->addr);
+                       mac = mlx4_mac_to_u64(ha->addr);
                        memcpy(entry->mac, ha->addr, ETH_ALEN);
                        err = mlx4_register_mac(mdev->dev, priv->port, mac);
                        if (err < 0) {
@@ -1669,7 +1666,7 @@ int mlx4_en_start_port(struct net_device *dev)
        }
 
        if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
-               err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC);
+               err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1);
                if (err) {
                        en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n",
                               err);
@@ -1701,6 +1698,8 @@ int mlx4_en_start_port(struct net_device *dev)
 
        mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
 
+       if (priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)
+               vxlan_get_rx_port(dev);
        priv->port_up = true;
        netif_tx_start_all_queues(dev);
        netif_device_attach(dev);
@@ -1792,6 +1791,8 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
                mc_list[5] = priv->port;
                mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
                                      mc_list, MLX4_PROT_ETH, mclist->reg_id);
+               if (mclist->tunnel_reg_id)
+                       mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id);
        }
        mlx4_en_clear_list(dev);
        list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
@@ -2206,7 +2207,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
 {
        struct mlx4_en_priv *en_priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = en_priv->mdev;
-       u64 mac_u64 = mlx4_en_mac_to_u64(mac);
+       u64 mac_u64 = mlx4_mac_to_u64(mac);
 
        if (!is_valid_ether_addr(mac))
                return -EINVAL;
@@ -2266,6 +2267,81 @@ static int mlx4_en_get_phys_port_id(struct net_device *dev,
        return 0;
 }
 
+static void mlx4_en_add_vxlan_offloads(struct work_struct *work)
+{
+       int ret;
+       struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+                                                vxlan_add_task);
+
+       ret = mlx4_config_vxlan_port(priv->mdev->dev, priv->vxlan_port);
+       if (ret)
+               goto out;
+
+       ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
+                                 VXLAN_STEER_BY_OUTER_MAC, 1);
+out:
+       if (ret)
+               en_err(priv, "failed setting L2 tunnel configuration ret %d\n", ret);
+}
+
+static void mlx4_en_del_vxlan_offloads(struct work_struct *work)
+{
+       int ret;
+       struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
+                                                vxlan_del_task);
+
+       ret = mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port,
+                                 VXLAN_STEER_BY_OUTER_MAC, 0);
+       if (ret)
+               en_err(priv, "failed setting L2 tunnel configuration ret %d\n", ret);
+
+       priv->vxlan_port = 0;
+}
+
+static void mlx4_en_add_vxlan_port(struct  net_device *dev,
+                                  sa_family_t sa_family, __be16 port)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       __be16 current_port;
+
+       if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS))
+               return;
+
+       if (sa_family == AF_INET6)
+               return;
+
+       current_port = priv->vxlan_port;
+       if (current_port && current_port != port) {
+               en_warn(priv, "vxlan port %d configured, can't add port %d\n",
+                       ntohs(current_port), ntohs(port));
+               return;
+       }
+
+       priv->vxlan_port = port;
+       queue_work(priv->mdev->workqueue, &priv->vxlan_add_task);
+}
+
+static void mlx4_en_del_vxlan_port(struct  net_device *dev,
+                                  sa_family_t sa_family, __be16 port)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       __be16 current_port;
+
+       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+               return;
+
+       if (sa_family == AF_INET6)
+               return;
+
+       current_port = priv->vxlan_port;
+       if (current_port != port) {
+               en_dbg(DRV, priv, "vxlan port %d isn't configured, ignoring\n", ntohs(port));
+               return;
+       }
+
+       queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);
+}
+
 static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_open               = mlx4_en_open,
        .ndo_stop               = mlx4_en_close,
@@ -2292,6 +2368,8 @@ static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_busy_poll          = mlx4_en_low_latency_recv,
 #endif
        .ndo_get_phys_port_id   = mlx4_en_get_phys_port_id,
+       .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
+       .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
 };
 
 static const struct net_device_ops mlx4_netdev_ops_master = {
@@ -2341,7 +2419,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        netif_set_real_num_rx_queues(dev, prof->rx_ring_num);
 
        SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
-       dev->dev_id =  port - 1;
+       dev->dev_port = port - 1;
 
        /*
         * Initialize driver private data
@@ -2383,6 +2461,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
        INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
        INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
+       INIT_WORK(&priv->vxlan_add_task, mlx4_en_add_vxlan_offloads);
+       INIT_WORK(&priv->vxlan_del_task, mlx4_en_del_vxlan_offloads);
 #ifdef CONFIG_MLX4_EN_DCB
        if (!mlx4_is_slave(priv->mdev->dev)) {
                if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) {
@@ -2407,7 +2487,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                if (mlx4_is_slave(priv->mdev->dev)) {
                        eth_hw_addr_random(dev);
                        en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr);
-                       mac_u64 = mlx4_en_mac_to_u64(dev->dev_addr);
+                       mac_u64 = mlx4_mac_to_u64(dev->dev_addr);
                        mdev->dev->caps.def_mac[priv->port] = mac_u64;
                } else {
                        en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n",
@@ -2516,7 +2596,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        }
 
        if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) {
-               err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC);
+               err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1);
                if (err) {
                        en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n",
                               err);
index dae1a1f4ae55e38287e6bcb5ff1bc5cb73435808..c2cfb05e72905cc6961ddc773547e1d09ae26bbf 100644 (file)
@@ -148,10 +148,16 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset)
        stats->tx_packets = 0;
        stats->tx_bytes = 0;
        priv->port_stats.tx_chksum_offload = 0;
+       priv->port_stats.queue_stopped = 0;
+       priv->port_stats.wake_queue = 0;
+
        for (i = 0; i < priv->tx_ring_num; i++) {
                stats->tx_packets += priv->tx_ring[i]->packets;
                stats->tx_bytes += priv->tx_ring[i]->bytes;
                priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum;
+               priv->port_stats.queue_stopped +=
+                       priv->tx_ring[i]->queue_stopped;
+               priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue;
        }
 
        stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) +
index 890922c1c8eea11d4d737d81aefffde4e157e3a2..ba049ae88749dac986a0712d281bbd649152acdd 100644 (file)
@@ -318,6 +318,31 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv,
        }
 }
 
+void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev)
+{
+       int i;
+       int num_of_eqs;
+       int num_rx_rings;
+       struct mlx4_dev *dev = mdev->dev;
+
+       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+               if (!dev->caps.comp_pool)
+                       num_of_eqs = max_t(int, MIN_RX_RINGS,
+                                          min_t(int,
+                                                dev->caps.num_comp_vectors,
+                                                DEF_RX_RINGS));
+               else
+                       num_of_eqs = min_t(int, MAX_MSIX_P_PORT,
+                                          dev->caps.comp_pool/
+                                          dev->caps.num_ports) - 1;
+
+               num_rx_rings = min_t(int, num_of_eqs,
+                                    netif_get_num_default_rss_queues());
+               mdev->profile.prof[i].rx_ring_num =
+                       rounddown_pow_of_two(num_rx_rings);
+       }
+}
+
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
                           struct mlx4_en_rx_ring **pring,
                           u32 size, u16 stride, int node)
@@ -636,6 +661,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
        if (!priv->port_up)
                return 0;
 
+       if (budget <= 0)
+               return polled;
+
        /* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
         * descriptor offset can be deduced from the CQE index instead of
         * reading 'cqe->index' */
index c11d063473e5f9aaa162aacd32b4cac386d53464..03e5f6ac67e7660dbc68c6fe69e5123247588bf0 100644 (file)
@@ -129,8 +129,10 @@ static int mlx4_en_test_speed(struct mlx4_en_priv *priv)
        if (mlx4_en_QUERY_PORT(priv->mdev, priv->port))
                return -ENOMEM;
 
-       /* The device currently only supports 10G speed */
-       if (priv->port_state.link_speed != SPEED_10000)
+       /* The device supports 1G, 10G and 40G speeds */
+       if (priv->port_state.link_speed != 1000 &&
+           priv->port_state.link_speed != 10000 &&
+           priv->port_state.link_speed != 40000)
                return priv->port_state.link_speed;
        return 0;
 }
index 8e8a7eb43a2ce861249d678e1f1053be9b7b0ac5..dd1f6d346459808dfe95690ce5fcf0af31e99231 100644 (file)
 
 #include "mlx4_en.h"
 
-enum {
-       MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */
-       MAX_BF = 256,
-};
-
-static int inline_thold __read_mostly = MAX_INLINE;
-
-module_param_named(inline_thold, inline_thold, int, 0444);
-MODULE_PARM_DESC(inline_thold, "threshold for using inline data");
-
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
                           struct mlx4_en_tx_ring **pring, int qpn, u32 size,
                           u16 stride, int node, int queue_index)
@@ -75,8 +65,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
        ring->size = size;
        ring->size_mask = size - 1;
        ring->stride = stride;
-
-       inline_thold = min(inline_thold, MAX_INLINE);
+       ring->inline_thold = priv->prof->inline_thold;
 
        tmp = size * sizeof(struct mlx4_en_tx_info);
        ring->tx_info = vmalloc_node(tmp, node);
@@ -325,7 +314,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv,
                        }
                }
        }
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return tx_info->nr_txbb;
 }
 
@@ -456,7 +445,7 @@ static int mlx4_en_process_tx_cq(struct net_device *dev,
         */
        if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) {
                netif_tx_wake_queue(ring->tx_queue);
-               priv->port_stats.wake_queue++;
+               ring->wake_queue++;
        }
        return done;
 }
@@ -520,7 +509,7 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv,
        return ring->buf + index * TXBB_SIZE;
 }
 
-static int is_inline(struct sk_buff *skb, void **pfrag)
+static int is_inline(int inline_thold, struct sk_buff *skb, void **pfrag)
 {
        void *ptr;
 
@@ -580,7 +569,7 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev,
                }
        } else {
                *lso_header_size = 0;
-               if (!is_inline(skb, NULL))
+               if (!is_inline(priv->prof->inline_thold, skb, NULL))
                        real_size = CTRL_SIZE + (skb_shinfo(skb)->nr_frags + 1) * DS_SIZE;
                else
                        real_size = inline_size(skb);
@@ -596,7 +585,13 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
        int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl;
 
        if (skb->len <= spc) {
-               inl->byte_count = cpu_to_be32(1 << 31 | skb->len);
+               if (likely(skb->len >= MIN_PKT_LEN)) {
+                       inl->byte_count = cpu_to_be32(1 << 31 | skb->len);
+               } else {
+                       inl->byte_count = cpu_to_be32(1 << 31 | MIN_PKT_LEN);
+                       memset(((void *)(inl + 1)) + skb->len, 0,
+                              MIN_PKT_LEN - skb->len);
+               }
                skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb));
                if (skb_shinfo(skb)->nr_frags)
                        memcpy(((void *)(inl + 1)) + skb_headlen(skb), fragptr,
@@ -629,7 +624,7 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk
 }
 
 u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
-                        void *accel_priv)
+                        void *accel_priv, select_queue_fallback_t fallback)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        u16 rings_p_up = priv->num_tx_rings_p_up;
@@ -641,7 +636,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
        if (vlan_tx_tag_present(skb))
                up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT;
 
-       return __netdev_pick_tx(dev, skb) % rings_p_up + up * rings_p_up;
+       return fallback(dev, skb) % rings_p_up + up * rings_p_up;
 }
 
 static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt)
@@ -696,7 +691,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
                /* every full Tx ring stops queue */
                netif_tx_stop_queue(ring->tx_queue);
-               priv->port_stats.queue_stopped++;
+               ring->queue_stopped++;
 
                /* If queue was emptied after the if, and before the
                 * stop_queue - need to wake the queue, or else it will remain
@@ -709,7 +704,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                if (unlikely(((int)(ring->prod - ring->cons)) <=
                             ring->size - HEADROOM - MAX_DESC_TXBBS)) {
                        netif_tx_wake_queue(ring->tx_queue);
-                       priv->port_stats.wake_queue++;
+                       ring->wake_queue++;
                } else {
                        return NETDEV_TX_BUSY;
                }
@@ -747,11 +742,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_info->data_offset = (void *)data - (void *)tx_desc;
 
        tx_info->linear = (lso_header_size < skb_headlen(skb) &&
-                          !is_inline(skb, NULL)) ? 1 : 0;
+                          !is_inline(ring->inline_thold, skb, NULL)) ? 1 : 0;
 
        data += skb_shinfo(skb)->nr_frags + tx_info->linear - 1;
 
-       if (is_inline(skb, &fragptr)) {
+       if (is_inline(ring->inline_thold, skb, &fragptr)) {
                tx_info->inl = 1;
        } else {
                /* Map fragments */
@@ -881,7 +876,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
        skb_tx_timestamp(skb);
 
        if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tx_tag_present(skb)) {
-               *(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
+               tx_desc->ctrl.bf_qpn |= cpu_to_be32(ring->doorbell_qpn);
+
                op_own |= htonl((bf_index & 0xffff) << 8);
                /* Ensure new descirptor hits memory
                * before setting ownership of this descriptor to HW */
index 8992b38578d5898ecaa9de19ee62e5079b1e8010..d501a2b0fb79f18e560fd0cd067aa4c19b83b447 100644 (file)
@@ -271,7 +271,10 @@ enum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave,
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state;
-       if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS) {
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
+
+       if (slave >= dev->num_slaves || port > dev->caps.num_ports ||
+           port <= 0 || !test_bit(port - 1, actv_ports.ports)) {
                pr_err("%s: Error: asking for slave:%d, port:%d\n",
                       __func__, slave, port);
                return SLAVE_PORT_DOWN;
@@ -285,8 +288,10 @@ static int mlx4_set_slave_port_state(struct mlx4_dev *dev, int slave, u8 port,
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state;
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
 
-       if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) {
+       if (slave >= dev->num_slaves || port > dev->caps.num_ports ||
+           port <= 0 || !test_bit(port - 1, actv_ports.ports)) {
                pr_err("%s: Error: asking for slave:%d, port:%d\n",
                       __func__, slave, port);
                return -1;
@@ -300,9 +305,13 @@ static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event)
 {
        int i;
        enum slave_port_gen_event gen_event;
+       struct mlx4_slaves_pport slaves_pport = mlx4_phys_to_slaves_pport(dev,
+                                                                         port);
 
-       for (i = 0; i < dev->num_slaves; i++)
-               set_and_calc_slave_port_state(dev, i, port, event, &gen_event);
+       for (i = 0; i < dev->num_vfs + 1; i++)
+               if (test_bit(i, slaves_pport.slaves))
+                       set_and_calc_slave_port_state(dev, i, port,
+                                                     event, &gen_event);
 }
 /**************************************************************************
        The function get as input the new event to that port,
@@ -321,12 +330,14 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave,
        struct mlx4_slave_state *ctx = NULL;
        unsigned long flags;
        int ret = -1;
+       struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave);
        enum slave_port_state cur_state =
                mlx4_get_slave_port_state(dev, slave, port);
 
        *gen_event = SLAVE_PORT_GEN_EVENT_NONE;
 
-       if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) {
+       if (slave >= dev->num_slaves || port > dev->caps.num_ports ||
+           port <= 0 || !test_bit(port - 1, actv_ports.ports)) {
                pr_err("%s: Error: asking for slave:%d, port:%d\n",
                       __func__, slave, port);
                return ret;
@@ -542,15 +553,19 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                       be64_to_cpu(eqe->event.cmd.out_param));
                        break;
 
-               case MLX4_EVENT_TYPE_PORT_CHANGE:
+               case MLX4_EVENT_TYPE_PORT_CHANGE: {
+                       struct mlx4_slaves_pport slaves_port;
                        port = be32_to_cpu(eqe->event.port_change.port) >> 28;
+                       slaves_port = mlx4_phys_to_slaves_pport(dev, port);
                        if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
                                mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
                                                    port);
                                mlx4_priv(dev)->sense.do_sense_port[port] = 1;
                                if (!mlx4_is_master(dev))
                                        break;
-                               for (i = 0; i < dev->num_slaves; i++) {
+                               for (i = 0; i < dev->num_vfs + 1; i++) {
+                                       if (!test_bit(i, slaves_port.slaves))
+                                               continue;
                                        if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) {
                                                if (i == mlx4_master_func_num(dev))
                                                        continue;
@@ -558,8 +573,13 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                                         " to slave: %d, port:%d\n",
                                                         __func__, i, port);
                                                s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
-                                               if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state)
+                                               if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
+                                                       eqe->event.port_change.port =
+                                                               cpu_to_be32(
+                                                               (be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
+                                                               | (mlx4_phys_to_slave_port(dev, i, port) << 28));
                                                        mlx4_slave_event(dev, i, eqe);
+                                               }
                                        } else {  /* IB port */
                                                set_and_calc_slave_port_state(dev, i, port,
                                                                              MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN,
@@ -580,12 +600,19 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                if (!mlx4_is_master(dev))
                                        break;
                                if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
-                                       for (i = 0; i < dev->num_slaves; i++) {
+                                       for (i = 0; i < dev->num_vfs + 1; i++) {
+                                               if (!test_bit(i, slaves_port.slaves))
+                                                       continue;
                                                if (i == mlx4_master_func_num(dev))
                                                        continue;
                                                s_info = &priv->mfunc.master.vf_oper[slave].vport[port].state;
-                                               if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state)
+                                               if (IFLA_VF_LINK_STATE_AUTO == s_info->link_state) {
+                                                       eqe->event.port_change.port =
+                                                               cpu_to_be32(
+                                                               (be32_to_cpu(eqe->event.port_change.port) & 0xFFFFFFF)
+                                                               | (mlx4_phys_to_slave_port(dev, i, port) << 28));
                                                        mlx4_slave_event(dev, i, eqe);
+                                               }
                                        }
                                else /* IB port */
                                        /* port-up event will be sent to a slave when the
@@ -594,6 +621,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
                                        set_all_slave_state(dev, port, MLX4_DEV_EVENT_PORT_UP);
                        }
                        break;
+               }
 
                case MLX4_EVENT_TYPE_CQ_ERROR:
                        mlx4_warn(dev, "CQ %s on CQN %06x\n",
index 91b69ff4b4a20f8f2bd2f6c9405cf6ab60af7f6a..d16a4d11890342167a2f2c8605e3b5e4e9d25198 100644 (file)
@@ -129,13 +129,14 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
                [0] = "RSS support",
                [1] = "RSS Toeplitz Hash Function support",
                [2] = "RSS XOR Hash Function support",
-               [3] = "Device manage flow steering support",
+               [3] = "Device managed flow steering support",
                [4] = "Automatic MAC reassignment support",
                [5] = "Time stamping support",
                [6] = "VST (control vlan insertion/stripping) support",
                [7] = "FSM (MAC anti-spoofing) support",
                [8] = "Dynamic QP updates support",
-               [9] = "TCP/IP offloads/flow-steering for VXLAN support"
+               [9] = "Device managed flow steering IPoIB support",
+               [10] = "TCP/IP offloads/flow-steering for VXLAN support"
        };
        int i;
 
@@ -224,13 +225,25 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
 #define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80
 
        if (vhcr->op_modifier == 1) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev, slave);
+               int converted_port = mlx4_slave_convert_port(
+                               dev, slave, vhcr->in_modifier);
+
+               if (converted_port < 0)
+                       return -EINVAL;
+
+               vhcr->in_modifier = converted_port;
                /* Set nic_info bit to mark new fields support */
                field  = QUERY_FUNC_CAP_FLAGS1_NIC_INFO;
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS1_OFFSET);
 
-               field = vhcr->in_modifier; /* phys-port = logical-port */
+               /* phys-port = logical-port */
+               field = vhcr->in_modifier -
+                       find_first_bit(actv_ports.ports, dev->caps.num_ports);
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_PHYS_PORT_OFFSET);
 
+               field = vhcr->in_modifier;
                /* size is now the QP number */
                size = dev->phys_caps.base_tunnel_sqpn + 8 * slave + field - 1;
                MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP0_TUNNEL);
@@ -248,12 +261,16 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
                         QUERY_FUNC_CAP_PHYS_PORT_ID);
 
        } else if (vhcr->op_modifier == 0) {
+               struct mlx4_active_ports actv_ports =
+                       mlx4_get_active_ports(dev, slave);
                /* enable rdma and ethernet interfaces, and new quota locations */
                field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
                         QUERY_FUNC_CAP_FLAG_QUOTAS);
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
 
-               field = dev->caps.num_ports;
+               field = min(
+                       bitmap_weight(actv_ports.ports, dev->caps.num_ports),
+                       dev->caps.num_ports);
                MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_NUM_PORTS_OFFSET);
 
                size = dev->caps.function_caps; /* set PF behaviours */
@@ -839,6 +856,10 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        int     err = 0;
        u8      field;
        u32     bmme_flags;
+       int     real_port;
+       int     slave_port;
+       int     first_port;
+       struct mlx4_active_ports actv_ports;
 
        err = mlx4_cmd_box(dev, 0, outbox->dma, 0, 0, MLX4_CMD_QUERY_DEV_CAP,
                           MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
@@ -851,15 +872,33 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_GET(flags, outbox->buf, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
        flags |= MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV;
        flags &= ~MLX4_DEV_CAP_FLAG_MEM_WINDOW;
+       actv_ports = mlx4_get_active_ports(dev, slave);
+       first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports);
+       for (slave_port = 0, real_port = first_port;
+            real_port < first_port +
+            bitmap_weight(actv_ports.ports, dev->caps.num_ports);
+            ++real_port, ++slave_port) {
+               if (flags & (MLX4_DEV_CAP_FLAG_WOL_PORT1 << real_port))
+                       flags |= MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port;
+               else
+                       flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
+       }
+       for (; slave_port < dev->caps.num_ports; ++slave_port)
+               flags &= ~(MLX4_DEV_CAP_FLAG_WOL_PORT1 << slave_port);
        MLX4_PUT(outbox->buf, flags, QUERY_DEV_CAP_EXT_FLAGS_OFFSET);
 
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VL_PORT_OFFSET);
+       field &= ~0x0F;
+       field |= bitmap_weight(actv_ports.ports, dev->caps.num_ports) & 0x0F;
+       MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VL_PORT_OFFSET);
+
        /* For guests, disable timestamp */
        MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
        field &= 0x7f;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_CQ_TS_SUPPORT_OFFSET);
 
        /* For guests, disable vxlan tunneling */
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_VXLAN);
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_VXLAN);
        field &= 0xf7;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_VXLAN);
 
@@ -869,7 +908,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
 
        /* For guests, disable mw type 2 */
-       MLX4_GET(bmme_flags, outbox, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+       MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
        bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
        MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
 
@@ -883,7 +922,7 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
        }
 
        /* turn off ipoib managed steering for guests */
-       MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
+       MLX4_GET(field, outbox->buf, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
        field &= ~0x80;
        MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET);
 
@@ -902,12 +941,20 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
        u16 short_field;
        int err;
        int admin_link_state;
+       int port = mlx4_slave_convert_port(dev, slave,
+                                          vhcr->in_modifier & 0xFF);
 
 #define MLX4_VF_PORT_NO_LINK_SENSE_MASK        0xE0
 #define MLX4_PORT_LINK_UP_MASK         0x80
 #define QUERY_PORT_CUR_MAX_PKEY_OFFSET 0x0c
 #define QUERY_PORT_CUR_MAX_GID_OFFSET  0x0e
 
+       if (port < 0)
+               return -EINVAL;
+
+       vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
+                           (port & 0xFF);
+
        err = mlx4_cmd_box(dev, 0, outbox->dma, vhcr->in_modifier, 0,
                           MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B,
                           MLX4_CMD_NATIVE);
@@ -934,7 +981,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
                MLX4_PUT(outbox->buf, port_type,
                         QUERY_PORT_SUPPORTED_TYPE_OFFSET);
 
-               short_field = 1; /* slave max gids */
+               if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH)
+                       short_field = mlx4_get_slave_num_gids(dev, slave, port);
+               else
+                       short_field = 1; /* slave max gids */
                MLX4_PUT(outbox->buf, short_field,
                         QUERY_PORT_CUR_MAX_GID_OFFSET);
 
@@ -1584,9 +1634,12 @@ int mlx4_INIT_PORT_wrapper(struct mlx4_dev *dev, int slave,
                           struct mlx4_cmd_info *cmd)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int port = vhcr->in_modifier;
+       int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
        int err;
 
+       if (port < 0)
+               return -EINVAL;
+
        if (priv->mfunc.master.slave_state[slave].init_port_mask & (1 << port))
                return 0;
 
@@ -1676,9 +1729,12 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
                            struct mlx4_cmd_info *cmd)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
-       int port = vhcr->in_modifier;
+       int port = mlx4_slave_convert_port(dev, slave, vhcr->in_modifier);
        int err;
 
+       if (port < 0)
+               return -EINVAL;
+
        if (!(priv->mfunc.master.slave_state[slave].init_port_mask &
            (1 << port)))
                return 0;
@@ -1723,6 +1779,46 @@ int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
                        MLX4_CMD_NATIVE);
 }
 
+struct mlx4_config_dev {
+       __be32  update_flags;
+       __be32  rsdv1[3];
+       __be16  vxlan_udp_dport;
+       __be16  rsvd2;
+};
+
+#define MLX4_VXLAN_UDP_DPORT (1 << 0)
+
+static int mlx4_CONFIG_DEV(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
+{
+       int err;
+       struct mlx4_cmd_mailbox *mailbox;
+
+       mailbox = mlx4_alloc_cmd_mailbox(dev);
+       if (IS_ERR(mailbox))
+               return PTR_ERR(mailbox);
+
+       memcpy(mailbox->buf, config_dev, sizeof(*config_dev));
+
+       err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_CONFIG_DEV,
+                      MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+
+       mlx4_free_cmd_mailbox(dev, mailbox);
+       return err;
+}
+
+int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
+{
+       struct mlx4_config_dev config_dev;
+
+       memset(&config_dev, 0, sizeof(config_dev));
+       config_dev.update_flags    = cpu_to_be32(MLX4_VXLAN_UDP_DPORT);
+       config_dev.vxlan_udp_dport = udp_port;
+
+       return mlx4_CONFIG_DEV(dev, &config_dev);
+}
+EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
+
+
 int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
 {
        int ret = mlx4_cmd_imm(dev, icm_size, aux_pages, 0, 0,
@@ -1890,7 +1986,8 @@ void mlx4_opreq_action(struct work_struct *work)
                        err = EINVAL;
                        break;
                }
-               err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16),
+               err = mlx4_cmd(dev, 0, ((u32) err |
+                                       (__force u32)cpu_to_be32(token) << 16),
                               1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A,
                               MLX4_CMD_NATIVE);
                if (err) {
index d711158b0d4b1ab59bb3d1cf8973e8d4936ce853..f0ae95f66cebe27bd306d64001cc516ff41b4554 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/slab.h>
 #include <linux/io-mapping.h>
 #include <linux/delay.h>
-#include <linux/netdevice.h>
 #include <linux/kmod.h>
 
 #include <linux/mlx4/device.h>
@@ -78,13 +77,17 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
 #endif /* CONFIG_PCI_MSI */
 
-static int num_vfs;
-module_param(num_vfs, int, 0444);
-MODULE_PARM_DESC(num_vfs, "enable #num_vfs functions if num_vfs > 0");
+static uint8_t num_vfs[3] = {0, 0, 0};
+static int num_vfs_argc = 3;
+module_param_array(num_vfs, byte , &num_vfs_argc, 0444);
+MODULE_PARM_DESC(num_vfs, "enable #num_vfs functions if num_vfs > 0\n"
+                         "num_vfs=port1,port2,port1+2");
 
-static int probe_vf;
-module_param(probe_vf, int, 0644);
-MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)");
+static uint8_t probe_vf[3] = {0, 0, 0};
+static int probe_vfs_argc = 3;
+module_param_array(probe_vf, byte, &probe_vfs_argc, 0444);
+MODULE_PARM_DESC(probe_vf, "number of vfs to probe by pf driver (num_vfs > 0)\n"
+                          "probe_vf=port1,port2,port1+2");
 
 int mlx4_log_num_mgm_entry_size = MLX4_DEFAULT_MGM_LOG_ENTRY_SIZE;
 module_param_named(log_num_mgm_entry_size,
@@ -150,6 +153,8 @@ struct mlx4_port_config {
        struct pci_dev *pdev;
 };
 
+static atomic_t pf_loading = ATOMIC_INIT(0);
+
 int mlx4_check_port_params(struct mlx4_dev *dev,
                           enum mlx4_port_type *port_type)
 {
@@ -749,7 +754,7 @@ static void mlx4_request_modules(struct mlx4_dev *dev)
                        has_eth_port = true;
        }
 
-       if (has_ib_port)
+       if (has_ib_port || (dev->caps.flags & MLX4_DEV_CAP_FLAG_IBOE))
                request_module_nowait(IB_DRV_NAME);
        if (has_eth_port)
                request_module_nowait(EN_DRV_NAME);
@@ -1407,6 +1412,11 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
        u32 slave_read;
        u32 cmd_channel_ver;
 
+       if (atomic_read(&pf_loading)) {
+               mlx4_warn(dev, "PF is not ready. Deferring probe\n");
+               return -EPROBE_DEFER;
+       }
+
        mutex_lock(&priv->cmd.slave_cmd_mutex);
        priv->cmd.max_cmds = 1;
        mlx4_warn(dev, "Sending reset\n");
@@ -1463,7 +1473,11 @@ static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev)
        int i;
 
        for (i = 1; i <= dev->caps.num_ports; i++) {
-               dev->caps.gid_table_len[i] = 1;
+               if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH)
+                       dev->caps.gid_table_len[i] =
+                               mlx4_get_slave_num_gids(dev, 0, i);
+               else
+                       dev->caps.gid_table_len[i] = 1;
                dev->caps.pkey_table_len[i] =
                        dev->phys_caps.pkey_phys_table_len[i] - 1;
        }
@@ -1488,7 +1502,7 @@ static void choose_steering_mode(struct mlx4_dev *dev,
        if (mlx4_log_num_mgm_entry_size == -1 &&
            dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN &&
            (!mlx4_is_mfunc(dev) ||
-            (dev_cap->fs_max_num_qp_per_entry >= (num_vfs + 1))) &&
+            (dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) &&
            choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >=
                MLX4_MIN_MGM_LOG_ENTRY_SIZE) {
                dev->oper_log_mgm_entry_size =
@@ -1974,9 +1988,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct msix_entry *entries;
        int nreq = min_t(int, dev->caps.num_ports *
-                        min_t(int, netif_get_num_default_rss_queues() + 1,
+                        min_t(int, num_online_cpus() + 1,
                               MAX_MSIX_P_PORT) + MSIX_LEGACY_SZ, MAX_MSIX);
-       int err;
        int i;
 
        if (msi_x) {
@@ -1990,23 +2003,13 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
                for (i = 0; i < nreq; ++i)
                        entries[i].entry = i;
 
-       retry:
-               err = pci_enable_msix(dev->pdev, entries, nreq);
-               if (err) {
-                       /* Try again if at least 2 vectors are available */
-                       if (err > 1) {
-                               mlx4_info(dev, "Requested %d vectors, "
-                                         "but only %d MSI-X vectors available, "
-                                         "trying again\n", nreq, err);
-                               nreq = err;
-                               goto retry;
-                       }
+               nreq = pci_enable_msix_range(dev->pdev, entries, 2, nreq);
+
+               if (nreq < 0) {
                        kfree(entries);
                        goto no_msi;
-               }
-
-               if (nreq <
-                   MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) {
+               } else if (nreq < MSIX_LEGACY_SZ +
+                                 dev->caps.num_ports * MIN_MSIX_P_PORT) {
                        /*Working in legacy mode , all EQ's shared*/
                        dev->caps.comp_pool           = 0;
                        dev->caps.num_comp_vectors = nreq - 1;
@@ -2194,6 +2197,13 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
        struct mlx4_dev *dev;
        int err;
        int port;
+       int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0};
+       int prb_vf[MLX4_MAX_PORTS + 1] = {0, 0, 0};
+       const int param_map[MLX4_MAX_PORTS + 1][MLX4_MAX_PORTS + 1] = {
+               {2, 0, 0}, {0, 1, 2}, {0, 1, 2} };
+       unsigned total_vfs = 0;
+       int sriov_initialized = 0;
+       unsigned int i;
 
        pr_info(DRV_NAME ": Initializing %s\n", pci_name(pdev));
 
@@ -2208,17 +2218,40 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
         * per port, we must limit the number of VFs to 63 (since their are
         * 128 MACs)
         */
-       if (num_vfs >= MLX4_MAX_NUM_VF) {
+       for (i = 0; i < sizeof(nvfs)/sizeof(nvfs[0]) && i < num_vfs_argc;
+            total_vfs += nvfs[param_map[num_vfs_argc - 1][i]], i++) {
+               nvfs[param_map[num_vfs_argc - 1][i]] = num_vfs[i];
+               if (nvfs[i] < 0) {
+                       dev_err(&pdev->dev, "num_vfs module parameter cannot be negative\n");
+                       return -EINVAL;
+               }
+       }
+       for (i = 0; i < sizeof(prb_vf)/sizeof(prb_vf[0]) && i < probe_vfs_argc;
+            i++) {
+               prb_vf[param_map[probe_vfs_argc - 1][i]] = probe_vf[i];
+               if (prb_vf[i] < 0 || prb_vf[i] > nvfs[i]) {
+                       dev_err(&pdev->dev, "probe_vf module parameter cannot be negative or greater than num_vfs\n");
+                       return -EINVAL;
+               }
+       }
+       if (total_vfs >= MLX4_MAX_NUM_VF) {
                dev_err(&pdev->dev,
                        "Requested more VF's (%d) than allowed (%d)\n",
-                       num_vfs, MLX4_MAX_NUM_VF - 1);
+                       total_vfs, MLX4_MAX_NUM_VF - 1);
                return -EINVAL;
        }
 
-       if (num_vfs < 0) {
-               pr_err("num_vfs module parameter cannot be negative\n");
-               return -EINVAL;
+       for (i = 0; i < MLX4_MAX_PORTS; i++) {
+               if (nvfs[i] + nvfs[2] >= MLX4_MAX_NUM_VF_P_PORT) {
+                       dev_err(&pdev->dev,
+                               "Requested more VF's (%d) for port (%d) than allowed (%d)\n",
+                               nvfs[i] + nvfs[2], i + 1,
+                               MLX4_MAX_NUM_VF_P_PORT - 1);
+                       return -EINVAL;
+               }
        }
+
+
        /*
         * Check for BARs.
         */
@@ -2293,11 +2326,23 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
        if (pci_dev_data & MLX4_PCI_DEV_IS_VF) {
                /* When acting as pf, we normally skip vfs unless explicitly
                 * requested to probe them. */
-               if (num_vfs && extended_func_num(pdev) > probe_vf) {
-                       mlx4_warn(dev, "Skipping virtual function:%d\n",
-                                               extended_func_num(pdev));
-                       err = -ENODEV;
-                       goto err_free_dev;
+               if (total_vfs) {
+                       unsigned vfs_offset = 0;
+                       for (i = 0; i < sizeof(nvfs)/sizeof(nvfs[0]) &&
+                            vfs_offset + nvfs[i] < extended_func_num(pdev);
+                            vfs_offset += nvfs[i], i++)
+                               ;
+                       if (i == sizeof(nvfs)/sizeof(nvfs[0])) {
+                               err = -ENODEV;
+                               goto err_free_dev;
+                       }
+                       if ((extended_func_num(pdev) - vfs_offset)
+                           > prb_vf[i]) {
+                               mlx4_warn(dev, "Skipping virtual function:%d\n",
+                                         extended_func_num(pdev));
+                               err = -ENODEV;
+                               goto err_free_dev;
+                       }
                }
                mlx4_warn(dev, "Detected virtual function - running in slave mode\n");
                dev->flags |= MLX4_FLAG_SLAVE;
@@ -2317,18 +2362,30 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data)
                        }
                }
 
-               if (num_vfs) {
-                       mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", num_vfs);
-                       err = pci_enable_sriov(pdev, num_vfs);
-                       if (err) {
-                               mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
-                                        err);
+               if (total_vfs) {
+                       mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n",
+                                 total_vfs);
+                       dev->dev_vfs = kzalloc(
+                                       total_vfs * sizeof(*dev->dev_vfs),
+                                       GFP_KERNEL);
+                       if (NULL == dev->dev_vfs) {
+                               mlx4_err(dev, "Failed to allocate memory for VFs\n");
                                err = 0;
                        } else {
-                               mlx4_warn(dev, "Running in master mode\n");
-                               dev->flags |= MLX4_FLAG_SRIOV |
-                                             MLX4_FLAG_MASTER;
-                               dev->num_vfs = num_vfs;
+                               atomic_inc(&pf_loading);
+                               err = pci_enable_sriov(pdev, total_vfs);
+                               atomic_dec(&pf_loading);
+                               if (err) {
+                                       mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n",
+                                                err);
+                                       err = 0;
+                               } else {
+                                       mlx4_warn(dev, "Running in master mode\n");
+                                       dev->flags |= MLX4_FLAG_SRIOV |
+                                                     MLX4_FLAG_MASTER;
+                                       dev->num_vfs = total_vfs;
+                                       sriov_initialized = 1;
+                               }
                        }
                }
 
@@ -2393,12 +2450,37 @@ slave_start:
        /* In master functions, the communication channel must be initialized
         * after obtaining its address from fw */
        if (mlx4_is_master(dev)) {
+               unsigned sum = 0;
                err = mlx4_multi_func_init(dev);
                if (err) {
                        mlx4_err(dev, "Failed to init master mfunc"
                                 "interface, aborting.\n");
                        goto err_close;
                }
+               if (sriov_initialized) {
+                       int ib_ports = 0;
+                       mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
+                               ib_ports++;
+
+                       if (ib_ports &&
+                           (num_vfs_argc > 1 || probe_vfs_argc > 1)) {
+                               mlx4_err(dev,
+                                        "Invalid syntax of num_vfs/probe_vfs "
+                                        "with IB port. Single port VFs syntax"
+                                        " is only supported when all ports "
+                                        "are configured as ethernet\n");
+                               goto err_close;
+                       }
+                       for (i = 0; i < sizeof(nvfs)/sizeof(nvfs[0]); i++) {
+                               unsigned j;
+                               for (j = 0; j < nvfs[i]; ++sum, ++j) {
+                                       dev->dev_vfs[sum].min_port =
+                                               i < 2 ? i + 1 : 1;
+                                       dev->dev_vfs[sum].n_ports = i < 2 ? 1 :
+                                               dev->caps.num_ports;
+                               }
+                       }
+               }
        }
 
        err = mlx4_alloc_eq_table(dev);
@@ -2506,6 +2588,8 @@ err_rel_own:
        if (!mlx4_is_slave(dev))
                mlx4_free_ownership(dev);
 
+       kfree(priv->dev.dev_vfs);
+
 err_free_dev:
        kfree(priv);
 
@@ -2592,6 +2676,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
                kfree(dev->caps.qp0_proxy);
                kfree(dev->caps.qp1_tunnel);
                kfree(dev->caps.qp1_proxy);
+               kfree(dev->dev_vfs);
 
                kfree(priv);
                pci_release_regions(pdev);
@@ -2670,7 +2755,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
 
 static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
 {
-       int ret = __mlx4_init_one(pdev, 0);
+       const struct pci_device_id *id;
+       int ret;
+
+       id = pci_match_id(mlx4_pci_table, pdev);
+       ret = __mlx4_init_one(pdev, id->driver_data);
 
        return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
 }
@@ -2684,6 +2773,7 @@ static struct pci_driver mlx4_driver = {
        .name           = DRV_NAME,
        .id_table       = mlx4_pci_table,
        .probe          = mlx4_init_one,
+       .shutdown       = mlx4_remove_one,
        .remove         = mlx4_remove_one,
        .err_handler    = &mlx4_err_handler,
 };
index db7dc0b6667d6f1ecb57076db2e855bd7a9cb448..80ccb4edf825f8888c6487626f2f380c7b27479b 100644 (file)
@@ -1387,9 +1387,12 @@ int mlx4_PROMISC_wrapper(struct mlx4_dev *dev, int slave,
                         struct mlx4_cmd_info *cmd)
 {
        u32 qpn = (u32) vhcr->in_param & 0xffffffff;
-       u8 port = vhcr->in_param >> 62;
+       int port = mlx4_slave_convert_port(dev, slave, vhcr->in_param >> 62);
        enum mlx4_steer_type steer = vhcr->in_modifier;
 
+       if (port < 0)
+               return -EINVAL;
+
        /* Promiscuous unicast is not allowed in mfunc */
        if (mlx4_is_mfunc(dev) && steer == MLX4_UC_STEER)
                return 0;
index 6b65f77952153f5dd1ceab2d074e456b2a9567c4..cf8be41abb36f9e0b5324abce28d24e81f4963e8 100644 (file)
@@ -51,8 +51,8 @@
 
 #define DRV_NAME       "mlx4_core"
 #define PFX            DRV_NAME ": "
-#define DRV_VERSION    "1.1"
-#define DRV_RELDATE    "Dec, 2011"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb, 2014"
 
 #define MLX4_FS_UDP_UC_EN              (1 << 1)
 #define MLX4_FS_TCP_UC_EN              (1 << 2)
@@ -788,6 +788,10 @@ enum {
        MLX4_USE_RR     = 1,
 };
 
+struct mlx4_roce_gid_entry {
+       u8 raw[16];
+};
+
 struct mlx4_priv {
        struct mlx4_dev         dev;
 
@@ -834,6 +838,7 @@ struct mlx4_priv {
        int                     fs_hash_mode;
        u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
        __be64                  slave_node_guids[MLX4_MFUNC_MAX];
+       struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][MLX4_ROCE_MAX_GIDS];
 
        atomic_t                opreq_count;
        struct work_struct      opreq_task;
@@ -1242,11 +1247,6 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
                                         struct mlx4_cmd_mailbox *inbox,
                                         struct mlx4_cmd_mailbox *outbox,
                                         struct mlx4_cmd_info *cmd);
-int mlx4_FLOW_STEERING_IB_UC_QP_RANGE_wrapper(struct mlx4_dev *dev, int slave,
-                                             struct mlx4_vhcr *vhcr,
-                                             struct mlx4_cmd_mailbox *inbox,
-                                             struct mlx4_cmd_mailbox *outbox,
-                                             struct mlx4_cmd_info *cmd);
 
 int mlx4_get_mgm_entry_size(struct mlx4_dev *dev);
 int mlx4_get_qp_per_mgm(struct mlx4_dev *dev);
@@ -1282,4 +1282,8 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work);
 
 void mlx4_init_quotas(struct mlx4_dev *dev);
 
+int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port);
+/* Returns the VF index of slave */
+int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave);
+
 #endif /* MLX4_H */
index 3af04c3f42ea96ddfa013ee874791c2db9dd6d94..36fc2a2b24c3156cbcd29ae97df50592cdc15fec 100644 (file)
@@ -57,8 +57,8 @@
 #include "en_port.h"
 
 #define DRV_NAME       "mlx4_en"
-#define DRV_VERSION    "2.0"
-#define DRV_RELDATE    "Dec 2011"
+#define DRV_VERSION    "2.2-1"
+#define DRV_RELDATE    "Feb 2014"
 
 #define MLX4_EN_MSG_LEVEL      (NETIF_MSG_LINK | NETIF_MSG_IFDOWN)
 
@@ -187,6 +187,13 @@ enum {
 #define GET_AVG_PERF_COUNTER(cnt)      (0)
 #endif /* MLX4_EN_PERF_STAT */
 
+/* Constants for TX flow */
+enum {
+       MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */
+       MAX_BF = 256,
+       MIN_PKT_LEN = 17,
+};
+
 /*
  * Configurables
  */
@@ -267,10 +274,13 @@ struct mlx4_en_tx_ring {
        unsigned long bytes;
        unsigned long packets;
        unsigned long tx_csum;
+       unsigned long queue_stopped;
+       unsigned long wake_queue;
        struct mlx4_bf bf;
        bool bf_enabled;
        struct netdev_queue *tx_queue;
        int hwtstamp_tx_type;
+       int inline_thold;
 };
 
 struct mlx4_en_rx_desc {
@@ -346,6 +356,7 @@ struct mlx4_en_port_profile {
        u8 tx_pause;
        u8 tx_ppp;
        int rss_rings;
+       int inline_thold;
 };
 
 struct mlx4_en_profile {
@@ -548,6 +559,8 @@ struct mlx4_en_priv {
        struct work_struct linkstate_task;
        struct delayed_work stats_task;
        struct delayed_work service_task;
+       struct work_struct vxlan_add_task;
+       struct work_struct vxlan_del_task;
        struct mlx4_en_perf_stats pstats;
        struct mlx4_en_pkt_stats pkstats;
        struct mlx4_en_port_stats port_stats;
@@ -574,6 +587,7 @@ struct mlx4_en_priv {
        struct hlist_head filter_hash[1 << MLX4_EN_FILTER_HASH_SHIFT];
 #endif
        u64 tunnel_reg_id;
+       __be16 vxlan_port;
 };
 
 enum mlx4_en_wol {
@@ -723,7 +737,7 @@ int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq);
 
 void mlx4_en_tx_irq(struct mlx4_cq *mcq);
 u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
-                        void *accel_priv);
+                        void *accel_priv, select_queue_fallback_t fallback);
 netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev);
 
 int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
@@ -737,7 +751,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
                             int cq, int user_prio);
 void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv,
                                struct mlx4_en_tx_ring *ring);
-
+void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev);
 int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
                           struct mlx4_en_rx_ring **pring,
                           u32 size, u16 stride, int node);
@@ -786,7 +800,6 @@ void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv);
 
 #define MLX4_EN_NUM_SELF_TEST  5
 void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf);
-u64 mlx4_en_mac_to_u64(u8 *addr);
 void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev);
 
 /*
index a58bcbf1b8067e88e5e153f25cd285ef57b90bb3..cfcad26ed40f60b0e5b992195339d8c12c0e68d7 100644 (file)
@@ -505,6 +505,84 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps)
        mlx4_free_cmd_mailbox(dev, outmailbox);
        return err;
 }
+static struct mlx4_roce_gid_entry zgid_entry;
+
+int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
+{
+       int vfs;
+       int slave_gid = slave;
+       unsigned i;
+       struct mlx4_slaves_pport slaves_pport;
+       struct mlx4_active_ports actv_ports;
+       unsigned max_port_p_one;
+
+       if (slave == 0)
+               return MLX4_ROCE_PF_GIDS;
+
+       /* Slave is a VF */
+       slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
+       actv_ports = mlx4_get_active_ports(dev, slave);
+       max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
+               bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
+
+       for (i = 1; i < max_port_p_one; i++) {
+               struct mlx4_active_ports exclusive_ports;
+               struct mlx4_slaves_pport slaves_pport_actv;
+               bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+               set_bit(i - 1, exclusive_ports.ports);
+               if (i == port)
+                       continue;
+               slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
+                                   dev, &exclusive_ports);
+               slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
+                                          dev->num_vfs + 1);
+       }
+       vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+       if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
+               return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
+       return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
+}
+
+int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
+{
+       int gids;
+       unsigned i;
+       int slave_gid = slave;
+       int vfs;
+
+       struct mlx4_slaves_pport slaves_pport;
+       struct mlx4_active_ports actv_ports;
+       unsigned max_port_p_one;
+
+       if (slave == 0)
+               return 0;
+
+       slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
+       actv_ports = mlx4_get_active_ports(dev, slave);
+       max_port_p_one = find_first_bit(actv_ports.ports, dev->caps.num_ports) +
+               bitmap_weight(actv_ports.ports, dev->caps.num_ports) + 1;
+
+       for (i = 1; i < max_port_p_one; i++) {
+               struct mlx4_active_ports exclusive_ports;
+               struct mlx4_slaves_pport slaves_pport_actv;
+               bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+               set_bit(i - 1, exclusive_ports.ports);
+               if (i == port)
+                       continue;
+               slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
+                                   dev, &exclusive_ports);
+               slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
+                                          dev->num_vfs + 1);
+       }
+       gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+       vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+       if (slave_gid <= gids % vfs)
+               return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
+
+       return MLX4_ROCE_PF_GIDS + (gids % vfs) +
+               ((gids / vfs) * (slave_gid - 1));
+}
+EXPORT_SYMBOL_GPL(mlx4_get_base_gid_ix);
 
 static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
                                u8 op_mod, struct mlx4_cmd_mailbox *inbox)
@@ -515,14 +593,18 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
        struct mlx4_slave_state *slave_st = &master->slave_state[slave];
        struct mlx4_set_port_rqp_calc_context *qpn_context;
        struct mlx4_set_port_general_context *gen_context;
+       struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1;
        int reset_qkey_viols;
        int port;
        int is_eth;
+       int num_gids;
+       int base;
        u32 in_modifier;
        u32 promisc;
        u16 mtu, prev_mtu;
        int err;
-       int i;
+       int i, j;
+       int offset;
        __be32 agg_cap_mask;
        __be32 slave_cap_mask;
        __be32 new_cap_mask;
@@ -535,7 +617,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
        /* Slaves cannot perform SET_PORT operations except changing MTU */
        if (is_eth) {
                if (slave != dev->caps.function &&
-                   in_modifier != MLX4_SET_PORT_GENERAL) {
+                   in_modifier != MLX4_SET_PORT_GENERAL &&
+                   in_modifier != MLX4_SET_PORT_GID_TABLE) {
                        mlx4_warn(dev, "denying SET_PORT for slave:%d\n",
                                        slave);
                        return -EINVAL;
@@ -581,6 +664,67 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod,
 
                        gen_context->mtu = cpu_to_be16(master->max_mtu[port]);
                        break;
+               case MLX4_SET_PORT_GID_TABLE:
+                       /* change to MULTIPLE entries: number of guest's gids
+                        * need a FOR-loop here over number of gids the guest has.
+                        * 1. Check no duplicates in gids passed by slave
+                        */
+                       num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+                       base = mlx4_get_base_gid_ix(dev, slave, port);
+                       gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                       for (i = 0; i < num_gids; gid_entry_mbox++, i++) {
+                               if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
+                                           sizeof(zgid_entry)))
+                                       continue;
+                               gid_entry_mb1 = gid_entry_mbox + 1;
+                               for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) {
+                                       if (!memcmp(gid_entry_mb1->raw,
+                                                   zgid_entry.raw, sizeof(zgid_entry)))
+                                               continue;
+                                       if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw,
+                                                   sizeof(gid_entry_mbox->raw))) {
+                                               /* found duplicate */
+                                               return -EINVAL;
+                                       }
+                               }
+                       }
+
+                       /* 2. Check that do not have duplicates in OTHER
+                        *    entries in the port GID table
+                        */
+                       for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
+                               if (i >= base && i < base + num_gids)
+                                       continue; /* don't compare to slave's current gids */
+                               gid_entry_tbl = &priv->roce_gids[port - 1][i];
+                               if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry)))
+                                       continue;
+                               gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                               for (j = 0; j < num_gids; gid_entry_mbox++, j++) {
+                                       if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw,
+                                                   sizeof(zgid_entry)))
+                                               continue;
+                                       if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw,
+                                                   sizeof(gid_entry_tbl->raw))) {
+                                               /* found duplicate */
+                                               mlx4_warn(dev, "requested gid entry for slave:%d "
+                                                         "is a duplicate of gid at index %d\n",
+                                                         slave, i);
+                                               return -EINVAL;
+                                       }
+                               }
+                       }
+
+                       /* insert slave GIDs with memcpy, starting at slave's base index */
+                       gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                       for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++)
+                               memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16);
+
+                       /* Now, copy roce port gids table to current mailbox for passing to FW */
+                       gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf);
+                       for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++)
+                               memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16);
+
+                       break;
                }
                return mlx4_cmd(dev, inbox->dma, in_mod, op_mod,
                                MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
@@ -646,6 +790,15 @@ int mlx4_SET_PORT_wrapper(struct mlx4_dev *dev, int slave,
                          struct mlx4_cmd_mailbox *outbox,
                          struct mlx4_cmd_info *cmd)
 {
+       int port = mlx4_slave_convert_port(
+                       dev, slave, vhcr->in_modifier & 0xFF);
+
+       if (port < 0)
+               return -EINVAL;
+
+       vhcr->in_modifier = (vhcr->in_modifier & ~0xFF) |
+                           (port & 0xFF);
+
        return mlx4_common_set_port(dev, slave, vhcr->in_modifier,
                                    vhcr->op_modifier, inbox);
 }
@@ -835,7 +988,7 @@ struct mlx4_set_port_vxlan_context {
        u8      steering;
 };
 
-int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering)
+int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable)
 {
        int err;
        u32 in_mod;
@@ -849,7 +1002,8 @@ int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering)
        memset(context, 0, sizeof(*context));
 
        context->modify_flags = VXLAN_ENABLE_MODIFY | VXLAN_STEERING_MODIFY;
-       context->enable_flags = VXLAN_ENABLE;
+       if (enable)
+               context->enable_flags = VXLAN_ENABLE;
        context->steering  = steering;
 
        in_mod = MLX4_SET_PORT_VXLAN << 8 | port;
@@ -927,3 +1081,108 @@ void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap)
                *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK;
 }
 EXPORT_SYMBOL(mlx4_set_stats_bitmap);
+
+int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
+                                int *slave_id)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       int i, found_ix = -1;
+       int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
+       struct mlx4_slaves_pport slaves_pport;
+       unsigned num_vfs;
+       int slave_gid;
+
+       if (!mlx4_is_mfunc(dev))
+               return -EINVAL;
+
+       slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
+       num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+
+       for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
+               if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) {
+                       found_ix = i;
+                       break;
+               }
+       }
+
+       if (found_ix >= 0) {
+               if (found_ix < MLX4_ROCE_PF_GIDS)
+                       slave_gid = 0;
+               else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % num_vfs) *
+                        (vf_gids / num_vfs + 1))
+                       slave_gid = ((found_ix - MLX4_ROCE_PF_GIDS) /
+                                    (vf_gids / num_vfs + 1)) + 1;
+               else
+                       slave_gid =
+                       ((found_ix - MLX4_ROCE_PF_GIDS -
+                         ((vf_gids % num_vfs) * ((vf_gids / num_vfs + 1)))) /
+                        (vf_gids / num_vfs)) + vf_gids % num_vfs + 1;
+
+               if (slave_gid) {
+                       struct mlx4_active_ports exclusive_ports;
+                       struct mlx4_active_ports actv_ports;
+                       struct mlx4_slaves_pport slaves_pport_actv;
+                       unsigned max_port_p_one;
+                       int num_slaves_before = 1;
+
+                       for (i = 1; i < port; i++) {
+                               bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+                               set_bit(i, exclusive_ports.ports);
+                               slaves_pport_actv =
+                                       mlx4_phys_to_slaves_pport_actv(
+                                                       dev, &exclusive_ports);
+                               num_slaves_before += bitmap_weight(
+                                               slaves_pport_actv.slaves,
+                                               dev->num_vfs + 1);
+                       }
+
+                       if (slave_gid < num_slaves_before) {
+                               bitmap_zero(exclusive_ports.ports, dev->caps.num_ports);
+                               set_bit(port - 1, exclusive_ports.ports);
+                               slaves_pport_actv =
+                                       mlx4_phys_to_slaves_pport_actv(
+                                                       dev, &exclusive_ports);
+                               slave_gid += bitmap_weight(
+                                               slaves_pport_actv.slaves,
+                                               dev->num_vfs + 1) -
+                                               num_slaves_before;
+                       }
+                       actv_ports = mlx4_get_active_ports(dev, slave_gid);
+                       max_port_p_one = find_first_bit(
+                               actv_ports.ports, dev->caps.num_ports) +
+                               bitmap_weight(actv_ports.ports,
+                                             dev->caps.num_ports) + 1;
+
+                       for (i = 1; i < max_port_p_one; i++) {
+                               if (i == port)
+                                       continue;
+                               bitmap_zero(exclusive_ports.ports,
+                                           dev->caps.num_ports);
+                               set_bit(i - 1, exclusive_ports.ports);
+                               slaves_pport_actv =
+                                       mlx4_phys_to_slaves_pport_actv(
+                                               dev, &exclusive_ports);
+                               slave_gid += bitmap_weight(
+                                               slaves_pport_actv.slaves,
+                                               dev->num_vfs + 1);
+                       }
+               }
+               *slave_id = slave_gid;
+       }
+
+       return (found_ix >= 0) ? 0 : -EINVAL;
+}
+EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid);
+
+int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
+                                u8 *gid)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+
+       if (!mlx4_is_master(dev))
+               return -EINVAL;
+
+       memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16);
+       return 0;
+}
+EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave);
index 57428a0cb9ddc37fd226cb22305323185eda22fd..3b5f53ef29b292d6edcb027f6b64b9c108a3a03b 100644 (file)
@@ -52,6 +52,8 @@
 struct mac_res {
        struct list_head list;
        u64 mac;
+       int ref_count;
+       u8 smac_index;
        u8 port;
 };
 
@@ -219,6 +221,11 @@ struct res_fs_rule {
        int                     qpn;
 };
 
+static int mlx4_is_eth(struct mlx4_dev *dev, int port)
+{
+       return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1;
+}
+
 static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
 {
        struct rb_node *node = root->rb_node;
@@ -461,6 +468,8 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
 
                spin_lock_init(&res_alloc->alloc_lock);
                for (t = 0; t < dev->num_vfs + 1; t++) {
+                       struct mlx4_active_ports actv_ports =
+                               mlx4_get_active_ports(dev, t);
                        switch (i) {
                        case RES_QP:
                                initialize_res_quotas(dev, res_alloc, RES_QP,
@@ -490,10 +499,27 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
                                break;
                        case RES_MAC:
                                if (t == mlx4_master_func_num(dev)) {
-                                       res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
+                                       int max_vfs_pport = 0;
+                                       /* Calculate the max vfs per port for */
+                                       /* both ports.                        */
+                                       for (j = 0; j < dev->caps.num_ports;
+                                            j++) {
+                                               struct mlx4_slaves_pport slaves_pport =
+                                                       mlx4_phys_to_slaves_pport(dev, j + 1);
+                                               unsigned current_slaves =
+                                                       bitmap_weight(slaves_pport.slaves,
+                                                                     dev->caps.num_ports) - 1;
+                                               if (max_vfs_pport < current_slaves)
+                                                       max_vfs_pport =
+                                                               current_slaves;
+                                       }
+                                       res_alloc->quota[t] =
+                                               MLX4_MAX_MAC_NUM -
+                                               2 * max_vfs_pport;
                                        res_alloc->guaranteed[t] = 2;
                                        for (j = 0; j < MLX4_MAX_PORTS; j++)
-                                               res_alloc->res_port_free[j] = MLX4_MAX_MAC_NUM;
+                                               res_alloc->res_port_free[j] =
+                                                       MLX4_MAX_MAC_NUM;
                                } else {
                                        res_alloc->quota[t] = MLX4_MAX_MAC_NUM;
                                        res_alloc->guaranteed[t] = 2;
@@ -521,9 +547,10 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
                                break;
                        }
                        if (i == RES_MAC || i == RES_VLAN) {
-                               for (j = 0; j < MLX4_MAX_PORTS; j++)
-                                       res_alloc->res_port_rsvd[j] +=
-                                               res_alloc->guaranteed[t];
+                               for (j = 0; j < dev->caps.num_ports; j++)
+                                       if (test_bit(j, actv_ports.ports))
+                                               res_alloc->res_port_rsvd[j] +=
+                                                       res_alloc->guaranteed[t];
                        } else {
                                res_alloc->res_reserved += res_alloc->guaranteed[t];
                        }
@@ -600,15 +627,37 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
        struct mlx4_qp_context  *qp_ctx = inbox->buf + 8;
        enum mlx4_qp_optpar     optpar = be32_to_cpu(*(__be32 *) inbox->buf);
        u32                     ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
+       int port;
 
-       if (MLX4_QP_ST_UD == ts)
-               qp_ctx->pri_path.mgid_index = 0x80 | slave;
-
-       if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) {
-               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH)
-                       qp_ctx->pri_path.mgid_index = slave & 0x7F;
-               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
-                       qp_ctx->alt_path.mgid_index = slave & 0x7F;
+       if (MLX4_QP_ST_UD == ts) {
+               port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+               if (mlx4_is_eth(dev, port))
+                       qp_ctx->pri_path.mgid_index =
+                               mlx4_get_base_gid_ix(dev, slave, port) | 0x80;
+               else
+                       qp_ctx->pri_path.mgid_index = slave | 0x80;
+
+       } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) {
+               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
+                       port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+                       if (mlx4_is_eth(dev, port)) {
+                               qp_ctx->pri_path.mgid_index +=
+                                       mlx4_get_base_gid_ix(dev, slave, port);
+                               qp_ctx->pri_path.mgid_index &= 0x7f;
+                       } else {
+                               qp_ctx->pri_path.mgid_index = slave & 0x7F;
+                       }
+               }
+               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+                       port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
+                       if (mlx4_is_eth(dev, port)) {
+                               qp_ctx->alt_path.mgid_index +=
+                                       mlx4_get_base_gid_ix(dev, slave, port);
+                               qp_ctx->alt_path.mgid_index &= 0x7f;
+                       } else {
+                               qp_ctx->alt_path.mgid_index = slave & 0x7F;
+                       }
+               }
        }
 }
 
@@ -619,7 +668,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
        struct mlx4_qp_context  *qpc = inbox->buf + 8;
        struct mlx4_vport_oper_state *vp_oper;
        struct mlx4_priv *priv;
-       u32 qp_type;
        int port;
 
        port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1;
@@ -627,12 +675,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev,
        vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
 
        if (MLX4_VGT != vp_oper->state.default_vlan) {
-               qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
-               if (MLX4_QP_ST_RC == qp_type ||
-                   (MLX4_QP_ST_UD == qp_type &&
-                    !mlx4_is_qp_reserved(dev, qpn)))
-                       return -EINVAL;
-
                /* the reserved QPs (special, proxy, tunnel)
                 * do not operate over vlans
                 */
@@ -1659,11 +1701,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        return err;
 }
 
-static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
+static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port,
+                                    u8 smac_index, u64 *mac)
+{
+       struct mlx4_priv *priv = mlx4_priv(dev);
+       struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
+       struct list_head *mac_list =
+               &tracker->slave_list[slave].res_list[RES_MAC];
+       struct mac_res *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, mac_list, list) {
+               if (res->smac_index == smac_index && res->port == (u8) port) {
+                       *mac = res->mac;
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
        struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker;
-       struct mac_res *res;
+       struct list_head *mac_list =
+               &tracker->slave_list[slave].res_list[RES_MAC];
+       struct mac_res *res, *tmp;
+
+       list_for_each_entry_safe(res, tmp, mac_list, list) {
+               if (res->mac == mac && res->port == (u8) port) {
+                       /* mac found. update ref count */
+                       ++res->ref_count;
+                       return 0;
+               }
+       }
 
        if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port))
                return -EINVAL;
@@ -1674,6 +1744,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port)
        }
        res->mac = mac;
        res->port = (u8) port;
+       res->smac_index = smac_index;
+       res->ref_count = 1;
        list_add_tail(&res->list,
                      &tracker->slave_list[slave].res_list[RES_MAC]);
        return 0;
@@ -1690,9 +1762,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac,
 
        list_for_each_entry_safe(res, tmp, mac_list, list) {
                if (res->mac == mac && res->port == (u8) port) {
-                       list_del(&res->list);
-                       mlx4_release_resource(dev, slave, RES_MAC, 1, port);
-                       kfree(res);
+                       if (!--res->ref_count) {
+                               list_del(&res->list);
+                               mlx4_release_resource(dev, slave, RES_MAC, 1, port);
+                               kfree(res);
+                       }
                        break;
                }
        }
@@ -1705,10 +1779,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave)
        struct list_head *mac_list =
                &tracker->slave_list[slave].res_list[RES_MAC];
        struct mac_res *res, *tmp;
+       int i;
 
        list_for_each_entry_safe(res, tmp, mac_list, list) {
                list_del(&res->list);
-               __mlx4_unregister_mac(dev, res->port, res->mac);
+               /* dereference the mac the num times the slave referenced it */
+               for (i = 0; i < res->ref_count; i++)
+                       __mlx4_unregister_mac(dev, res->port, res->mac);
                mlx4_release_resource(dev, slave, RES_MAC, 1, res->port);
                kfree(res);
        }
@@ -1720,21 +1797,28 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        int err = -EINVAL;
        int port;
        u64 mac;
+       u8 smac_index;
 
        if (op != RES_OP_RESERVE_AND_MAP)
                return err;
 
        port = !in_port ? get_param_l(out_param) : in_port;
+       port = mlx4_slave_convert_port(
+                       dev, slave, port);
+
+       if (port < 0)
+               return -EINVAL;
        mac = in_param;
 
        err = __mlx4_register_mac(dev, port, mac);
        if (err >= 0) {
+               smac_index = err;
                set_param_l(out_param, err);
                err = 0;
        }
 
        if (!err) {
-               err = mac_add_to_slave(dev, slave, mac, port);
+               err = mac_add_to_slave(dev, slave, mac, port, smac_index);
                if (err)
                        __mlx4_unregister_mac(dev, port, mac);
        }
@@ -1831,6 +1915,11 @@ static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        if (!port || op != RES_OP_RESERVE_AND_MAP)
                return -EINVAL;
 
+       port = mlx4_slave_convert_port(
+                       dev, slave, port);
+
+       if (port < 0)
+               return -EINVAL;
        /* upstream kernels had NOP for reg/unreg vlan. Continue this. */
        if (!in_port && port > 0 && port <= dev->caps.num_ports) {
                slave_state[slave].old_vlan_api = true;
@@ -2128,6 +2217,11 @@ static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        switch (op) {
        case RES_OP_RESERVE_AND_MAP:
                port = !in_port ? get_param_l(out_param) : in_port;
+               port = mlx4_slave_convert_port(
+                               dev, slave, port);
+
+               if (port < 0)
+                       return -EINVAL;
                mac_del_from_slave(dev, slave, in_param, port);
                __mlx4_unregister_mac(dev, port, in_param);
                break;
@@ -2147,6 +2241,11 @@ static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
        struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
        int err = 0;
 
+       port = mlx4_slave_convert_port(
+                       dev, slave, port);
+
+       if (port < 0)
+               return -EINVAL;
        switch (op) {
        case RES_OP_RESERVE_AND_MAP:
                if (slave_state[slave].old_vlan_api)
@@ -2734,6 +2833,8 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
        u32                     qp_type;
        struct mlx4_qp_context  *qp_ctx;
        enum mlx4_qp_optpar     optpar;
+       int port;
+       int num_gids;
 
        qp_ctx  = inbox->buf + 8;
        qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
@@ -2741,6 +2842,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
 
        switch (qp_type) {
        case MLX4_QP_ST_RC:
+       case MLX4_QP_ST_XRC:
        case MLX4_QP_ST_UC:
                switch (transition) {
                case QP_TRANS_INIT2RTR:
@@ -2749,13 +2851,24 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
                case QP_TRANS_SQD2SQD:
                case QP_TRANS_SQD2RTS:
                        if (slave != mlx4_master_func_num(dev))
-                               /* slaves have only gid index 0 */
-                               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH)
-                                       if (qp_ctx->pri_path.mgid_index)
+                               if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) {
+                                       port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1;
+                                       if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
+                                               num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+                                       else
+                                               num_gids = 1;
+                                       if (qp_ctx->pri_path.mgid_index >= num_gids)
                                                return -EINVAL;
-                               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
-                                       if (qp_ctx->alt_path.mgid_index)
+                               }
+                               if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+                                       port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1;
+                                       if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB)
+                                               num_gids = mlx4_get_slave_num_gids(dev, slave, port);
+                                       else
+                                               num_gids = 1;
+                                       if (qp_ctx->alt_path.mgid_index >= num_gids)
                                                return -EINVAL;
+                               }
                        break;
                default:
                        break;
@@ -3268,6 +3381,58 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave,
        return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
 }
 
+static int adjust_qp_sched_queue(struct mlx4_dev *dev, int slave,
+                                 struct mlx4_qp_context *qpc,
+                                 struct mlx4_cmd_mailbox *inbox)
+{
+       enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *)inbox->buf);
+       u8 pri_sched_queue;
+       int port = mlx4_slave_convert_port(
+                  dev, slave, (qpc->pri_path.sched_queue >> 6 & 1) + 1) - 1;
+
+       if (port < 0)
+               return -EINVAL;
+
+       pri_sched_queue = (qpc->pri_path.sched_queue & ~(1 << 6)) |
+                         ((port & 1) << 6);
+
+       if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH ||
+           mlx4_is_eth(dev, port + 1)) {
+               qpc->pri_path.sched_queue = pri_sched_queue;
+       }
+
+       if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) {
+               port = mlx4_slave_convert_port(
+                               dev, slave, (qpc->alt_path.sched_queue >> 6 & 1)
+                               + 1) - 1;
+               if (port < 0)
+                       return -EINVAL;
+               qpc->alt_path.sched_queue =
+                       (qpc->alt_path.sched_queue & ~(1 << 6)) |
+                       (port & 1) << 6;
+       }
+       return 0;
+}
+
+static int roce_verify_mac(struct mlx4_dev *dev, int slave,
+                               struct mlx4_qp_context *qpc,
+                               struct mlx4_cmd_mailbox *inbox)
+{
+       u64 mac;
+       int port;
+       u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff;
+       u8 sched = *(u8 *)(inbox->buf + 64);
+       u8 smac_ix;
+
+       port = (sched >> 6 & 1) + 1;
+       if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) {
+               smac_ix = qpc->pri_path.grh_mylmc & 0x7f;
+               if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac))
+                       return -ENOENT;
+       }
+       return 0;
+}
+
 int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
                             struct mlx4_vhcr *vhcr,
                             struct mlx4_cmd_mailbox *inbox,
@@ -3286,10 +3451,16 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave,
        u8 orig_vlan_index = qpc->pri_path.vlan_index;
        u8 orig_feup = qpc->pri_path.feup;
 
+       err = adjust_qp_sched_queue(dev, slave, qpc, inbox);
+       if (err)
+               return err;
        err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave);
        if (err)
                return err;
 
+       if (roce_verify_mac(dev, slave, qpc, inbox))
+               return -EINVAL;
+
        update_pkey_index(dev, slave, inbox);
        update_gid(dev, inbox, (u8)slave);
        adjust_proxy_tun_qkey(dev, vhcr, qpc);
@@ -3334,6 +3505,9 @@ int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        struct mlx4_qp_context *context = inbox->buf + 8;
 
+       err = adjust_qp_sched_queue(dev, slave, context, inbox);
+       if (err)
+               return err;
        err = verify_qp_parameters(dev, inbox, QP_TRANS_RTR2RTS, slave);
        if (err)
                return err;
@@ -3353,6 +3527,9 @@ int mlx4_RTS2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        struct mlx4_qp_context *context = inbox->buf + 8;
 
+       err = adjust_qp_sched_queue(dev, slave, context, inbox);
+       if (err)
+               return err;
        err = verify_qp_parameters(dev, inbox, QP_TRANS_RTS2RTS, slave);
        if (err)
                return err;
@@ -3371,6 +3548,9 @@ int mlx4_SQERR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
                              struct mlx4_cmd_info *cmd)
 {
        struct mlx4_qp_context *context = inbox->buf + 8;
+       int err = adjust_qp_sched_queue(dev, slave, context, inbox);
+       if (err)
+               return err;
        adjust_proxy_tun_qkey(dev, vhcr, context);
        return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd);
 }
@@ -3384,6 +3564,9 @@ int mlx4_SQD2SQD_QP_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        struct mlx4_qp_context *context = inbox->buf + 8;
 
+       err = adjust_qp_sched_queue(dev, slave, context, inbox);
+       if (err)
+               return err;
        err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2SQD, slave);
        if (err)
                return err;
@@ -3403,6 +3586,9 @@ int mlx4_SQD2RTS_QP_wrapper(struct mlx4_dev *dev, int slave,
        int err;
        struct mlx4_qp_context *context = inbox->buf + 8;
 
+       err = adjust_qp_sched_queue(dev, slave, context, inbox);
+       if (err)
+               return err;
        err = verify_qp_parameters(dev, inbox, QP_TRANS_SQD2RTS, slave);
        if (err)
                return err;
@@ -3506,16 +3692,26 @@ static int rem_mcg_res(struct mlx4_dev *dev, int slave, struct res_qp *rqp,
        return err;
 }
 
-static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
-                    int block_loopback, enum mlx4_protocol prot,
+static int qp_attach(struct mlx4_dev *dev, int slave, struct mlx4_qp *qp,
+                    u8 gid[16], int block_loopback, enum mlx4_protocol prot,
                     enum mlx4_steer_type type, u64 *reg_id)
 {
        switch (dev->caps.steering_mode) {
-       case MLX4_STEERING_MODE_DEVICE_MANAGED:
-               return mlx4_trans_to_dmfs_attach(dev, qp, gid, gid[5],
+       case MLX4_STEERING_MODE_DEVICE_MANAGED: {
+               int port = mlx4_slave_convert_port(dev, slave, gid[5]);
+               if (port < 0)
+                       return port;
+               return mlx4_trans_to_dmfs_attach(dev, qp, gid, port,
                                                block_loopback, prot,
                                                reg_id);
+       }
        case MLX4_STEERING_MODE_B0:
+               if (prot == MLX4_PROT_ETH) {
+                       int port = mlx4_slave_convert_port(dev, slave, gid[5]);
+                       if (port < 0)
+                               return port;
+                       gid[5] = port;
+               }
                return mlx4_qp_attach_common(dev, qp, gid,
                                            block_loopback, prot, type);
        default:
@@ -3523,9 +3719,9 @@ static int qp_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
        }
 }
 
-static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
-                    enum mlx4_protocol prot, enum mlx4_steer_type type,
-                    u64 reg_id)
+static int qp_detach(struct mlx4_dev *dev, struct mlx4_qp *qp,
+                    u8 gid[16], enum mlx4_protocol prot,
+                    enum mlx4_steer_type type, u64 reg_id)
 {
        switch (dev->caps.steering_mode) {
        case MLX4_STEERING_MODE_DEVICE_MANAGED:
@@ -3562,7 +3758,7 @@ int mlx4_QP_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
 
        qp.qpn = qpn;
        if (attach) {
-               err = qp_attach(dev, &qp, gid, block_loopback, prot,
+               err = qp_attach(dev, slave, &qp, gid, block_loopback, prot,
                                type, &reg_id);
                if (err) {
                        pr_err("Fail to attach rule to qp 0x%x\n", qpn);
@@ -3698,6 +3894,9 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
                return -EOPNOTSUPP;
 
        ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
+       ctrl->port = mlx4_slave_convert_port(dev, slave, ctrl->port);
+       if (ctrl->port <= 0)
+               return -EINVAL;
        qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
        err = get_res(dev, slave, qpn, RES_QP, &rqp);
        if (err) {
@@ -3816,16 +4015,6 @@ int mlx4_QUERY_IF_STAT_wrapper(struct mlx4_dev *dev, int slave,
        return err;
 }
 
-int mlx4_FLOW_STEERING_IB_UC_QP_RANGE_wrapper(struct mlx4_dev *dev, int slave,
-                                             struct mlx4_vhcr *vhcr,
-                                             struct mlx4_cmd_mailbox *inbox,
-                                             struct mlx4_cmd_mailbox *outbox,
-                                             struct mlx4_cmd_info *cmd)
-{
-       return -EPERM;
-}
-
-
 static void detach_qp(struct mlx4_dev *dev, int slave, struct res_qp *rqp)
 {
        struct res_gid *rgid;
index 157fe8df2c3ed5c105a5301219b281670ed70efd..8ff57e8e3e91601bc503e5f501ac2ef1da956296 100644 (file)
@@ -4,5 +4,5 @@
 
 config MLX5_CORE
        tristate
-       depends on PCI && X86
+       depends on PCI
        default n
index a064f06e0cb8a244d183c3c48acb1754349115dd..77ac95f052da81e31608891129141e43f9e61659 100644 (file)
@@ -46,8 +46,8 @@
 #include "mlx5_core.h"
 
 #define DRIVER_NAME "mlx5_core"
-#define DRIVER_VERSION "1.0"
-#define DRIVER_RELDATE "June 2013"
+#define DRIVER_VERSION "2.2-1"
+#define DRIVER_RELDATE "Feb 2014"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library");
@@ -116,7 +116,6 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)
        struct mlx5_eq_table *table = &dev->priv.eq_table;
        int num_eqs = 1 << dev->caps.log_max_eq;
        int nvec;
-       int err;
        int i;
 
        nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE;
@@ -131,17 +130,12 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev)
        for (i = 0; i < nvec; i++)
                table->msix_arr[i].entry = i;
 
-retry:
-       table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
-       err = pci_enable_msix(dev->pdev, table->msix_arr, nvec);
-       if (err <= 0) {
-               return err;
-       } else if (err > 2) {
-               nvec = err;
-               goto retry;
-       }
+       nvec = pci_enable_msix_range(dev->pdev, table->msix_arr,
+                                    MLX5_EQ_VEC_COMP_BASE, nvec);
+       if (nvec < 0)
+               return nvec;
 
-       mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec);
+       table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE;
 
        return 0;
 }
@@ -537,7 +531,6 @@ static int __init init(void)
 
        return 0;
 
-       mlx5_health_cleanup();
 err_debug:
        mlx5_unregister_debugfs();
        return err;
index 727b546a9eb844c909dd8cd145aacfab014c9f99..e0c92e0e5e1d463f0242088d184394608b243cb6 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/eeprom_93cx6.h>
+#include <linux/regulator/consumer.h>
 
 #include <linux/spi/spi.h>
 
@@ -83,6 +84,7 @@ union ks8851_tx_hdr {
  * @rc_rxqcr: Cached copy of KS_RXQCR.
  * @eeprom_size: Companion eeprom size in Bytes, 0 if no eeprom
  * @eeprom: 93CX6 EEPROM state for accessing on-board EEPROM.
+ * @vdd_reg:   Optional regulator supplying the chip
  *
  * The @lock ensures that the chip is protected when certain operations are
  * in progress. When the read or write packet transfer is in progress, most
@@ -130,6 +132,7 @@ struct ks8851_net {
        struct spi_transfer     spi_xfer2[2];
 
        struct eeprom_93cx6     eeprom;
+       struct regulator        *vdd_reg;
 };
 
 static int msg_enable;
@@ -1414,6 +1417,21 @@ static int ks8851_probe(struct spi_device *spi)
        ks->spidev = spi;
        ks->tx_space = 6144;
 
+       ks->vdd_reg = regulator_get_optional(&spi->dev, "vdd");
+       if (IS_ERR(ks->vdd_reg)) {
+               ret = PTR_ERR(ks->vdd_reg);
+               if (ret == -EPROBE_DEFER)
+                       goto err_reg;
+       } else {
+               ret = regulator_enable(ks->vdd_reg);
+               if (ret) {
+                       dev_err(&spi->dev, "regulator enable fail: %d\n",
+                               ret);
+                       goto err_reg_en;
+               }
+       }
+
+
        mutex_init(&ks->lock);
        spin_lock_init(&ks->statelock);
 
@@ -1508,8 +1526,14 @@ static int ks8851_probe(struct spi_device *spi)
 err_netdev:
        free_irq(ndev->irq, ks);
 
-err_id:
 err_irq:
+err_id:
+       if (!IS_ERR(ks->vdd_reg))
+               regulator_disable(ks->vdd_reg);
+err_reg_en:
+       if (!IS_ERR(ks->vdd_reg))
+               regulator_put(ks->vdd_reg);
+err_reg:
        free_netdev(ndev);
        return ret;
 }
@@ -1523,6 +1547,10 @@ static int ks8851_remove(struct spi_device *spi)
 
        unregister_netdev(priv->netdev);
        free_irq(spi->irq, priv);
+       if (!IS_ERR(priv->vdd_reg)) {
+               regulator_disable(priv->vdd_reg);
+               regulator_put(priv->vdd_reg);
+       }
        free_netdev(priv->netdev);
 
        return 0;
index ce84dc289c8fe785ed62a948d6bbf1f37983d3c8..14ac0e2bc09fcbc50f65ceead949ecd7d15d6130 100644 (file)
@@ -4832,7 +4832,7 @@ static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb)
        skb->csum = old->csum;
        skb_set_network_header(skb, ETH_HLEN);
 
-       dev_kfree_skb(old);
+       dev_consume_skb_any(old);
 }
 
 /**
index 68026f7e8ba308d62c66570fb5ac7c19eb9f8994..130f6b204efa29cb9c97c98b4e3b0f52b569cd35 100644 (file)
@@ -2329,16 +2329,14 @@ static int myri10ge_request_irq(struct myri10ge_priv *mgp)
        status = 0;
        if (myri10ge_msi) {
                if (mgp->num_slices > 1) {
-                       status =
-                           pci_enable_msix(pdev, mgp->msix_vectors,
-                                           mgp->num_slices);
-                       if (status == 0) {
-                               mgp->msix_enabled = 1;
-                       } else {
+                       status = pci_enable_msix_range(pdev, mgp->msix_vectors,
+                                       mgp->num_slices, mgp->num_slices);
+                       if (status < 0) {
                                dev_err(&pdev->dev,
                                        "Error %d setting up MSI-X\n", status);
                                return status;
                        }
+                       mgp->msix_enabled = 1;
                }
                if (mgp->msix_enabled == 0) {
                        status = pci_enable_msi(pdev);
@@ -3895,32 +3893,34 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
        mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors),
                                    GFP_KERNEL);
        if (mgp->msix_vectors == NULL)
-               goto disable_msix;
+               goto no_msix;
        for (i = 0; i < mgp->num_slices; i++) {
                mgp->msix_vectors[i].entry = i;
        }
 
        while (mgp->num_slices > 1) {
-               /* make sure it is a power of two */
-               while (!is_power_of_2(mgp->num_slices))
-                       mgp->num_slices--;
+               mgp->num_slices = rounddown_pow_of_two(mgp->num_slices);
                if (mgp->num_slices == 1)
-                       goto disable_msix;
-               status = pci_enable_msix(pdev, mgp->msix_vectors,
-                                        mgp->num_slices);
-               if (status == 0) {
-                       pci_disable_msix(pdev);
+                       goto no_msix;
+               status = pci_enable_msix_range(pdev,
+                                              mgp->msix_vectors,
+                                              mgp->num_slices,
+                                              mgp->num_slices);
+               if (status < 0)
+                       goto no_msix;
+
+               pci_disable_msix(pdev);
+
+               if (status == mgp->num_slices) {
                        if (old_allocated)
                                kfree(old_fw);
                        return;
-               }
-               if (status > 0)
+               } else {
                        mgp->num_slices = status;
-               else
-                       goto disable_msix;
+               }
        }
 
-disable_msix:
+no_msix:
        if (mgp->msix_vectors != NULL) {
                kfree(mgp->msix_vectors);
                mgp->msix_vectors = NULL;
index 9eeddbd0b2c7c749de1c863e4b142c25f35c4fb9..a2844ff322c4c62bed8957a7f3797ad321359cbf 100644 (file)
@@ -2914,6 +2914,9 @@ static int rx_intr_handler(struct ring_info *ring_data, int budget)
        struct RxD1 *rxdp1;
        struct RxD3 *rxdp3;
 
+       if (budget <= 0)
+               return napi_pkts;
+
        get_info = ring_data->rx_curr_get_info;
        get_block = get_info.block_index;
        memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
@@ -3792,9 +3795,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
        writeq(rx_mat, &bar0->rx_mat);
        readq(&bar0->rx_mat);
 
-       ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries);
+       ret = pci_enable_msix_range(nic->pdev, nic->entries,
+                                   nic->num_entries, nic->num_entries);
        /* We fail init if error or we get less vectors than min required */
-       if (ret) {
+       if (ret < 0) {
                DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n");
                kfree(nic->entries);
                swstats->mem_freed += nic->num_entries *
@@ -4045,7 +4049,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!is_s2io_card_up(sp)) {
                DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
                          dev->name);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -4118,7 +4122,7 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
            ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) {
                DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
                s2io_stop_tx_queue(sp, fifo->fifo_no);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                spin_unlock_irqrestore(&fifo->tx_lock, flags);
                return NETDEV_TX_OK;
        }
@@ -4240,7 +4244,7 @@ pci_map_failed:
        swstats->pci_map_fail_cnt++;
        s2io_stop_tx_queue(sp, fifo->fifo_no);
        swstats->mem_freed += skb->truesize;
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        spin_unlock_irqrestore(&fifo->tx_lock, flags);
        return NETDEV_TX_OK;
 }
index 1ded50ca1600195d3ab46daf3d5689c152b3d5cc..d107bcbb8543035110a98a82a21a7e72c8ec1303 100644 (file)
@@ -368,6 +368,9 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
        vxge_debug_entryexit(VXGE_TRACE, "%s: %s:%d",
                ring->ndev->name, __func__, __LINE__);
 
+       if (ring->budget <= 0)
+               goto out;
+
        do {
                prefetch((char *)dtr + L1_CACHE_BYTES);
                rx_priv = vxge_hw_ring_rxd_private_get(dtr);
@@ -525,6 +528,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
        if (first_dtr)
                vxge_hw_ring_rxd_post_post_wmb(ringh, first_dtr);
 
+out:
        vxge_debug_entryexit(VXGE_TRACE,
                                "%s:%d  Exiting...",
                                __func__, __LINE__);
@@ -726,9 +730,6 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header)
        int vpath_idx = 0;
        enum vxge_hw_status status = VXGE_HW_OK;
        struct vxge_vpath *vpath = NULL;
-       struct __vxge_hw_device *hldev;
-
-       hldev = pci_get_drvdata(vdev->pdev);
 
        mac_address = (u8 *)&mac_addr;
        memcpy(mac_address, mac_header, ETH_ALEN);
@@ -823,7 +824,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(skb->len <= 0)) {
                vxge_debug_tx(VXGE_ERR,
                        "%s: Buffer has no data..", dev->name);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -832,7 +833,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
        if (unlikely(!is_vxge_card_up(vdev))) {
                vxge_debug_tx(VXGE_ERR,
                        "%s: vdev not initialized", dev->name);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
@@ -842,7 +843,7 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
                        vxge_debug_tx(VXGE_ERR,
                                "%s: Failed to store the mac address",
                                dev->name);
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        return NETDEV_TX_OK;
                }
        }
@@ -989,7 +990,7 @@ _exit1:
        vxge_hw_fifo_txdl_free(fifo_hw, dtr);
 _exit0:
        netif_tx_stop_queue(fifo->txq);
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
@@ -2352,12 +2353,18 @@ start:
        vdev->vxge_entries[j].entry = VXGE_ALARM_MSIX_ID;
        vdev->vxge_entries[j].in_use = 0;
 
-       ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt);
-       if (ret > 0) {
+       ret = pci_enable_msix_range(vdev->pdev,
+                                   vdev->entries, 3, vdev->intr_cnt);
+       if (ret < 0) {
+               ret = -ENODEV;
+               goto enable_msix_failed;
+       } else if (ret < vdev->intr_cnt) {
+               pci_disable_msix(vdev->pdev);
+
                vxge_debug_init(VXGE_ERR,
                        "%s: MSI-X enable failed for %d vectors, ret: %d",
                        VXGE_DRIVER_NAME, vdev->intr_cnt, ret);
-               if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) {
+               if (max_config_vpath != VXGE_USE_DEFAULT) {
                        ret = -ENODEV;
                        goto enable_msix_failed;
                }
@@ -2371,9 +2378,6 @@ start:
                vxge_close_vpaths(vdev, temp);
                vdev->no_of_vpath = temp;
                goto start;
-       } else if (ret < 0) {
-               ret = -ENODEV;
-               goto enable_msix_failed;
        }
        return 0;
 
@@ -2443,9 +2447,6 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev)
 
 static void vxge_rem_isr(struct vxgedev *vdev)
 {
-       struct __vxge_hw_device *hldev;
-       hldev = pci_get_drvdata(vdev->pdev);
-
 #ifdef CONFIG_PCI_MSI
        if (vdev->config.intr_type == MSI_X) {
                vxge_rem_msix_isr(vdev);
@@ -3137,12 +3138,12 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
                u64 packets, bytes, multicast;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&rxstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&rxstats->syncp);
 
                        packets   = rxstats->rx_frms;
                        multicast = rxstats->rx_mcast;
                        bytes     = rxstats->rx_bytes;
-               } while (u64_stats_fetch_retry_bh(&rxstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&rxstats->syncp, start));
 
                net_stats->rx_packets += packets;
                net_stats->rx_bytes += bytes;
@@ -3152,11 +3153,11 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
                net_stats->rx_dropped += rxstats->rx_dropped;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&txstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&txstats->syncp);
 
                        packets = txstats->tx_frms;
                        bytes   = txstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&txstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&txstats->syncp, start));
 
                net_stats->tx_packets += packets;
                net_stats->tx_bytes += bytes;
index 70cf97fe67f2d0e63439d8d684f0244a212caa22..fddb464aeab3a517c362d12ad4891eb3e2529cae 100644 (file)
@@ -1753,19 +1753,19 @@ nv_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *storage)
 
        /* software stats */
        do {
-               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_rx_syncp);
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_rx_syncp);
                storage->rx_packets       = np->stat_rx_packets;
                storage->rx_bytes         = np->stat_rx_bytes;
                storage->rx_dropped       = np->stat_rx_dropped;
                storage->rx_missed_errors = np->stat_rx_missed_errors;
-       } while (u64_stats_fetch_retry_bh(&np->swstats_rx_syncp, syncp_start));
+       } while (u64_stats_fetch_retry_irq(&np->swstats_rx_syncp, syncp_start));
 
        do {
-               syncp_start = u64_stats_fetch_begin_bh(&np->swstats_tx_syncp);
+               syncp_start = u64_stats_fetch_begin_irq(&np->swstats_tx_syncp);
                storage->tx_packets = np->stat_tx_packets;
                storage->tx_bytes   = np->stat_tx_bytes;
                storage->tx_dropped = np->stat_tx_dropped;
-       } while (u64_stats_fetch_retry_bh(&np->swstats_tx_syncp, syncp_start));
+       } while (u64_stats_fetch_retry_irq(&np->swstats_tx_syncp, syncp_start));
 
        /* If the nic supports hw counters then retrieve latest values */
        if (np->driver_data & DEV_HAS_STATISTICS_V123) {
@@ -2231,7 +2231,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                if (pci_dma_mapping_error(np->pci_dev,
                                          np->put_tx_ctx->dma)) {
                        /* on DMA mapping error - drop the packet */
-                       kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        u64_stats_update_begin(&np->swstats_tx_syncp);
                        np->stat_tx_dropped++;
                        u64_stats_update_end(&np->swstats_tx_syncp);
@@ -2277,7 +2277,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                        if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
                                                tmp_tx_ctx = np->first_tx_ctx;
                                } while (tmp_tx_ctx != np->put_tx_ctx);
-                               kfree_skb(skb);
+                               dev_kfree_skb_any(skb);
                                np->put_tx_ctx = start_tx_ctx;
                                u64_stats_update_begin(&np->swstats_tx_syncp);
                                np->stat_tx_dropped++;
@@ -2380,7 +2380,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                if (pci_dma_mapping_error(np->pci_dev,
                                          np->put_tx_ctx->dma)) {
                        /* on DMA mapping error - drop the packet */
-                       kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        u64_stats_update_begin(&np->swstats_tx_syncp);
                        np->stat_tx_dropped++;
                        u64_stats_update_end(&np->swstats_tx_syncp);
@@ -2427,7 +2427,7 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
                                        if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
                                                tmp_tx_ctx = np->first_tx_ctx;
                                } while (tmp_tx_ctx != np->put_tx_ctx);
-                               kfree_skb(skb);
+                               dev_kfree_skb_any(skb);
                                np->put_tx_ctx = start_tx_ctx;
                                u64_stats_update_begin(&np->swstats_tx_syncp);
                                np->stat_tx_dropped++;
@@ -3930,7 +3930,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
 {
        struct fe_priv *np = get_nvpriv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       int ret = 1;
+       int ret;
        int i;
        irqreturn_t (*handler)(int foo, void *data);
 
@@ -3946,14 +3946,18 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
        if (np->msi_flags & NV_MSI_X_CAPABLE) {
                for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++)
                        np->msi_x_entry[i].entry = i;
-               ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK));
-               if (ret == 0) {
+               ret = pci_enable_msix_range(np->pci_dev,
+                                           np->msi_x_entry,
+                                           np->msi_flags & NV_MSI_X_VECTORS_MASK,
+                                           np->msi_flags & NV_MSI_X_VECTORS_MASK);
+               if (ret > 0) {
                        np->msi_flags |= NV_MSI_X_ENABLED;
                        if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) {
                                /* Request irq for rx handling */
                                sprintf(np->name_rx, "%s-rx", dev->name);
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector,
-                                               nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) {
+                               ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector,
+                                                 nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev);
+                               if (ret) {
                                        netdev_info(dev,
                                                    "request_irq failed for rx %d\n",
                                                    ret);
@@ -3963,8 +3967,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                }
                                /* Request irq for tx handling */
                                sprintf(np->name_tx, "%s-tx", dev->name);
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector,
-                                               nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) {
+                               ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector,
+                                                 nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev);
+                               if (ret) {
                                        netdev_info(dev,
                                                    "request_irq failed for tx %d\n",
                                                    ret);
@@ -3974,8 +3979,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                }
                                /* Request irq for link and timer handling */
                                sprintf(np->name_other, "%s-other", dev->name);
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector,
-                                               nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) {
+                               ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector,
+                                                 nv_nic_irq_other, IRQF_SHARED, np->name_other, dev);
+                               if (ret) {
                                        netdev_info(dev,
                                                    "request_irq failed for link %d\n",
                                                    ret);
@@ -3991,7 +3997,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
                        } else {
                                /* Request irq for all interrupts */
-                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
+                               ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector,
+                                                 handler, IRQF_SHARED, dev->name, dev);
+                               if (ret) {
                                        netdev_info(dev,
                                                    "request_irq failed %d\n",
                                                    ret);
@@ -4005,13 +4013,15 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                writel(0, base + NvRegMSIXMap1);
                        }
                        netdev_info(dev, "MSI-X enabled\n");
+                       return 0;
                }
        }
-       if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
+       if (np->msi_flags & NV_MSI_CAPABLE) {
                ret = pci_enable_msi(np->pci_dev);
                if (ret == 0) {
                        np->msi_flags |= NV_MSI_ENABLED;
-                       if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
+                       ret = request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev);
+                       if (ret) {
                                netdev_info(dev, "request_irq failed %d\n",
                                            ret);
                                pci_disable_msi(np->pci_dev);
@@ -4025,13 +4035,12 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                        /* enable msi vector 0 */
                        writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
                        netdev_info(dev, "MSI enabled\n");
+                       return 0;
                }
        }
-       if (ret != 0) {
-               if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
-                       goto out_err;
 
-       }
+       if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
+               goto out_err;
 
        return 0;
 out_free_tx:
index 464e91058c81157da7fa8d3c25a03b266ed0ffe6..73e66838cfef901e276803b2a6d136fdbd20aa02 100644 (file)
@@ -120,10 +120,6 @@ static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg,
                               int data);
 static void pch_gbe_set_multi(struct net_device *netdev);
 
-static struct sock_filter ptp_filter[] = {
-       PTP_FILTER
-};
-
 static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
 {
        u8 *data = skb->data;
@@ -131,7 +127,7 @@ static int pch_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
        u16 *hi, *id;
        u32 lo;
 
-       if (sk_run_filter(skb, ptp_filter) == PTP_CLASS_NONE)
+       if (ptp_classify_raw(skb) == PTP_CLASS_NONE)
                return 0;
 
        offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
@@ -2635,11 +2631,6 @@ static int pch_gbe_probe(struct pci_dev *pdev,
 
        adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
                                               PCI_DEVFN(12, 4));
-       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
-               dev_err(&pdev->dev, "Bad ptp filter\n");
-               ret = -EINVAL;
-               goto err_free_netdev;
-       }
 
        netdev->netdev_ops = &pch_gbe_netdev_ops;
        netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
index 70849dea32b1306400822919ca0bd547339cbd4a..f09c35d669b3ec7d8898f96f0ffd9ce7362ddb13 100644 (file)
@@ -643,8 +643,9 @@ static int netxen_setup_msi_interrupts(struct netxen_adapter *adapter,
 
        if (adapter->msix_supported) {
                netxen_init_msix_entries(adapter, num_msix);
-               err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
-               if (err == 0) {
+               err = pci_enable_msix_range(pdev, adapter->msix_entries,
+                                           num_msix, num_msix);
+               if (err > 0) {
                        adapter->flags |= NETXEN_NIC_MSIX_ENABLED;
                        netxen_set_msix_bit(pdev, 1);
 
index f19f81cde134ba1ed37807b460dc7ad4015b7707..b9039b569bebf54bb2d82904c0c33f00f138abd1 100644 (file)
@@ -38,8 +38,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 55
-#define QLCNIC_LINUX_VERSIONID  "5.3.55"
+#define _QLCNIC_LINUX_SUBVERSION 57
+#define QLCNIC_LINUX_VERSIONID  "5.3.57"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
                 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -169,11 +169,20 @@ struct cmd_desc_type0 {
 
        __le64 addr_buffer2;
 
-       __le16 reference_handle;
+       __le16 encap_descr;     /* 15:10 offset of outer L3 header,
+                                * 9:6 number of 32bit words in outer L3 header,
+                                * 5 offload outer L4 checksum,
+                                * 4 offload outer L3 checksum,
+                                * 3 Inner L4 type, TCP=0, UDP=1,
+                                * 2 Inner L3 type, IPv4=0, IPv6=1,
+                                * 1 Outer L3 type,IPv4=0, IPv6=1,
+                                * 0 type of encapsulation, GRE=0, VXLAN=1
+                                */
        __le16 mss;
        u8 port_ctxid;          /* 7:4 ctxid 3:0 port */
-       u8 total_hdr_length;    /* LSO only : MAC+IP+TCP Hdr size */
-       __le16 conn_id;         /* IPSec offoad only */
+       u8 hdr_length;          /* LSO only : MAC+IP+TCP Hdr size */
+       u8 outer_hdr_length;    /* Encapsulation only */
+       u8 rsvd1;
 
        __le64 addr_buffer3;
        __le64 addr_buffer1;
@@ -183,7 +192,9 @@ struct cmd_desc_type0 {
        __le64 addr_buffer4;
 
        u8 eth_addr[ETH_ALEN];
-       __le16 vlan_TCI;
+       __le16 vlan_TCI;        /* In case of  encapsulation,
+                                * this is for outer VLAN
+                                */
 
 } __attribute__ ((aligned(64)));
 
@@ -394,7 +405,7 @@ struct qlcnic_nic_intr_coalesce {
        u32     timer_out;
 };
 
-struct qlcnic_dump_template_hdr {
+struct qlcnic_83xx_dump_template_hdr {
        u32     type;
        u32     offset;
        u32     size;
@@ -411,15 +422,42 @@ struct qlcnic_dump_template_hdr {
        u32     rsvd[0];
 };
 
+struct qlcnic_82xx_dump_template_hdr {
+       u32     type;
+       u32     offset;
+       u32     size;
+       u32     cap_mask;
+       u32     num_entries;
+       u32     version;
+       u32     timestamp;
+       u32     checksum;
+       u32     drv_cap_mask;
+       u32     sys_info[3];
+       u32     saved_state[16];
+       u32     cap_sizes[8];
+       u32     rsvd[7];
+       u32     capabilities;
+       u32     rsvd1[0];
+};
+
 struct qlcnic_fw_dump {
        u8      clr;    /* flag to indicate if dump is cleared */
        bool    enable; /* enable/disable dump */
        u32     size;   /* total size of the dump */
+       u32     cap_mask; /* Current capture mask */
        void    *data;  /* dump data area */
-       struct  qlcnic_dump_template_hdr *tmpl_hdr;
+       void    *tmpl_hdr;
        dma_addr_t phys_addr;
        void    *dma_buffer;
        bool    use_pex_dma;
+       /* Read only elements which are common between 82xx and 83xx
+        * template header. Update these values immediately after we read
+        * template header from Firmware
+        */
+       u32     tmpl_hdr_size;
+       u32     version;
+       u32     num_entries;
+       u32     offset;
 };
 
 /*
@@ -497,6 +535,7 @@ struct qlcnic_hardware_context {
        u8 extend_lb_time;
        u8 phys_port_id[ETH_ALEN];
        u8 lb_mode;
+       u16 vxlan_port;
 };
 
 struct qlcnic_adapter_stats {
@@ -511,6 +550,9 @@ struct qlcnic_adapter_stats {
        u64  txbytes;
        u64  lrobytes;
        u64  lso_frames;
+       u64  encap_lso_frames;
+       u64  encap_tx_csummed;
+       u64  encap_rx_csummed;
        u64  xmit_on;
        u64  xmit_off;
        u64  skb_alloc_failure;
@@ -872,6 +914,10 @@ struct qlcnic_mac_vlan_list {
 #define QLCNIC_FW_CAPABILITY_2_BEACON          BIT_7
 #define QLCNIC_FW_CAPABILITY_2_PER_PORT_ESWITCH_CFG    BIT_9
 
+#define QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD  BIT_0
+#define QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD  BIT_1
+#define QLCNIC_83XX_FW_CAPAB_ENCAP_CKO_OFFLOAD BIT_4
+
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT                   1
 #define LINKEVENT_MODULE_OPTICAL_UNKNOWN               2
@@ -965,6 +1011,8 @@ struct qlcnic_ipaddr {
 #define QLCNIC_APP_CHANGED_FLAGS       0x20000
 #define QLCNIC_HAS_PHYS_PORT_ID                0x40000
 #define QLCNIC_TSS_RSS                 0x80000
+#define QLCNIC_ADD_VXLAN_PORT          0x100000
+#define QLCNIC_DEL_VXLAN_PORT          0x200000
 
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
@@ -1769,10 +1817,28 @@ struct qlcnic_hardware_ops {
                                struct qlcnic_host_tx_ring *);
        void (*disable_tx_intr) (struct qlcnic_adapter *,
                                 struct qlcnic_host_tx_ring *);
+       u32 (*get_saved_state)(void *, u32);
+       void (*set_saved_state)(void *, u32, u32);
+       void (*cache_tmpl_hdr_values)(struct qlcnic_fw_dump *);
+       u32 (*get_cap_size)(void *, int);
+       void (*set_sys_info)(void *, int, u32);
+       void (*store_cap_mask)(void *, u32);
 };
 
 extern struct qlcnic_nic_template qlcnic_vf_ops;
 
+static inline bool qlcnic_encap_tx_offload(struct qlcnic_adapter *adapter)
+{
+       return adapter->ahw->extra_capability[0] &
+              QLCNIC_83XX_FW_CAPAB_ENCAP_TX_OFFLOAD;
+}
+
+static inline bool qlcnic_encap_rx_offload(struct qlcnic_adapter *adapter)
+{
+       return adapter->ahw->extra_capability[0] &
+              QLCNIC_83XX_FW_CAPAB_ENCAP_RX_OFFLOAD;
+}
+
 static inline int qlcnic_start_firmware(struct qlcnic_adapter *adapter)
 {
        return adapter->nic_ops->start_firmware(adapter);
@@ -2007,6 +2073,42 @@ static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter)
                adapter->ahw->hw_ops->read_phys_port_id(adapter);
 }
 
+static inline u32 qlcnic_get_saved_state(struct qlcnic_adapter *adapter,
+                                        void *t_hdr, u32 index)
+{
+       return adapter->ahw->hw_ops->get_saved_state(t_hdr, index);
+}
+
+static inline void qlcnic_set_saved_state(struct qlcnic_adapter *adapter,
+                                         void *t_hdr, u32 index, u32 value)
+{
+       adapter->ahw->hw_ops->set_saved_state(t_hdr, index, value);
+}
+
+static inline void qlcnic_cache_tmpl_hdr_values(struct qlcnic_adapter *adapter,
+                                               struct qlcnic_fw_dump *fw_dump)
+{
+       adapter->ahw->hw_ops->cache_tmpl_hdr_values(fw_dump);
+}
+
+static inline u32 qlcnic_get_cap_size(struct qlcnic_adapter *adapter,
+                                     void *tmpl_hdr, int index)
+{
+       return adapter->ahw->hw_ops->get_cap_size(tmpl_hdr, index);
+}
+
+static inline void qlcnic_set_sys_info(struct qlcnic_adapter *adapter,
+                                      void *tmpl_hdr, int idx, u32 value)
+{
+       adapter->ahw->hw_ops->set_sys_info(tmpl_hdr, idx, value);
+}
+
+static inline void qlcnic_store_cap_mask(struct qlcnic_adapter *adapter,
+                                        void *tmpl_hdr, u32 mask)
+{
+       adapter->ahw->hw_ops->store_cap_mask(tmpl_hdr, mask);
+}
+
 static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
                                            u32 key)
 {
index 4146664d4d6a43978789081713b858b3f982de0e..b7cffb46a75dbd8f215752218a6f1f4239c1cc98 100644 (file)
@@ -77,7 +77,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
        {QLCNIC_CMD_GET_PORT_CONFIG, 2, 2},
        {QLCNIC_CMD_GET_LINK_STATUS, 2, 4},
        {QLCNIC_CMD_IDC_ACK, 5, 1},
-       {QLCNIC_CMD_INIT_NIC_FUNC, 2, 1},
+       {QLCNIC_CMD_INIT_NIC_FUNC, 3, 1},
        {QLCNIC_CMD_STOP_NIC_FUNC, 2, 1},
        {QLCNIC_CMD_SET_LED_CONFIG, 5, 1},
        {QLCNIC_CMD_GET_LED_CONFIG, 1, 5},
@@ -87,6 +87,7 @@ static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
        {QLCNIC_CMD_BC_EVENT_SETUP, 2, 1},
        {QLCNIC_CMD_DCB_QUERY_CAP, 1, 2},
        {QLCNIC_CMD_DCB_QUERY_PARAM, 1, 50},
+       {QLCNIC_CMD_SET_INGRESS_ENCAP, 2, 1},
 };
 
 const u32 qlcnic_83xx_ext_reg_tbl[] = {
@@ -203,7 +204,12 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
        .disable_sds_intr               = qlcnic_83xx_disable_sds_intr,
        .enable_tx_intr                 = qlcnic_83xx_enable_tx_intr,
        .disable_tx_intr                = qlcnic_83xx_disable_tx_intr,
-
+       .get_saved_state                = qlcnic_83xx_get_saved_state,
+       .set_saved_state                = qlcnic_83xx_set_saved_state,
+       .cache_tmpl_hdr_values          = qlcnic_83xx_cache_tmpl_hdr_values,
+       .get_cap_size                   = qlcnic_83xx_get_cap_size,
+       .set_sys_info                   = qlcnic_83xx_set_sys_info,
+       .store_cap_mask                 = qlcnic_83xx_store_cap_mask,
 };
 
 static struct qlcnic_nic_template qlcnic_83xx_ops = {
@@ -340,6 +346,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter)
                        if (qlcnic_sriov_vf_check(adapter))
                                return -EINVAL;
                        num_msix = 1;
+                       adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
                        adapter->drv_tx_rings = QLCNIC_SINGLE_RING;
                }
        }
index f92485ca21d1131d989890f16f91a470847051c1..88d809c356334675026fb1a71e37107ded60c709 100644 (file)
@@ -308,6 +308,8 @@ struct qlc_83xx_reset {
 #define QLC_83XX_IDC_FLASH_PARAM_ADDR                  0x3e8020
 
 struct qlcnic_adapter;
+struct qlcnic_fw_dump;
+
 struct qlc_83xx_idc {
        int (*state_entry) (struct qlcnic_adapter *);
        u64             sec_counter;
@@ -526,8 +528,9 @@ enum qlc_83xx_ext_regs {
 };
 
 /* Initialize/Stop NIC command bit definitions */
-#define QLC_REGISTER_DCB_AEN           BIT_1
 #define QLC_REGISTER_LB_IDC            BIT_0
+#define QLC_REGISTER_DCB_AEN           BIT_1
+#define QLC_83XX_MULTI_TENANCY_INFO    BIT_29
 #define QLC_INIT_FW_RESOURCES          BIT_31
 
 /* 83xx funcitons */
@@ -650,4 +653,10 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *);
 void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *);
 int qlcnic_83xx_aer_reset(struct qlcnic_adapter *);
 void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *);
+u32 qlcnic_83xx_get_saved_state(void *, u32);
+void qlcnic_83xx_set_saved_state(void *, u32, u32);
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *);
+u32 qlcnic_83xx_get_cap_size(void *, int);
+void qlcnic_83xx_set_sys_info(void *, int, u32);
+void qlcnic_83xx_store_cap_mask(void *, u32);
 #endif
index 90a2dda351ec0eeba96930533402d5e6d098a2a8..2d91975d21f77323064b5b68fcc231981f33e6ad 100644 (file)
@@ -1020,10 +1020,97 @@ static int qlcnic_83xx_idc_check_state_validity(struct qlcnic_adapter *adapter,
        return 0;
 }
 
+#define QLC_83XX_ENCAP_TYPE_VXLAN      BIT_1
+#define QLC_83XX_MATCH_ENCAP_ID                BIT_2
+#define QLC_83XX_SET_VXLAN_UDP_DPORT   BIT_3
+#define QLC_83XX_VXLAN_UDP_DPORT(PORT) ((PORT & 0xffff) << 16)
+
+#define QLCNIC_ENABLE_INGRESS_ENCAP_PARSING 1
+#define QLCNIC_DISABLE_INGRESS_ENCAP_PARSING 0
+
+static int qlcnic_set_vxlan_port(struct qlcnic_adapter *adapter)
+{
+       u16 port = adapter->ahw->vxlan_port;
+       struct qlcnic_cmd_args cmd;
+       int ret = 0;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       ret = qlcnic_alloc_mbx_args(&cmd, adapter,
+                                   QLCNIC_CMD_INIT_NIC_FUNC);
+       if (ret)
+               return ret;
+
+       cmd.req.arg[1] = QLC_83XX_MULTI_TENANCY_INFO;
+       cmd.req.arg[2] = QLC_83XX_ENCAP_TYPE_VXLAN |
+                        QLC_83XX_SET_VXLAN_UDP_DPORT |
+                        QLC_83XX_VXLAN_UDP_DPORT(port);
+
+       ret = qlcnic_issue_cmd(adapter, &cmd);
+       if (ret)
+               netdev_err(adapter->netdev,
+                          "Failed to set VXLAN port %d in adapter\n",
+                          port);
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return ret;
+}
+
+static int qlcnic_set_vxlan_parsing(struct qlcnic_adapter *adapter,
+                                   bool state)
+{
+       u16 vxlan_port = adapter->ahw->vxlan_port;
+       struct qlcnic_cmd_args cmd;
+       int ret = 0;
+
+       memset(&cmd, 0, sizeof(cmd));
+
+       ret = qlcnic_alloc_mbx_args(&cmd, adapter,
+                                   QLCNIC_CMD_SET_INGRESS_ENCAP);
+       if (ret)
+               return ret;
+
+       cmd.req.arg[1] = state ? QLCNIC_ENABLE_INGRESS_ENCAP_PARSING :
+                                QLCNIC_DISABLE_INGRESS_ENCAP_PARSING;
+
+       ret = qlcnic_issue_cmd(adapter, &cmd);
+       if (ret)
+               netdev_err(adapter->netdev,
+                          "Failed to %s VXLAN parsing for port %d\n",
+                          state ? "enable" : "disable", vxlan_port);
+       else
+               netdev_info(adapter->netdev,
+                           "%s VXLAN parsing for port %d\n",
+                           state ? "Enabled" : "Disabled", vxlan_port);
+
+       qlcnic_free_mbx_args(&cmd);
+
+       return ret;
+}
+
 static void qlcnic_83xx_periodic_tasks(struct qlcnic_adapter *adapter)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
        if (adapter->fhash.fnum)
                qlcnic_prune_lb_filters(adapter);
+
+       if (adapter->flags & QLCNIC_ADD_VXLAN_PORT) {
+               if (qlcnic_set_vxlan_port(adapter))
+                       return;
+
+               if (qlcnic_set_vxlan_parsing(adapter, true))
+                       return;
+
+               adapter->flags &= ~QLCNIC_ADD_VXLAN_PORT;
+       } else if (adapter->flags & QLCNIC_DEL_VXLAN_PORT) {
+               if (qlcnic_set_vxlan_parsing(adapter, false))
+                       return;
+
+               ahw->vxlan_port = 0;
+               adapter->flags &= ~QLCNIC_DEL_VXLAN_PORT;
+       }
 }
 
 /**
@@ -1301,7 +1388,7 @@ static int qlcnic_83xx_copy_fw_file(struct qlcnic_adapter *adapter)
        addr = (u64)dest;
 
        ret = qlcnic_83xx_ms_mem_write128(adapter, addr,
-                                         (u32 *)p_cache, size / 16);
+                                         p_cache, size / 16);
        if (ret) {
                dev_err(&adapter->pdev->dev, "MS memory write failed\n");
                release_firmware(fw);
index 77f1bce432d2998b3d14b5b6f56c694a877a1ae6..7d4f54912bad526077b145109dc003e532b88d70 100644 (file)
@@ -807,7 +807,7 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio,
            !type->tc_param_valid)
                return;
 
-       if (tc < 0 || (tc > QLC_DCB_MAX_TC))
+       if (tc < 0 || (tc >= QLC_DCB_MAX_TC))
                return;
 
        tc_cfg = &type->tc_cfg[tc];
@@ -843,7 +843,7 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid,
            !type->tc_param_valid)
                return;
 
-       if (pgid < 0 || pgid > QLC_DCB_MAX_PG)
+       if (pgid < 0 || pgid >= QLC_DCB_MAX_PG)
                return;
 
        pgcfg = &type->pg_cfg[pgid];
index acee1a5d80c6521095c755418eb8c46197d9cec7..5bacf5210aed658abc12c639be38f0649bf96cbf 100644 (file)
@@ -47,6 +47,12 @@ static const struct qlcnic_stats qlcnic_gstrings_stats[] = {
        {"lro_pkts", QLC_SIZEOF(stats.lro_pkts), QLC_OFF(stats.lro_pkts)},
        {"lrobytes", QLC_SIZEOF(stats.lrobytes), QLC_OFF(stats.lrobytes)},
        {"lso_frames", QLC_SIZEOF(stats.lso_frames), QLC_OFF(stats.lso_frames)},
+       {"encap_lso_frames", QLC_SIZEOF(stats.encap_lso_frames),
+        QLC_OFF(stats.encap_lso_frames)},
+       {"encap_tx_csummed", QLC_SIZEOF(stats.encap_tx_csummed),
+        QLC_OFF(stats.encap_tx_csummed)},
+       {"encap_rx_csummed", QLC_SIZEOF(stats.encap_rx_csummed),
+        QLC_OFF(stats.encap_rx_csummed)},
        {"skb_alloc_failure", QLC_SIZEOF(stats.skb_alloc_failure),
         QLC_OFF(stats.skb_alloc_failure)},
        {"mac_filter_limit_overrun", QLC_SIZEOF(stats.mac_filter_limit_overrun),
@@ -1639,14 +1645,14 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
        }
 
        if (fw_dump->clr)
-               dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
+               dump->len = fw_dump->tmpl_hdr_size + fw_dump->size;
        else
                dump->len = 0;
 
        if (!qlcnic_check_fw_dump_state(adapter))
                dump->flag = ETH_FW_DUMP_DISABLE;
        else
-               dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+               dump->flag = fw_dump->cap_mask;
 
        dump->version = adapter->fw_version;
        return 0;
@@ -1671,9 +1677,10 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
                netdev_info(netdev, "Dump not available\n");
                return -EINVAL;
        }
+
        /* Copy template header first */
-       copy_sz = fw_dump->tmpl_hdr->size;
-       hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
+       copy_sz = fw_dump->tmpl_hdr_size;
+       hdr_ptr = (u32 *)fw_dump->tmpl_hdr;
        data = buffer;
        for (i = 0; i < copy_sz/sizeof(u32); i++)
                *data++ = cpu_to_le32(*hdr_ptr++);
@@ -1681,7 +1688,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
        /* Copy captured dump data */
        memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
        dump->len = copy_sz + fw_dump->size;
-       dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+       dump->flag = fw_dump->cap_mask;
 
        /* Free dump area once data has been captured */
        vfree(fw_dump->data);
@@ -1703,7 +1710,11 @@ static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask)
                return -EOPNOTSUPP;
        }
 
-       fw_dump->tmpl_hdr->drv_cap_mask = mask;
+       fw_dump->cap_mask = mask;
+
+       /* Store new capture mask in template header as well*/
+       qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask);
+
        netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask);
        return 0;
 }
index 03d18a0be6ce98cd8ab517d9623983de22a99672..9f3adf4e70b5f31a2d143c8d946ce6d88201a096 100644 (file)
@@ -317,9 +317,7 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
 int
 qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 {
-       int timeout = 0;
-       int err = 0;
-       u32 done = 0;
+       int timeout = 0, err = 0, done = 0;
 
        while (!done) {
                done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
@@ -327,10 +325,20 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
                if (done == 1)
                        break;
                if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
-                       dev_err(&adapter->pdev->dev,
-                               "Failed to acquire sem=%d lock; holdby=%d\n",
-                               sem,
-                               id_reg ? QLCRD32(adapter, id_reg, &err) : -1);
+                       if (id_reg) {
+                               done = QLCRD32(adapter, id_reg, &err);
+                               if (done != -1)
+                                       dev_err(&adapter->pdev->dev,
+                                               "Failed to acquire sem=%d lock held by=%d\n",
+                                               sem, done);
+                               else
+                                       dev_err(&adapter->pdev->dev,
+                                               "Failed to acquire sem=%d lock",
+                                               sem);
+                       } else {
+                               dev_err(&adapter->pdev->dev,
+                                       "Failed to acquire sem=%d lock", sem);
+                       }
                        return -EIO;
                }
                msleep(1);
index 63d75617d445a2de9c6e9d998cc58d1a105f7b16..cbe2399c30a0d11e9621bed426b9b45318187901 100644 (file)
@@ -98,6 +98,7 @@ enum qlcnic_regs {
 #define QLCNIC_CMD_GET_LINK_EVENT              0x48
 #define QLCNIC_CMD_CONFIGURE_MAC_RX_MODE       0x49
 #define QLCNIC_CMD_CONFIGURE_HW_LRO            0x4A
+#define QLCNIC_CMD_SET_INGRESS_ENCAP           0x4E
 #define QLCNIC_CMD_INIT_NIC_FUNC               0x60
 #define QLCNIC_CMD_STOP_NIC_FUNC               0x61
 #define QLCNIC_CMD_IDC_ACK                     0x63
@@ -161,6 +162,7 @@ struct qlcnic_host_sds_ring;
 struct qlcnic_host_tx_ring;
 struct qlcnic_hardware_context;
 struct qlcnic_adapter;
+struct qlcnic_fw_dump;
 
 int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *);
 int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
@@ -213,4 +215,11 @@ int qlcnic_82xx_shutdown(struct pci_dev *);
 int qlcnic_82xx_resume(struct qlcnic_adapter *);
 void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed);
 void qlcnic_fw_poll_work(struct work_struct *work);
+
+u32 qlcnic_82xx_get_saved_state(void *, u32);
+void qlcnic_82xx_set_saved_state(void *, u32, u32);
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *);
+u32 qlcnic_82xx_get_cap_size(void *, int);
+void qlcnic_82xx_set_sys_info(void *, int, u32);
+void qlcnic_82xx_store_cap_mask(void *, u32);
 #endif                         /* __QLCNIC_HW_H_ */
index 54ebf300332a353246066e5cf62f1d097355e1e5..173b3d12991f55a62751d5e6a213d20ee02c3174 100644 (file)
 
 #include "qlcnic.h"
 
-#define TX_ETHER_PKT   0x01
-#define TX_TCP_PKT     0x02
-#define TX_UDP_PKT     0x03
-#define TX_IP_PKT      0x04
-#define TX_TCP_LSO     0x05
-#define TX_TCP_LSO6    0x06
-#define TX_TCPV6_PKT   0x0b
-#define TX_UDPV6_PKT   0x0c
-#define FLAGS_VLAN_TAGGED      0x10
-#define FLAGS_VLAN_OOB         0x40
+#define QLCNIC_TX_ETHER_PKT            0x01
+#define QLCNIC_TX_TCP_PKT              0x02
+#define QLCNIC_TX_UDP_PKT              0x03
+#define QLCNIC_TX_IP_PKT               0x04
+#define QLCNIC_TX_TCP_LSO              0x05
+#define QLCNIC_TX_TCP_LSO6             0x06
+#define QLCNIC_TX_ENCAP_PKT            0x07
+#define QLCNIC_TX_ENCAP_LSO            0x08
+#define QLCNIC_TX_TCPV6_PKT            0x0b
+#define QLCNIC_TX_UDPV6_PKT            0x0c
+
+#define QLCNIC_FLAGS_VLAN_TAGGED       0x10
+#define QLCNIC_FLAGS_VLAN_OOB          0x40
 
 #define qlcnic_set_tx_vlan_tci(cmd_desc, v)    \
        (cmd_desc)->vlan_TCI = cpu_to_le16(v);
@@ -364,6 +367,101 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
        spin_unlock(&adapter->mac_learn_lock);
 }
 
+#define QLCNIC_ENCAP_VXLAN_PKT         BIT_0
+#define QLCNIC_ENCAP_OUTER_L3_IP6      BIT_1
+#define QLCNIC_ENCAP_INNER_L3_IP6      BIT_2
+#define QLCNIC_ENCAP_INNER_L4_UDP      BIT_3
+#define QLCNIC_ENCAP_DO_L3_CSUM                BIT_4
+#define QLCNIC_ENCAP_DO_L4_CSUM                BIT_5
+
+static int qlcnic_tx_encap_pkt(struct qlcnic_adapter *adapter,
+                              struct cmd_desc_type0 *first_desc,
+                              struct sk_buff *skb,
+                              struct qlcnic_host_tx_ring *tx_ring)
+{
+       u8 opcode = 0, inner_hdr_len = 0, outer_hdr_len = 0, total_hdr_len = 0;
+       int copied, copy_len, descr_size;
+       u32 producer = tx_ring->producer;
+       struct cmd_desc_type0 *hwdesc;
+       u16 flags = 0, encap_descr = 0;
+
+       opcode = QLCNIC_TX_ETHER_PKT;
+       encap_descr = QLCNIC_ENCAP_VXLAN_PKT;
+
+       if (skb_is_gso(skb)) {
+               inner_hdr_len = skb_inner_transport_header(skb) +
+                               inner_tcp_hdrlen(skb) -
+                               skb_inner_mac_header(skb);
+
+               /* VXLAN header size = 8 */
+               outer_hdr_len = skb_transport_offset(skb) + 8 +
+                               sizeof(struct udphdr);
+               first_desc->outer_hdr_length = outer_hdr_len;
+               total_hdr_len = inner_hdr_len + outer_hdr_len;
+               encap_descr |= QLCNIC_ENCAP_DO_L3_CSUM |
+                              QLCNIC_ENCAP_DO_L4_CSUM;
+               first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+               first_desc->hdr_length = inner_hdr_len;
+
+               /* Copy inner and outer headers in Tx descriptor(s)
+                * If total_hdr_len > cmd_desc_type0, use multiple
+                * descriptors
+                */
+               copied = 0;
+               descr_size = (int)sizeof(struct cmd_desc_type0);
+               while (copied < total_hdr_len) {
+                       copy_len = min(descr_size, (total_hdr_len - copied));
+                       hwdesc = &tx_ring->desc_head[producer];
+                       tx_ring->cmd_buf_arr[producer].skb = NULL;
+                       skb_copy_from_linear_data_offset(skb, copied,
+                                                        (char *)hwdesc,
+                                                        copy_len);
+                       copied += copy_len;
+                       producer = get_next_index(producer, tx_ring->num_desc);
+               }
+
+               tx_ring->producer = producer;
+
+               /* Make sure updated tx_ring->producer is visible
+                * for qlcnic_tx_avail()
+                */
+               smp_mb();
+               adapter->stats.encap_lso_frames++;
+
+               opcode = QLCNIC_TX_ENCAP_LSO;
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               if (inner_ip_hdr(skb)->version == 6) {
+                       if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+                               encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP;
+               } else {
+                       if (inner_ip_hdr(skb)->protocol == IPPROTO_UDP)
+                               encap_descr |= QLCNIC_ENCAP_INNER_L4_UDP;
+               }
+
+               adapter->stats.encap_tx_csummed++;
+               opcode = QLCNIC_TX_ENCAP_PKT;
+       }
+
+       /* Prepare first 16 bits of byte offset 16 of Tx descriptor */
+       if (ip_hdr(skb)->version == 6)
+               encap_descr |= QLCNIC_ENCAP_OUTER_L3_IP6;
+
+       /* outer IP header's size in 32bit words size*/
+       encap_descr |= (skb_network_header_len(skb) >> 2) << 6;
+
+       /* outer IP header offset */
+       encap_descr |= skb_network_offset(skb) << 10;
+       first_desc->encap_descr = cpu_to_le16(encap_descr);
+
+       first_desc->tcp_hdr_offset = skb_inner_transport_header(skb) -
+                                    skb->data;
+       first_desc->ip_hdr_offset = skb_inner_network_offset(skb);
+
+       qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+       return 0;
+}
+
 static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
                         struct cmd_desc_type0 *first_desc, struct sk_buff *skb,
                         struct qlcnic_host_tx_ring *tx_ring)
@@ -378,11 +476,11 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
 
        if (protocol == ETH_P_8021Q) {
                vh = (struct vlan_ethhdr *)skb->data;
-               flags = FLAGS_VLAN_TAGGED;
+               flags = QLCNIC_FLAGS_VLAN_TAGGED;
                vlan_tci = ntohs(vh->h_vlan_TCI);
                protocol = ntohs(vh->h_vlan_encapsulated_proto);
        } else if (vlan_tx_tag_present(skb)) {
-               flags = FLAGS_VLAN_OOB;
+               flags = QLCNIC_FLAGS_VLAN_OOB;
                vlan_tci = vlan_tx_tag_get(skb);
        }
        if (unlikely(adapter->tx_pvid)) {
@@ -391,7 +489,7 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
                if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
                        goto set_flags;
 
-               flags = FLAGS_VLAN_OOB;
+               flags = QLCNIC_FLAGS_VLAN_OOB;
                vlan_tci = adapter->tx_pvid;
        }
 set_flags:
@@ -402,25 +500,26 @@ set_flags:
                flags |= BIT_0;
                memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
        }
-       opcode = TX_ETHER_PKT;
+       opcode = QLCNIC_TX_ETHER_PKT;
        if (skb_is_gso(skb)) {
                hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
                first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
-               first_desc->total_hdr_length = hdr_len;
-               opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
+               first_desc->hdr_length = hdr_len;
+               opcode = (protocol == ETH_P_IPV6) ? QLCNIC_TX_TCP_LSO6 :
+                                                   QLCNIC_TX_TCP_LSO;
 
                /* For LSO, we need to copy the MAC/IP/TCP headers into
                * the descriptor ring */
                copied = 0;
                offset = 2;
 
-               if (flags & FLAGS_VLAN_OOB) {
-                       first_desc->total_hdr_length += VLAN_HLEN;
+               if (flags & QLCNIC_FLAGS_VLAN_OOB) {
+                       first_desc->hdr_length += VLAN_HLEN;
                        first_desc->tcp_hdr_offset = VLAN_HLEN;
                        first_desc->ip_hdr_offset = VLAN_HLEN;
 
                        /* Only in case of TSO on vlan device */
-                       flags |= FLAGS_VLAN_TAGGED;
+                       flags |= QLCNIC_FLAGS_VLAN_TAGGED;
 
                        /* Create a TSO vlan header template for firmware */
                        hwdesc = &tx_ring->desc_head[producer];
@@ -464,16 +563,16 @@ set_flags:
                        l4proto = ip_hdr(skb)->protocol;
 
                        if (l4proto == IPPROTO_TCP)
-                               opcode = TX_TCP_PKT;
+                               opcode = QLCNIC_TX_TCP_PKT;
                        else if (l4proto == IPPROTO_UDP)
-                               opcode = TX_UDP_PKT;
+                               opcode = QLCNIC_TX_UDP_PKT;
                } else if (protocol == ETH_P_IPV6) {
                        l4proto = ipv6_hdr(skb)->nexthdr;
 
                        if (l4proto == IPPROTO_TCP)
-                               opcode = TX_TCPV6_PKT;
+                               opcode = QLCNIC_TX_TCPV6_PKT;
                        else if (l4proto == IPPROTO_UDP)
-                               opcode = TX_UDPV6_PKT;
+                               opcode = QLCNIC_TX_UDPV6_PKT;
                }
        }
        first_desc->tcp_hdr_offset += skb_transport_offset(skb);
@@ -563,6 +662,8 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        struct ethhdr *phdr;
        int i, k, frag_count, delta = 0;
        u32 producer, num_txd;
+       u16 protocol;
+       bool l4_is_udp = false;
 
        if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
                netif_tx_stop_all_queues(netdev);
@@ -653,8 +754,23 @@ netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        tx_ring->producer = get_next_index(producer, num_txd);
        smp_mb();
 
-       if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb, tx_ring)))
-               goto unwind_buff;
+       protocol = ntohs(skb->protocol);
+       if (protocol == ETH_P_IP)
+               l4_is_udp = ip_hdr(skb)->protocol == IPPROTO_UDP;
+       else if (protocol == ETH_P_IPV6)
+               l4_is_udp = ipv6_hdr(skb)->nexthdr == IPPROTO_UDP;
+
+       /* Check if it is a VXLAN packet */
+       if (!skb->encapsulation || !l4_is_udp ||
+           !qlcnic_encap_tx_offload(adapter)) {
+               if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb,
+                                          tx_ring)))
+                       goto unwind_buff;
+       } else {
+               if (unlikely(qlcnic_tx_encap_pkt(adapter, first_desc,
+                                                skb, tx_ring)))
+                       goto unwind_buff;
+       }
 
        if (adapter->drv_mac_learn)
                qlcnic_send_filter(adapter, first_desc, skb);
@@ -1587,6 +1703,13 @@ static inline int qlcnic_83xx_is_lb_pkt(u64 sts_data, int lro_pkt)
                return (sts_data & QLC_83XX_NORMAL_LB_PKT) ? 1 : 0;
 }
 
+#define QLCNIC_ENCAP_LENGTH_MASK       0x7f
+
+static inline u8 qlcnic_encap_length(u64 sts_data)
+{
+       return sts_data & QLCNIC_ENCAP_LENGTH_MASK;
+}
+
 static struct qlcnic_rx_buffer *
 qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
                        struct qlcnic_host_sds_ring *sds_ring,
@@ -1637,6 +1760,12 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter,
 
        skb->protocol = eth_type_trans(skb, netdev);
 
+       if (qlcnic_encap_length(sts_data[1]) &&
+           skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               skb->encapsulation = 1;
+               adapter->stats.encap_rx_csummed++;
+       }
+
        if (vid != 0xffff)
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
 
index ba78c7481fa3432f32fd7d5a5e7c56b66423b801..79be451a3ffc4ef0b820d91a86e403ead3b27d6a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/aer.h>
 #include <linux/log2.h>
 #include <linux/pci.h>
+#include <net/vxlan.h>
 
 MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
 MODULE_LICENSE("GPL");
@@ -90,7 +91,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *);
 static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *);
 static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *,
                                                      pci_channel_state_t);
-
 static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_hardware_context *ahw = adapter->ahw;
@@ -462,6 +462,35 @@ static int qlcnic_get_phys_port_id(struct net_device *netdev,
        return 0;
 }
 
+static void qlcnic_add_vxlan_port(struct net_device *netdev,
+                                 sa_family_t sa_family, __be16 port)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       /* Adapter supports only one VXLAN port. Use very first port
+        * for enabling offload
+        */
+       if (!qlcnic_encap_rx_offload(adapter) || ahw->vxlan_port)
+               return;
+
+       ahw->vxlan_port = ntohs(port);
+       adapter->flags |= QLCNIC_ADD_VXLAN_PORT;
+}
+
+static void qlcnic_del_vxlan_port(struct net_device *netdev,
+                                 sa_family_t sa_family, __be16 port)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
+
+       if (!qlcnic_encap_rx_offload(adapter) || !ahw->vxlan_port ||
+           (ahw->vxlan_port != ntohs(port)))
+               return;
+
+       adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
+}
+
 static const struct net_device_ops qlcnic_netdev_ops = {
        .ndo_open          = qlcnic_open,
        .ndo_stop          = qlcnic_close,
@@ -480,6 +509,8 @@ static const struct net_device_ops qlcnic_netdev_ops = {
        .ndo_fdb_del            = qlcnic_fdb_del,
        .ndo_fdb_dump           = qlcnic_fdb_dump,
        .ndo_get_phys_port_id   = qlcnic_get_phys_port_id,
+       .ndo_add_vxlan_port     = qlcnic_add_vxlan_port,
+       .ndo_del_vxlan_port     = qlcnic_del_vxlan_port,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = qlcnic_poll_controller,
 #endif
@@ -561,6 +592,12 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = {
        .disable_sds_intr               = qlcnic_82xx_disable_sds_intr,
        .enable_tx_intr                 = qlcnic_82xx_enable_tx_intr,
        .disable_tx_intr                = qlcnic_82xx_disable_tx_intr,
+       .get_saved_state                = qlcnic_82xx_get_saved_state,
+       .set_saved_state                = qlcnic_82xx_set_saved_state,
+       .cache_tmpl_hdr_values          = qlcnic_82xx_cache_tmpl_hdr_values,
+       .get_cap_size                   = qlcnic_82xx_get_cap_size,
+       .set_sys_info                   = qlcnic_82xx_set_sys_info,
+       .store_cap_mask                 = qlcnic_82xx_store_cap_mask,
 };
 
 static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter)
@@ -684,7 +721,7 @@ restore:
 int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
 {
        struct pci_dev *pdev = adapter->pdev;
-       int err = -1, vector;
+       int err, vector;
 
        if (!adapter->msix_entries) {
                adapter->msix_entries = kcalloc(num_msix,
@@ -701,13 +738,17 @@ enable_msix:
                for (vector = 0; vector < num_msix; vector++)
                        adapter->msix_entries[vector].entry = vector;
 
-               err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
-               if (err == 0) {
+               err = pci_enable_msix_range(pdev,
+                                           adapter->msix_entries, 1, num_msix);
+
+               if (err == num_msix) {
                        adapter->flags |= QLCNIC_MSIX_ENABLED;
                        adapter->ahw->num_msix = num_msix;
                        dev_info(&pdev->dev, "using msi-x interrupts\n");
-                       return err;
+                       return 0;
                } else if (err > 0) {
+                       pci_disable_msix(pdev);
+
                        dev_info(&pdev->dev,
                                 "Unable to allocate %d MSI-X vectors, Available vectors %d\n",
                                 num_msix, err);
@@ -715,12 +756,12 @@ enable_msix:
                        if (qlcnic_82xx_check(adapter)) {
                                num_msix = rounddown_pow_of_two(err);
                                if (err < QLCNIC_82XX_MINIMUM_VECTOR)
-                                       return -EIO;
+                                       return -ENOSPC;
                        } else {
                                num_msix = rounddown_pow_of_two(err - 1);
                                num_msix += 1;
                                if (err < QLCNIC_83XX_MINIMUM_VECTOR)
-                                       return -EIO;
+                                       return -ENOSPC;
                        }
 
                        if (qlcnic_82xx_check(adapter) &&
@@ -747,7 +788,7 @@ enable_msix:
                }
        }
 
-       return err;
+       return -EIO;
 }
 
 static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter)
@@ -816,9 +857,10 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter)
 
                if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) {
                        qlcnic_disable_multi_tx(adapter);
+                       adapter->drv_sds_rings = QLCNIC_SINGLE_RING;
 
                        err = qlcnic_enable_msi_legacy(adapter);
-                       if (!err)
+                       if (err)
                                return err;
                }
        }
@@ -1933,6 +1975,9 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
 
        qlcnic_create_sysfs_entries(adapter);
 
+       if (qlcnic_encap_rx_offload(adapter))
+               vxlan_get_rx_port(netdev);
+
        adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
        return 0;
 
@@ -2195,6 +2240,19 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev,
        if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
                netdev->features |= NETIF_F_LRO;
 
+       if (qlcnic_encap_tx_offload(adapter)) {
+               netdev->features |= NETIF_F_GSO_UDP_TUNNEL;
+
+               /* encapsulation Tx offload supported by Adapter */
+               netdev->hw_enc_features = NETIF_F_IP_CSUM        |
+                                         NETIF_F_GSO_UDP_TUNNEL |
+                                         NETIF_F_TSO            |
+                                         NETIF_F_TSO6;
+       }
+
+       if (qlcnic_encap_rx_offload(adapter))
+               netdev->hw_enc_features |= NETIF_F_RXCSUM;
+
        netdev->hw_features = netdev->features;
        netdev->priv_flags |= IFF_UNICAST_FLT;
        netdev->irq = adapter->msix_entries[0].vector;
@@ -2441,8 +2499,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                if (err) {
                        switch (err) {
                        case -ENOTRECOVERABLE:
-                               dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware. Please reboot\n");
-                               dev_err(&pdev->dev, "If reboot doesn't help, please replace the adapter with new one and return the faulty adapter for repair\n");
+                               dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n");
+                               dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n");
                                goto err_out_free_hw;
                        case -ENOMEM:
                                dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n");
@@ -3863,7 +3921,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt,
                strcpy(buf, "Tx");
        }
 
-       if (!qlcnic_use_msi_x && !qlcnic_use_msi) {
+       if (!QLCNIC_IS_MSI_FAMILY(adapter)) {
                netdev_err(netdev, "No RSS/TSS support in INT-x mode\n");
                return -EINVAL;
        }
index 7763962e2ec4e9128ae22cf7b8ee694248d8058d..37b979b1266bc2e0aa552f84dd8a14a149c82665 100644 (file)
@@ -211,6 +211,107 @@ enum qlcnic_minidump_opcode {
        QLCNIC_DUMP_RDEND       = 255
 };
 
+inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index)
+{
+       struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+       return hdr->saved_state[index];
+}
+
+inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index,
+                                       u32 value)
+{
+       struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+       hdr->saved_state[index] = value;
+}
+
+void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
+{
+       struct qlcnic_82xx_dump_template_hdr *hdr;
+
+       hdr = fw_dump->tmpl_hdr;
+       fw_dump->tmpl_hdr_size = hdr->size;
+       fw_dump->version = hdr->version;
+       fw_dump->num_entries = hdr->num_entries;
+       fw_dump->offset = hdr->offset;
+
+       hdr->drv_cap_mask = hdr->cap_mask;
+       fw_dump->cap_mask = hdr->cap_mask;
+}
+
+inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index)
+{
+       struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+       return hdr->cap_sizes[index];
+}
+
+void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value)
+{
+       struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr;
+
+       hdr->sys_info[idx] = value;
+}
+
+void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask)
+{
+       struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr;
+
+       hdr->drv_cap_mask = mask;
+}
+
+inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index)
+{
+       struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+       return hdr->saved_state[index];
+}
+
+inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index,
+                                       u32 value)
+{
+       struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+       hdr->saved_state[index] = value;
+}
+
+void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump)
+{
+       struct qlcnic_83xx_dump_template_hdr *hdr;
+
+       hdr = fw_dump->tmpl_hdr;
+       fw_dump->tmpl_hdr_size = hdr->size;
+       fw_dump->version = hdr->version;
+       fw_dump->num_entries = hdr->num_entries;
+       fw_dump->offset = hdr->offset;
+
+       hdr->drv_cap_mask = hdr->cap_mask;
+       fw_dump->cap_mask = hdr->cap_mask;
+}
+
+inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index)
+{
+       struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+       return hdr->cap_sizes[index];
+}
+
+void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value)
+{
+       struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr;
+
+       hdr->sys_info[idx] = value;
+}
+
+void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask)
+{
+       struct qlcnic_83xx_dump_template_hdr *hdr;
+
+       hdr = tmpl_hdr;
+       hdr->drv_cap_mask = mask;
+}
+
 struct qlcnic_dump_operations {
        enum qlcnic_minidump_opcode opcode;
        u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
@@ -238,11 +339,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
 static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
                            struct qlcnic_dump_entry *entry, __le32 *buffer)
 {
+       void *hdr = adapter->ahw->fw_dump.tmpl_hdr;
+       struct __ctrl *ctr = &entry->region.ctrl;
        int i, k, timeout = 0;
-       u32 addr, data;
+       u32 addr, data, temp;
        u8 no_ops;
-       struct __ctrl *ctr = &entry->region.ctrl;
-       struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
 
        addr = ctr->addr;
        no_ops = ctr->no_ops;
@@ -285,29 +386,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
                                }
                                break;
                        case QLCNIC_DUMP_RD_SAVE:
-                               if (ctr->index_a)
-                                       addr = t_hdr->saved_state[ctr->index_a];
+                               temp = ctr->index_a;
+                               if (temp)
+                                       addr = qlcnic_get_saved_state(adapter,
+                                                                     hdr,
+                                                                     temp);
                                data = qlcnic_ind_rd(adapter, addr);
-                               t_hdr->saved_state[ctr->index_v] = data;
+                               qlcnic_set_saved_state(adapter, hdr,
+                                                      ctr->index_v, data);
                                break;
                        case QLCNIC_DUMP_WRT_SAVED:
-                               if (ctr->index_v)
-                                       data = t_hdr->saved_state[ctr->index_v];
+                               temp = ctr->index_v;
+                               if (temp)
+                                       data = qlcnic_get_saved_state(adapter,
+                                                                     hdr,
+                                                                     temp);
                                else
                                        data = ctr->val1;
-                               if (ctr->index_a)
-                                       addr = t_hdr->saved_state[ctr->index_a];
+
+                               temp = ctr->index_a;
+                               if (temp)
+                                       addr = qlcnic_get_saved_state(adapter,
+                                                                     hdr,
+                                                                     temp);
                                qlcnic_ind_wr(adapter, addr, data);
                                break;
                        case QLCNIC_DUMP_MOD_SAVE_ST:
-                               data = t_hdr->saved_state[ctr->index_v];
+                               data = qlcnic_get_saved_state(adapter, hdr,
+                                                             ctr->index_v);
                                data <<= ctr->shl_val;
                                data >>= ctr->shr_val;
                                if (ctr->val2)
                                        data &= ctr->val2;
                                data |= ctr->val3;
                                data += ctr->val1;
-                               t_hdr->saved_state[ctr->index_v] = data;
+                               qlcnic_set_saved_state(adapter, hdr,
+                                                      ctr->index_v, data);
                                break;
                        default:
                                dev_info(&adapter->pdev->dev,
@@ -544,7 +658,7 @@ out:
 static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter,
                                struct __mem *mem)
 {
-       struct qlcnic_dump_template_hdr *tmpl_hdr;
+       struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
        struct device *dev = &adapter->pdev->dev;
        u32 dma_no, dma_base_addr, temp_addr;
        int i, ret, dma_sts;
@@ -596,7 +710,7 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter,
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
        u32 temp, dma_base_addr, size = 0, read_size = 0;
        struct qlcnic_pex_dma_descriptor *dma_descr;
-       struct qlcnic_dump_template_hdr *tmpl_hdr;
+       struct qlcnic_83xx_dump_template_hdr *tmpl_hdr;
        struct device *dev = &adapter->pdev->dev;
        dma_addr_t dma_phys_addr;
        void *dma_buffer;
@@ -938,8 +1052,8 @@ static int
 qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter,
                                       struct qlcnic_cmd_args *cmd)
 {
-       struct qlcnic_dump_template_hdr tmp_hdr;
-       u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32);
+       struct qlcnic_83xx_dump_template_hdr tmp_hdr;
+       u32 size = sizeof(tmp_hdr) / sizeof(u32);
        int ret = 0;
 
        if (qlcnic_82xx_check(adapter))
@@ -1027,17 +1141,19 @@ free_mem:
        return err;
 }
 
+#define QLCNIC_TEMPLATE_VERSION (0x20001)
+
 int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
 {
-       int err;
-       u32 temp_size = 0;
-       u32 version, csum, *tmp_buf;
        struct qlcnic_hardware_context *ahw;
-       struct qlcnic_dump_template_hdr *tmpl_hdr;
+       struct qlcnic_fw_dump *fw_dump;
+       u32 version, csum, *tmp_buf;
        u8 use_flash_temp = 0;
+       u32 temp_size = 0;
+       int err;
 
        ahw = adapter->ahw;
-
+       fw_dump = &ahw->fw_dump;
        err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size,
                                               &use_flash_temp);
        if (err) {
@@ -1046,11 +1162,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
                return -EIO;
        }
 
-       ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
-       if (!ahw->fw_dump.tmpl_hdr)
+       fw_dump->tmpl_hdr = vzalloc(temp_size);
+       if (!fw_dump->tmpl_hdr)
                return -ENOMEM;
 
-       tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr;
+       tmp_buf = (u32 *)fw_dump->tmpl_hdr;
        if (use_flash_temp)
                goto flash_temp;
 
@@ -1065,8 +1181,8 @@ flash_temp:
                        dev_err(&adapter->pdev->dev,
                                "Failed to get minidump template header %d\n",
                                err);
-                       vfree(ahw->fw_dump.tmpl_hdr);
-                       ahw->fw_dump.tmpl_hdr = NULL;
+                       vfree(fw_dump->tmpl_hdr);
+                       fw_dump->tmpl_hdr = NULL;
                        return -EIO;
                }
        }
@@ -1076,21 +1192,22 @@ flash_temp:
        if (csum) {
                dev_err(&adapter->pdev->dev,
                        "Template header checksum validation failed\n");
-               vfree(ahw->fw_dump.tmpl_hdr);
-               ahw->fw_dump.tmpl_hdr = NULL;
+               vfree(fw_dump->tmpl_hdr);
+               fw_dump->tmpl_hdr = NULL;
                return -EIO;
        }
 
-       tmpl_hdr = ahw->fw_dump.tmpl_hdr;
-       tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
+       qlcnic_cache_tmpl_hdr_values(adapter, fw_dump);
+
        dev_info(&adapter->pdev->dev,
                 "Default minidump capture mask 0x%x\n",
-                tmpl_hdr->cap_mask);
+                fw_dump->cap_mask);
 
-       if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
-               ahw->fw_dump.use_pex_dma = true;
+       if (qlcnic_83xx_check(adapter) &&
+           (fw_dump->version & 0xfffff) >= QLCNIC_TEMPLATE_VERSION)
+               fw_dump->use_pex_dma = true;
        else
-               ahw->fw_dump.use_pex_dma = false;
+               fw_dump->use_pex_dma = false;
 
        qlcnic_enable_fw_dump_state(adapter);
 
@@ -1099,21 +1216,22 @@ flash_temp:
 
 int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 {
-       __le32 *buffer;
-       u32 ocm_window;
-       char mesg[64];
-       char *msg[] = {mesg, NULL};
-       int i, k, ops_cnt, ops_index, dump_size = 0;
-       u32 entry_offset, dump, no_entries, buf_offset = 0;
-       struct qlcnic_dump_entry *entry;
        struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
-       struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
        static const struct qlcnic_dump_operations *fw_dump_ops;
+       struct qlcnic_83xx_dump_template_hdr *hdr_83xx;
+       u32 entry_offset, dump, no_entries, buf_offset = 0;
+       int i, k, ops_cnt, ops_index, dump_size = 0;
        struct device *dev = &adapter->pdev->dev;
        struct qlcnic_hardware_context *ahw;
-       void *temp_buffer;
+       struct qlcnic_dump_entry *entry;
+       void *temp_buffer, *tmpl_hdr;
+       u32 ocm_window;
+       __le32 *buffer;
+       char mesg[64];
+       char *msg[] = {mesg, NULL};
 
        ahw = adapter->ahw;
+       tmpl_hdr = fw_dump->tmpl_hdr;
 
        /* Return if we don't have firmware dump template header */
        if (!tmpl_hdr)
@@ -1133,8 +1251,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
        netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n");
        /* Calculate the size for dump data area only */
        for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
-               if (i & tmpl_hdr->drv_cap_mask)
-                       dump_size += tmpl_hdr->cap_sizes[k];
+               if (i & fw_dump->cap_mask)
+                       dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k);
+
        if (!dump_size)
                return -EIO;
 
@@ -1144,10 +1263,10 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 
        buffer = fw_dump->data;
        fw_dump->size = dump_size;
-       no_entries = tmpl_hdr->num_entries;
-       entry_offset = tmpl_hdr->offset;
-       tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
-       tmpl_hdr->sys_info[1] = adapter->fw_version;
+       no_entries = fw_dump->num_entries;
+       entry_offset = fw_dump->offset;
+       qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION);
+       qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version);
 
        if (fw_dump->use_pex_dma) {
                temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE,
@@ -1163,16 +1282,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
                ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops);
                fw_dump_ops = qlcnic_fw_dump_ops;
        } else {
+               hdr_83xx = tmpl_hdr;
                ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops);
                fw_dump_ops = qlcnic_83xx_fw_dump_ops;
-               ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func];
-               tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
-               tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
+               ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func];
+               hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window;
+               hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func;
        }
 
        for (i = 0; i < no_entries; i++) {
-               entry = (void *)tmpl_hdr + entry_offset;
-               if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+               entry = tmpl_hdr + entry_offset;
+               if (!(entry->hdr.mask & fw_dump->cap_mask)) {
                        entry->hdr.flags |= QLCNIC_DUMP_SKIP;
                        entry_offset += entry->hdr.offset;
                        continue;
@@ -1209,8 +1329,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
 
        fw_dump->clr = 1;
        snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name);
-       dev_info(dev, "%s: Dump data %d bytes captured, template header size %d bytes\n",
-                adapter->netdev->name, fw_dump->size, tmpl_hdr->size);
+       netdev_info(adapter->netdev,
+                   "Dump data %d bytes captured, template header size %d bytes\n",
+                   fw_dump->size, fw_dump->tmpl_hdr_size);
        /* Send a udev event to notify availability of FW dump */
        kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg);
 
index 09acf15c3a564d1482a6e40960c6ef8dafa6f1cc..14f748cbf0deeb8cd4c6ccfa3039d08764ee1142 100644 (file)
 #define QLC_VF_MIN_TX_RATE     100
 #define QLC_VF_MAX_TX_RATE     9999
 #define QLC_MAC_OPCODE_MASK    0x7
-#define QLC_MAC_STAR_ADD       6
-#define QLC_MAC_STAR_DEL       7
 #define QLC_VF_FLOOD_BIT       BIT_16
 #define QLC_FLOOD_MODE         0x5
+#define QLC_SRIOV_ALLOW_VLAN0  BIT_19
 
 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
 
@@ -337,8 +336,11 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,
                return err;
 
        cmd.req.arg[1] = 0x4;
-       if (enable)
+       if (enable) {
                cmd.req.arg[1] |= BIT_16;
+               if (qlcnic_84xx_check(adapter))
+                       cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0;
+       }
 
        err = qlcnic_issue_cmd(adapter, &cmd);
        if (err)
@@ -1206,13 +1208,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter,
        struct qlcnic_vport *vp = vf->vp;
        u8 op, new_op;
 
-       if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) ||
-           ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) {
-               netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n",
-                          vf->pci_func);
-               return -EINVAL;
-       }
-
        if (!(cmd->req.arg[1] & BIT_8))
                return -EINVAL;
 
index 3d64113a35af60428a0abfc0d02a0f8bd0f7a918..448d156c3d0804da56c2633113d3a7ef04b8e683 100644 (file)
@@ -350,33 +350,15 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
        return size;
 }
 
-static u32 qlcnic_get_pci_func_count(struct qlcnic_adapter *adapter)
-{
-       struct qlcnic_hardware_context *ahw = adapter->ahw;
-       u32 count = 0;
-
-       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
-               return ahw->total_nic_func;
-
-       if (ahw->total_pci_func <= QLC_DEFAULT_VNIC_COUNT)
-               count = QLC_DEFAULT_VNIC_COUNT;
-       else
-               count = ahw->max_vnic_func;
-
-       return count;
-}
-
 int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func)
 {
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        int i;
 
-       for (i = 0; i < pci_func_count; i++) {
+       for (i = 0; i < adapter->ahw->max_vnic_func; i++) {
                if (adapter->npars[i].pci_func == pci_func)
                        return i;
        }
-
-       return -1;
+       return -EINVAL;
 }
 
 static int validate_pm_config(struct qlcnic_adapter *adapter,
@@ -464,23 +446,21 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_pm_func_cfg *pm_cfg;
-       int i, pm_cfg_size;
        u8 pci_func;
+       u32 count;
+       int i;
 
-       pm_cfg_size = pci_func_count * sizeof(*pm_cfg);
-       if (size != pm_cfg_size)
-               return QL_STATUS_INVALID_PARAM;
-
-       memset(buf, 0, pm_cfg_size);
+       memset(buf, 0, size);
        pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
-
-       for (i = 0; i < pci_func_count; i++) {
+       count = size / sizeof(struct qlcnic_pm_func_cfg);
+       for (i = 0; i < adapter->ahw->total_nic_func; i++) {
                pci_func = adapter->npars[i].pci_func;
-               if (!adapter->npars[i].active)
+               if (pci_func >= count) {
+                       dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+                               __func__, adapter->ahw->total_nic_func, count);
                        continue;
-
+               }
                if (!adapter->npars[i].eswitch_status)
                        continue;
 
@@ -494,7 +474,6 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
 static int validate_esw_config(struct qlcnic_adapter *adapter,
                               struct qlcnic_esw_func_cfg *esw_cfg, int count)
 {
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        int i, ret;
        u32 op_mode;
@@ -507,7 +486,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter,
 
        for (i = 0; i < count; i++) {
                pci_func = esw_cfg[i].pci_func;
-               if (pci_func >= pci_func_count)
+               if (pci_func >= ahw->max_vnic_func)
                        return QL_STATUS_INVALID_PARAM;
 
                if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC)
@@ -642,23 +621,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_esw_func_cfg *esw_cfg;
-       size_t esw_cfg_size;
-       u8 i, pci_func;
-
-       esw_cfg_size = pci_func_count * sizeof(*esw_cfg);
-       if (size != esw_cfg_size)
-               return QL_STATUS_INVALID_PARAM;
+       u8 pci_func;
+       u32 count;
+       int i;
 
-       memset(buf, 0, esw_cfg_size);
+       memset(buf, 0, size);
        esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
-
-       for (i = 0; i < pci_func_count; i++) {
+       count = size / sizeof(struct qlcnic_esw_func_cfg);
+       for (i = 0; i < adapter->ahw->total_nic_func; i++) {
                pci_func = adapter->npars[i].pci_func;
-               if (!adapter->npars[i].active)
+               if (pci_func >= count) {
+                       dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+                               __func__, adapter->ahw->total_nic_func, count);
                        continue;
-
+               }
                if (!adapter->npars[i].eswitch_status)
                        continue;
 
@@ -741,23 +718,24 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_npar_func_cfg *np_cfg;
        struct qlcnic_info nic_info;
-       size_t np_cfg_size;
        int i, ret;
-
-       np_cfg_size = pci_func_count * sizeof(*np_cfg);
-       if (size != np_cfg_size)
-               return QL_STATUS_INVALID_PARAM;
+       u32 count;
 
        memset(&nic_info, 0, sizeof(struct qlcnic_info));
-       memset(buf, 0, np_cfg_size);
+       memset(buf, 0, size);
        np_cfg = (struct qlcnic_npar_func_cfg *)buf;
 
-       for (i = 0; i < pci_func_count; i++) {
+       count = size / sizeof(struct qlcnic_npar_func_cfg);
+       for (i = 0; i < adapter->ahw->total_nic_func; i++) {
                if (qlcnic_is_valid_nic_func(adapter, i) < 0)
                        continue;
+               if (adapter->npars[i].pci_func >= count) {
+                       dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n",
+                               __func__, adapter->ahw->total_nic_func, count);
+                       continue;
+               }
                ret = qlcnic_get_nic_info(adapter, &nic_info, i);
                if (ret)
                        return ret;
@@ -783,7 +761,6 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_esw_statistics port_stats;
        int ret;
 
@@ -793,7 +770,7 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
        if (size != sizeof(struct qlcnic_esw_statistics))
                return QL_STATUS_INVALID_PARAM;
 
-       if (offset >= pci_func_count)
+       if (offset >= adapter->ahw->max_vnic_func)
                return QL_STATUS_INVALID_PARAM;
 
        memset(&port_stats, 0, size);
@@ -884,13 +861,12 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
 
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        int ret;
 
        if (qlcnic_83xx_check(adapter))
                return QLC_STATUS_UNSUPPORTED_CMD;
 
-       if (offset >= pci_func_count)
+       if (offset >= adapter->ahw->max_vnic_func)
                return QL_STATUS_INVALID_PARAM;
 
        ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
@@ -914,17 +890,12 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
 {
        struct device *dev = container_of(kobj, struct device, kobj);
        struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-       u32 pci_func_count = qlcnic_get_pci_func_count(adapter);
        struct qlcnic_pci_func_cfg *pci_cfg;
        struct qlcnic_pci_info *pci_info;
-       size_t pci_cfg_sz;
        int i, ret;
+       u32 count;
 
-       pci_cfg_sz = pci_func_count * sizeof(*pci_cfg);
-       if (size != pci_cfg_sz)
-               return QL_STATUS_INVALID_PARAM;
-
-       pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL);
+       pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL);
        if (!pci_info)
                return -ENOMEM;
 
@@ -935,7 +906,8 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
        }
 
        pci_cfg = (struct qlcnic_pci_func_cfg *)buf;
-       for (i = 0; i < pci_func_count; i++) {
+       count = size / sizeof(struct qlcnic_pci_func_cfg);
+       for (i = 0; i < count; i++) {
                pci_cfg[i].pci_func = pci_info[i].id;
                pci_cfg[i].func_type = pci_info[i].type;
                pci_cfg[i].func_state = 0;
index ce2cfddbed504c1b960e32bc87691ff6965a1fce..0a1d76acab8171929e3c6f9ad6139b48484ebbcc 100644 (file)
@@ -2556,11 +2556,10 @@ static int ql_tso(struct sk_buff *skb, struct ob_mac_tso_iocb_req *mac_iocb_ptr)
 
        if (skb_is_gso(skb)) {
                int err;
-               if (skb_header_cloned(skb)) {
-                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
-                       if (err)
-                               return err;
-               }
+
+               err = skb_cow_head(skb, 0);
+               if (err < 0)
+                       return err;
 
                mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
                mac_iocb_ptr->flags3 |= OB_MAC_TSO_IOCB_IC;
@@ -3331,24 +3330,16 @@ static void ql_enable_msix(struct ql_adapter *qdev)
                for (i = 0; i < qdev->intr_count; i++)
                        qdev->msi_x_entry[i].entry = i;
 
-               /* Loop to get our vectors.  We start with
-                * what we want and settle for what we get.
-                */
-               do {
-                       err = pci_enable_msix(qdev->pdev,
-                               qdev->msi_x_entry, qdev->intr_count);
-                       if (err > 0)
-                               qdev->intr_count = err;
-               } while (err > 0);
-
+               err = pci_enable_msix_range(qdev->pdev, qdev->msi_x_entry,
+                                           1, qdev->intr_count);
                if (err < 0) {
                        kfree(qdev->msi_x_entry);
                        qdev->msi_x_entry = NULL;
                        netif_warn(qdev, ifup, qdev->ndev,
                                   "MSI-X Enable failed, trying MSI.\n");
-                       qdev->intr_count = 1;
                        qlge_irq_type = MSI_IRQ;
-               } else if (err == 0) {
+               } else {
+                       qdev->intr_count = err;
                        set_bit(QL_MSIX_ENABLED, &qdev->flags);
                        netif_info(qdev, ifup, qdev->ndev,
                                   "MSI-X Enabled, got %d vectors.\n",
@@ -4765,7 +4756,9 @@ static int qlge_probe(struct pci_dev *pdev,
        ndev->features = ndev->hw_features;
        ndev->vlan_features = ndev->hw_features;
        /* vlan gets same features (except vlan filter) */
-       ndev->vlan_features &= ~NETIF_F_HW_VLAN_CTAG_FILTER;
+       ndev->vlan_features &= ~(NETIF_F_HW_VLAN_CTAG_FILTER |
+                                NETIF_F_HW_VLAN_CTAG_TX |
+                                NETIF_F_HW_VLAN_CTAG_RX);
 
        if (test_bit(QL_DMA64, &qdev->flags))
                ndev->features |= NETIF_F_HIGHDMA;
index 819b74cefd64653d4bad2dfe18971dfd64744f59..cd045ecb9816d90e32cb086d5ef36f5a67749548 100644 (file)
@@ -270,11 +270,6 @@ static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
        return r6040_phy_write(ioaddr, phy_addr, reg, value);
 }
 
-static int r6040_mdiobus_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static void r6040_free_txbufs(struct net_device *dev)
 {
        struct r6040_private *lp = netdev_priv(dev);
@@ -1191,7 +1186,6 @@ static int r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        lp->mii_bus->priv = dev;
        lp->mii_bus->read = r6040_mdiobus_read;
        lp->mii_bus->write = r6040_mdiobus_write;
-       lp->mii_bus->reset = r6040_mdiobus_reset;
        lp->mii_bus->name = "r6040_eth_mii";
        snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
                dev_name(&pdev->dev), card_idx);
index 737c1a881f781917061d8b39ad43762f62ee7a6e..2bc728e65e245424e34f69797d841f5b60af4d5c 100644 (file)
@@ -476,7 +476,7 @@ rx_status_loop:
        rx = 0;
        cpw16(IntrStatus, cp_rx_intr_mask);
 
-       while (1) {
+       while (rx < budget) {
                u32 status, len;
                dma_addr_t mapping, new_mapping;
                struct sk_buff *skb, *new_skb;
@@ -554,9 +554,6 @@ rx_next:
                else
                        desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
                rx_tail = NEXT_RX(rx_tail);
-
-               if (rx >= budget)
-                       break;
        }
 
        cp->rx_tail = rx_tail;
@@ -899,7 +896,7 @@ out_unlock:
 
        return NETDEV_TX_OK;
 out_dma_error:
-       kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        cp->dev->stats.tx_dropped++;
        goto out_unlock;
 }
index da5972eefdd2bfc5d702fd553cf68b91c5485fb5..2e5df148af4c7d6fa36c33f7543ef5c758db9368 100644 (file)
@@ -1717,9 +1717,9 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb,
                if (len < ETH_ZLEN)
                        memset(tp->tx_buf[entry], 0, ETH_ZLEN);
                skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
        } else {
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                dev->stats.tx_dropped++;
                return NETDEV_TX_OK;
        }
@@ -2522,16 +2522,16 @@ rtl8139_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        netdev_stats_to_stats64(stats, &dev->stats);
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp);
                stats->rx_packets = tp->rx_stats.packets;
                stats->rx_bytes = tp->rx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start));
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp);
                stats->tx_packets = tp->tx_stats.packets;
                stats->tx_bytes = tp->tx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start));
 
        return stats;
 }
index 91a67ae8f17b9bffc5bf86405a5788055b583ba0..aa1c079f231dc6f2cfc017cd4950f9ebb8e1e9da 100644 (file)
@@ -209,7 +209,7 @@ static const struct {
        [RTL_GIGA_MAC_VER_16] =
                _R("RTL8101e",          RTL_TD_0, NULL, JUMBO_1K, true),
        [RTL_GIGA_MAC_VER_17] =
-               _R("RTL8168b/8111b",    RTL_TD_1, NULL, JUMBO_4K, false),
+               _R("RTL8168b/8111b",    RTL_TD_0, NULL, JUMBO_4K, false),
        [RTL_GIGA_MAC_VER_18] =
                _R("RTL8168cp/8111cp",  RTL_TD_1, NULL, JUMBO_6K, false),
        [RTL_GIGA_MAC_VER_19] =
@@ -5834,7 +5834,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start,
                                             tp->TxDescArray + entry);
                        if (skb) {
                                tp->dev->stats.tx_dropped++;
-                               dev_kfree_skb(skb);
+                               dev_kfree_skb_any(skb);
                                tx_skb->skb = NULL;
                        }
                }
@@ -6059,7 +6059,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
 err_dma_1:
        rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
 err_dma_0:
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
 err_update_stats:
        dev->stats.tx_dropped++;
        return NETDEV_TX_OK;
@@ -6142,7 +6142,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp)
                        tp->tx_stats.packets++;
                        tp->tx_stats.bytes += tx_skb->skb->len;
                        u64_stats_update_end(&tp->tx_stats.syncp);
-                       dev_kfree_skb(tx_skb->skb);
+                       dev_kfree_skb_any(tx_skb->skb);
                        tx_skb->skb = NULL;
                }
                dirty_tx++;
@@ -6590,17 +6590,17 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                rtl8169_rx_missed(dev, ioaddr);
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->rx_stats.syncp);
                stats->rx_packets = tp->rx_stats.packets;
                stats->rx_bytes = tp->rx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start));
 
 
        do {
-               start = u64_stats_fetch_begin_bh(&tp->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp);
                stats->tx_packets = tp->tx_stats.packets;
                stats->tx_bytes = tp->tx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&tp->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&tp->tx_stats.syncp, start));
 
        stats->rx_dropped       = dev->stats.rx_dropped;
        stats->tx_dropped       = dev->stats.tx_dropped;
@@ -7118,6 +7118,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        mutex_init(&tp->wk.mutex);
+       u64_stats_init(&tp->rx_stats.syncp);
+       u64_stats_init(&tp->tx_stats.syncp);
 
        /* Get MAC address */
        for (i = 0; i < ETH_ALEN; i++)
index 040cb94e8219cf8438dd2017164fca8387be45db..6a9509ccd33b29dd84ddcd0b48269f1c24b8da63 100644 (file)
@@ -1,8 +1,9 @@
 /*  SuperH Ethernet device driver
  *
  *  Copyright (C) 2006-2012 Nobuhiro Iwamatsu
- *  Copyright (C) 2008-2013 Renesas Solutions Corp.
- *  Copyright (C) 2013 Cogent Embedded, Inc.
+ *  Copyright (C) 2008-2014 Renesas Solutions Corp.
+ *  Copyright (C) 2013-2014 Cogent Embedded, Inc.
+ *  Copyright (C) 2014 Codethink Limited
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  under the terms and conditions of the GNU General Public License,
 #include <linux/platform_device.h>
 #include <linux/mdio-bitbang.h>
 #include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
 #include <linux/phy.h>
 #include <linux/cache.h>
 #include <linux/io.h>
@@ -36,6 +41,7 @@
 #include <linux/if_vlan.h>
 #include <linux/clk.h>
 #include <linux/sh_eth.h>
+#include <linux/of_mdio.h>
 
 #include "sh_eth.h"
 
@@ -394,7 +400,8 @@ static void sh_eth_select_mii(struct net_device *ndev)
                value = 0x0;
                break;
        default:
-               pr_warn("PHY interface mode was not setup. Set to MII.\n");
+               netdev_warn(ndev,
+                           "PHY interface mode was not setup. Set to MII.\n");
                value = 0x1;
                break;
        }
@@ -848,7 +855,7 @@ static int sh_eth_check_reset(struct net_device *ndev)
                cnt--;
        }
        if (cnt <= 0) {
-               pr_err("Device reset failed\n");
+               netdev_err(ndev, "Device reset failed\n");
                ret = -ETIMEDOUT;
        }
        return ret;
@@ -866,7 +873,7 @@ static int sh_eth_reset(struct net_device *ndev)
 
                ret = sh_eth_check_reset(ndev);
                if (ret)
-                       goto out;
+                       return ret;
 
                /* Table Init */
                sh_eth_write(ndev, 0x0, TDLAR);
@@ -893,7 +900,6 @@ static int sh_eth_reset(struct net_device *ndev)
                             EDMR);
        }
 
-out:
        return ret;
 }
 
@@ -1257,7 +1263,7 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
        /* Soft Reset */
        ret = sh_eth_reset(ndev);
        if (ret)
-               goto out;
+               return ret;
 
        if (mdp->cd->rmiimode)
                sh_eth_write(ndev, 0x1, RMIIMODE);
@@ -1336,7 +1342,6 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
                netif_start_queue(ndev);
        }
 
-out:
        return ret;
 }
 
@@ -1550,8 +1555,7 @@ ignore_link:
                /* Unused write back interrupt */
                if (intr_status & EESR_TABT) {  /* Transmit Abort int */
                        ndev->stats.tx_aborted_errors++;
-                       if (netif_msg_tx_err(mdp))
-                               dev_err(&ndev->dev, "Transmit Abort\n");
+                       netif_err(mdp, tx_err, ndev, "Transmit Abort\n");
                }
        }
 
@@ -1560,45 +1564,38 @@ ignore_link:
                if (intr_status & EESR_RFRMER) {
                        /* Receive Frame Overflow int */
                        ndev->stats.rx_frame_errors++;
-                       if (netif_msg_rx_err(mdp))
-                               dev_err(&ndev->dev, "Receive Abort\n");
+                       netif_err(mdp, rx_err, ndev, "Receive Abort\n");
                }
        }
 
        if (intr_status & EESR_TDE) {
                /* Transmit Descriptor Empty int */
                ndev->stats.tx_fifo_errors++;
-               if (netif_msg_tx_err(mdp))
-                       dev_err(&ndev->dev, "Transmit Descriptor Empty\n");
+               netif_err(mdp, tx_err, ndev, "Transmit Descriptor Empty\n");
        }
 
        if (intr_status & EESR_TFE) {
                /* FIFO under flow */
                ndev->stats.tx_fifo_errors++;
-               if (netif_msg_tx_err(mdp))
-                       dev_err(&ndev->dev, "Transmit FIFO Under flow\n");
+               netif_err(mdp, tx_err, ndev, "Transmit FIFO Under flow\n");
        }
 
        if (intr_status & EESR_RDE) {
                /* Receive Descriptor Empty int */
                ndev->stats.rx_over_errors++;
-
-               if (netif_msg_rx_err(mdp))
-                       dev_err(&ndev->dev, "Receive Descriptor Empty\n");
+               netif_err(mdp, rx_err, ndev, "Receive Descriptor Empty\n");
        }
 
        if (intr_status & EESR_RFE) {
                /* Receive FIFO Overflow int */
                ndev->stats.rx_fifo_errors++;
-               if (netif_msg_rx_err(mdp))
-                       dev_err(&ndev->dev, "Receive FIFO Overflow\n");
+               netif_err(mdp, rx_err, ndev, "Receive FIFO Overflow\n");
        }
 
        if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) {
                /* Address Error */
                ndev->stats.tx_fifo_errors++;
-               if (netif_msg_tx_err(mdp))
-                       dev_err(&ndev->dev, "Address Error\n");
+               netif_err(mdp, tx_err, ndev, "Address Error\n");
        }
 
        mask = EESR_TWB | EESR_TABT | EESR_ADE | EESR_TDE | EESR_TFE;
@@ -1609,9 +1606,9 @@ ignore_link:
                u32 edtrr = sh_eth_read(ndev, EDTRR);
 
                /* dmesg */
-               dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
-                       intr_status, mdp->cur_tx, mdp->dirty_tx,
-                       (u32)ndev->state, edtrr);
+               netdev_err(ndev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n",
+                          intr_status, mdp->cur_tx, mdp->dirty_tx,
+                          (u32)ndev->state, edtrr);
                /* dirty buffer free */
                sh_eth_txfree(ndev);
 
@@ -1656,9 +1653,9 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
                                     EESIPR);
                        __napi_schedule(&mdp->napi);
                } else {
-                       dev_warn(&ndev->dev,
-                                "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
-                                intr_status, intr_enable);
+                       netdev_warn(ndev,
+                                   "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
+                                   intr_status, intr_enable);
                }
        }
 
@@ -1757,27 +1754,42 @@ static void sh_eth_adjust_link(struct net_device *ndev)
 /* PHY init function */
 static int sh_eth_phy_init(struct net_device *ndev)
 {
+       struct device_node *np = ndev->dev.parent->of_node;
        struct sh_eth_private *mdp = netdev_priv(ndev);
-       char phy_id[MII_BUS_ID_SIZE + 3];
        struct phy_device *phydev = NULL;
 
-       snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
-                mdp->mii_bus->id, mdp->phy_id);
-
        mdp->link = 0;
        mdp->speed = 0;
        mdp->duplex = -1;
 
        /* Try connect to PHY */
-       phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
-                            mdp->phy_interface);
+       if (np) {
+               struct device_node *pn;
+
+               pn = of_parse_phandle(np, "phy-handle", 0);
+               phydev = of_phy_connect(ndev, pn,
+                                       sh_eth_adjust_link, 0,
+                                       mdp->phy_interface);
+
+               if (!phydev)
+                       phydev = ERR_PTR(-ENOENT);
+       } else {
+               char phy_id[MII_BUS_ID_SIZE + 3];
+
+               snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
+                        mdp->mii_bus->id, mdp->phy_id);
+
+               phydev = phy_connect(ndev, phy_id, sh_eth_adjust_link,
+                                    mdp->phy_interface);
+       }
+
        if (IS_ERR(phydev)) {
-               dev_err(&ndev->dev, "phy_connect failed\n");
+               netdev_err(ndev, "failed to connect PHY\n");
                return PTR_ERR(phydev);
        }
 
-       dev_info(&ndev->dev, "attached PHY %d (IRQ %d) to driver %s\n",
-                phydev->addr, phydev->irq, phydev->drv->name);
+       netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
+                   phydev->addr, phydev->irq, phydev->drv->name);
 
        mdp->phydev = phydev;
 
@@ -1958,12 +1970,12 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
 
        ret = sh_eth_ring_init(ndev);
        if (ret < 0) {
-               dev_err(&ndev->dev, "%s: sh_eth_ring_init failed.\n", __func__);
+               netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__);
                return ret;
        }
        ret = sh_eth_dev_init(ndev, false);
        if (ret < 0) {
-               dev_err(&ndev->dev, "%s: sh_eth_dev_init failed.\n", __func__);
+               netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", __func__);
                return ret;
        }
 
@@ -2004,7 +2016,7 @@ static int sh_eth_open(struct net_device *ndev)
        ret = request_irq(ndev->irq, sh_eth_interrupt,
                          mdp->cd->irq_flags, ndev->name, ndev);
        if (ret) {
-               dev_err(&ndev->dev, "Can not assign IRQ number\n");
+               netdev_err(ndev, "Can not assign IRQ number\n");
                goto out_napi_off;
        }
 
@@ -2042,10 +2054,9 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
 
        netif_stop_queue(ndev);
 
-       if (netif_msg_timer(mdp)) {
-               dev_err(&ndev->dev, "%s: transmit timed out, status %8.8x, resetting...\n",
-                       ndev->name, (int)sh_eth_read(ndev, EESR));
-       }
+       netif_err(mdp, timer, ndev,
+                 "transmit timed out, status %8.8x, resetting...\n",
+                 (int)sh_eth_read(ndev, EESR));
 
        /* tx_errors count up */
        ndev->stats.tx_errors++;
@@ -2080,8 +2091,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        spin_lock_irqsave(&mdp->lock, flags);
        if ((mdp->cur_tx - mdp->dirty_tx) >= (mdp->num_tx_ring - 4)) {
                if (!sh_eth_txfree(ndev)) {
-                       if (netif_msg_tx_queued(mdp))
-                               dev_warn(&ndev->dev, "TxFD exhausted.\n");
+                       netif_warn(mdp, tx_queued, ndev, "TxFD exhausted.\n");
                        netif_stop_queue(ndev);
                        spin_unlock_irqrestore(&mdp->lock, flags);
                        return NETDEV_TX_BUSY;
@@ -2098,8 +2108,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                 skb->len + 2);
        txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
                                      DMA_TO_DEVICE);
-       if (skb->len < ETHERSMALL)
-               txdesc->buffer_length = ETHERSMALL;
+       if (skb->len < ETH_ZLEN)
+               txdesc->buffer_length = ETH_ZLEN;
        else
                txdesc->buffer_length = skb->len;
 
@@ -2251,7 +2261,7 @@ static int sh_eth_tsu_busy(struct net_device *ndev)
                udelay(10);
                timeout--;
                if (timeout <= 0) {
-                       dev_err(&ndev->dev, "%s: timeout\n", __func__);
+                       netdev_err(ndev, "%s: timeout\n", __func__);
                        return -ETIMEDOUT;
                }
        }
@@ -2571,37 +2581,30 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp)
 }
 
 /* MDIO bus release function */
-static int sh_mdio_release(struct net_device *ndev)
+static int sh_mdio_release(struct sh_eth_private *mdp)
 {
-       struct mii_bus *bus = dev_get_drvdata(&ndev->dev);
-
        /* unregister mdio bus */
-       mdiobus_unregister(bus);
-
-       /* remove mdio bus info from net_device */
-       dev_set_drvdata(&ndev->dev, NULL);
+       mdiobus_unregister(mdp->mii_bus);
 
        /* free bitbang info */
-       free_mdio_bitbang(bus);
+       free_mdio_bitbang(mdp->mii_bus);
 
        return 0;
 }
 
 /* MDIO bus init function */
-static int sh_mdio_init(struct net_device *ndev, int id,
+static int sh_mdio_init(struct sh_eth_private *mdp,
                        struct sh_eth_plat_data *pd)
 {
        int ret, i;
        struct bb_info *bitbang;
-       struct sh_eth_private *mdp = netdev_priv(ndev);
+       struct platform_device *pdev = mdp->pdev;
+       struct device *dev = &mdp->pdev->dev;
 
        /* create bit control struct for PHY */
-       bitbang = devm_kzalloc(&ndev->dev, sizeof(struct bb_info),
-                              GFP_KERNEL);
-       if (!bitbang) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       bitbang = devm_kzalloc(dev, sizeof(struct bb_info), GFP_KERNEL);
+       if (!bitbang)
+               return -ENOMEM;
 
        /* bitbang init */
        bitbang->addr = mdp->addr + mdp->reg_offset[PIR];
@@ -2614,44 +2617,42 @@ static int sh_mdio_init(struct net_device *ndev, int id,
 
        /* MII controller setting */
        mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
-       if (!mdp->mii_bus) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!mdp->mii_bus)
+               return -ENOMEM;
 
        /* Hook up MII support for ethtool */
        mdp->mii_bus->name = "sh_mii";
-       mdp->mii_bus->parent = &ndev->dev;
+       mdp->mii_bus->parent = dev;
        snprintf(mdp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
-                mdp->pdev->name, id);
+                pdev->name, pdev->id);
 
        /* PHY IRQ */
-       mdp->mii_bus->irq = devm_kzalloc(&ndev->dev,
-                                        sizeof(int) * PHY_MAX_ADDR,
+       mdp->mii_bus->irq = devm_kzalloc(dev, sizeof(int) * PHY_MAX_ADDR,
                                         GFP_KERNEL);
        if (!mdp->mii_bus->irq) {
                ret = -ENOMEM;
                goto out_free_bus;
        }
 
-       for (i = 0; i < PHY_MAX_ADDR; i++)
-               mdp->mii_bus->irq[i] = PHY_POLL;
-       if (pd->phy_irq > 0)
-               mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
+       /* register MDIO bus */
+       if (dev->of_node) {
+               ret = of_mdiobus_register(mdp->mii_bus, dev->of_node);
+       } else {
+               for (i = 0; i < PHY_MAX_ADDR; i++)
+                       mdp->mii_bus->irq[i] = PHY_POLL;
+               if (pd->phy_irq > 0)
+                       mdp->mii_bus->irq[pd->phy] = pd->phy_irq;
+
+               ret = mdiobus_register(mdp->mii_bus);
+       }
 
-       /* register mdio bus */
-       ret = mdiobus_register(mdp->mii_bus);
        if (ret)
                goto out_free_bus;
 
-       dev_set_drvdata(&ndev->dev, mdp->mii_bus);
-
        return 0;
 
 out_free_bus:
        free_mdio_bitbang(mdp->mii_bus);
-
-out:
        return ret;
 }
 
@@ -2676,7 +2677,6 @@ static const u16 *sh_eth_get_register_offset(int register_type)
                reg_offset = sh_eth_offset_fast_sh3_sh2;
                break;
        default:
-               pr_err("Unknown register type (%d)\n", register_type);
                break;
        }
 
@@ -2710,6 +2710,48 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = {
        .ndo_change_mtu         = eth_change_mtu,
 };
 
+#ifdef CONFIG_OF
+static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct sh_eth_plat_data *pdata;
+       const char *mac_addr;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return NULL;
+
+       pdata->phy_interface = of_get_phy_mode(np);
+
+       mac_addr = of_get_mac_address(np);
+       if (mac_addr)
+               memcpy(pdata->mac_addr, mac_addr, ETH_ALEN);
+
+       pdata->no_ether_link =
+               of_property_read_bool(np, "renesas,no-ether-link");
+       pdata->ether_link_active_low =
+               of_property_read_bool(np, "renesas,ether-link-active-low");
+
+       return pdata;
+}
+
+static const struct of_device_id sh_eth_match_table[] = {
+       { .compatible = "renesas,gether-r8a7740", .data = &r8a7740_data },
+       { .compatible = "renesas,ether-r8a7778", .data = &r8a777x_data },
+       { .compatible = "renesas,ether-r8a7779", .data = &r8a777x_data },
+       { .compatible = "renesas,ether-r8a7790", .data = &r8a779x_data },
+       { .compatible = "renesas,ether-r8a7791", .data = &r8a779x_data },
+       { .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sh_eth_match_table);
+#else
+static inline struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
 static int sh_eth_drv_probe(struct platform_device *pdev)
 {
        int ret, devno = 0;
@@ -2723,15 +2765,15 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (unlikely(res == NULL)) {
                dev_err(&pdev->dev, "invalid resource\n");
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
 
        ndev = alloc_etherdev(sizeof(struct sh_eth_private));
-       if (!ndev) {
-               ret = -ENOMEM;
-               goto out;
-       }
+       if (!ndev)
+               return -ENOMEM;
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
 
        /* The sh Ether-specific entries in the device structure. */
        ndev->base_addr = res->start;
@@ -2760,9 +2802,9 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
 
        spin_lock_init(&mdp->lock);
        mdp->pdev = pdev;
-       pm_runtime_enable(&pdev->dev);
-       pm_runtime_resume(&pdev->dev);
 
+       if (pdev->dev.of_node)
+               pd = sh_eth_parse_dt(&pdev->dev);
        if (!pd) {
                dev_err(&pdev->dev, "no platform data\n");
                ret = -EINVAL;
@@ -2778,8 +2820,22 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        mdp->ether_link_active_low = pd->ether_link_active_low;
 
        /* set cpu data */
-       mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
+       if (id) {
+               mdp->cd = (struct sh_eth_cpu_data *)id->driver_data;
+       } else  {
+               const struct of_device_id *match;
+
+               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",
+                       mdp->cd->register_type);
+               ret = -EINVAL;
+               goto out_release;
+       }
        sh_eth_set_default_cpu_data(mdp->cd);
 
        /* set function */
@@ -2825,6 +2881,13 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
                }
        }
 
+       /* MDIO bus init */
+       ret = sh_mdio_init(mdp, pd);
+       if (ret) {
+               dev_err(&ndev->dev, "failed to initialise MDIO\n");
+               goto out_release;
+       }
+
        netif_napi_add(ndev, &mdp->napi, sh_eth_poll, 64);
 
        /* network device register */
@@ -2832,31 +2895,26 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        if (ret)
                goto out_napi_del;
 
-       /* mdio bus init */
-       ret = sh_mdio_init(ndev, pdev->id, pd);
-       if (ret)
-               goto out_unregister;
-
        /* print device information */
-       pr_info("Base address at 0x%x, %pM, IRQ %d.\n",
-               (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
+       netdev_info(ndev, "Base address at 0x%x, %pM, IRQ %d.\n",
+                   (u32)ndev->base_addr, ndev->dev_addr, ndev->irq);
 
+       pm_runtime_put(&pdev->dev);
        platform_set_drvdata(pdev, ndev);
 
        return ret;
 
-out_unregister:
-       unregister_netdev(ndev);
-
 out_napi_del:
        netif_napi_del(&mdp->napi);
+       sh_mdio_release(mdp);
 
 out_release:
        /* net_dev free */
        if (ndev)
                free_netdev(ndev);
 
-out:
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        return ret;
 }
 
@@ -2865,9 +2923,9 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
        struct net_device *ndev = platform_get_drvdata(pdev);
        struct sh_eth_private *mdp = netdev_priv(ndev);
 
-       sh_mdio_release(ndev);
        unregister_netdev(ndev);
        netif_napi_del(&mdp->napi);
+       sh_mdio_release(mdp);
        pm_runtime_disable(&pdev->dev);
        free_netdev(ndev);
 
@@ -2920,6 +2978,7 @@ static struct platform_driver sh_eth_driver = {
        .driver = {
                   .name = CARDNAME,
                   .pm = SH_ETH_PM_OPS,
+                  .of_match_table = of_match_ptr(sh_eth_match_table),
        },
 };
 
index 6075915b88ece2f42e59a70ab160cd5bd7f6a423..d55e37cd5fec04abcd6bc4e52827351e74d5fbdb 100644 (file)
@@ -27,8 +27,7 @@
 #define RX_RING_MIN    64
 #define TX_RING_MAX    1024
 #define RX_RING_MAX    1024
-#define ETHERSMALL             60
-#define PKT_BUF_SZ             1538
+#define PKT_BUF_SZ     1538
 #define SH_ETH_TSU_TIMEOUT_MS  500
 #define SH_ETH_TSU_CAM_ENTRIES 32
 
diff --git a/drivers/net/ethernet/samsung/Kconfig b/drivers/net/ethernet/samsung/Kconfig
new file mode 100644 (file)
index 0000000..7902341
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# Samsung Ethernet device configuration
+#
+
+config NET_VENDOR_SAMSUNG
+       bool "Samsung Ethernet device"
+       default y
+       ---help---
+         This is the driver for the SXGBE 10G Ethernet IP block found on Samsung
+         platforms.
+
+if NET_VENDOR_SAMSUNG
+
+source "drivers/net/ethernet/samsung/sxgbe/Kconfig"
+
+endif # NET_VENDOR_SAMSUNG
diff --git a/drivers/net/ethernet/samsung/Makefile b/drivers/net/ethernet/samsung/Makefile
new file mode 100644 (file)
index 0000000..1773c29
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for the Samsung Ethernet device drivers.
+#
+
+obj-$(CONFIG_SXGBE_ETH) += sxgbe/
diff --git a/drivers/net/ethernet/samsung/sxgbe/Kconfig b/drivers/net/ethernet/samsung/sxgbe/Kconfig
new file mode 100644 (file)
index 0000000..d79288c
--- /dev/null
@@ -0,0 +1,9 @@
+config SXGBE_ETH
+       tristate "Samsung 10G/2.5G/1G SXGBE Ethernet driver"
+       depends on HAS_IOMEM && HAS_DMA
+       select PHYLIB
+       select CRC32
+       select PTP_1588_CLOCK
+       ---help---
+         This is the driver for the SXGBE 10G Ethernet IP block found on Samsung
+         platforms.
diff --git a/drivers/net/ethernet/samsung/sxgbe/Makefile b/drivers/net/ethernet/samsung/sxgbe/Makefile
new file mode 100644 (file)
index 0000000..dcc80b9
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_SXGBE_ETH) += samsung-sxgbe.o
+samsung-sxgbe-objs:= sxgbe_platform.o sxgbe_main.o sxgbe_desc.o \
+               sxgbe_dma.o sxgbe_core.o sxgbe_mtl.o  sxgbe_mdio.o \
+               sxgbe_ethtool.o sxgbe_xpcs.o $(samsung-sxgbe-y)
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_common.h
new file mode 100644 (file)
index 0000000..6203c7d
--- /dev/null
@@ -0,0 +1,535 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 __SXGBE_COMMON_H__
+#define __SXGBE_COMMON_H__
+
+/* forward references */
+struct sxgbe_desc_ops;
+struct sxgbe_dma_ops;
+struct sxgbe_mtl_ops;
+
+#define SXGBE_RESOURCE_NAME    "sam_sxgbeeth"
+#define DRV_MODULE_VERSION     "November_2013"
+
+/* MAX HW feature words */
+#define SXGBE_HW_WORDS 3
+
+#define SXGBE_RX_COE_NONE      0
+
+/* CSR Frequency Access Defines*/
+#define SXGBE_CSR_F_150M       150000000
+#define SXGBE_CSR_F_250M       250000000
+#define SXGBE_CSR_F_300M       300000000
+#define SXGBE_CSR_F_350M       350000000
+#define SXGBE_CSR_F_400M       400000000
+#define SXGBE_CSR_F_500M       500000000
+
+/* pause time */
+#define SXGBE_PAUSE_TIME 0x200
+
+/* tx queues */
+#define SXGBE_TX_QUEUES   8
+#define SXGBE_RX_QUEUES   16
+
+/* Calculated based how much time does it take to fill 256KB Rx memory
+ * at 10Gb speed at 156MHz clock rate and considered little less then
+ * the actual value.
+ */
+#define SXGBE_MAX_DMA_RIWT     0x70
+#define SXGBE_MIN_DMA_RIWT     0x01
+
+/* Tx coalesce parameters */
+#define SXGBE_COAL_TX_TIMER    40000
+#define SXGBE_MAX_COAL_TX_TICK 100000
+#define SXGBE_TX_MAX_FRAMES    512
+#define SXGBE_TX_FRAMES        128
+
+/* SXGBE TX FIFO is 8K, Rx FIFO is 16K */
+#define BUF_SIZE_16KiB 16384
+#define BUF_SIZE_8KiB 8192
+#define BUF_SIZE_4KiB 4096
+#define BUF_SIZE_2KiB 2048
+
+#define SXGBE_DEFAULT_LIT_LS   0x3E8
+#define SXGBE_DEFAULT_TWT_LS   0x0
+
+/* Flow Control defines */
+#define SXGBE_FLOW_OFF         0
+#define SXGBE_FLOW_RX          1
+#define SXGBE_FLOW_TX          2
+#define SXGBE_FLOW_AUTO                (SXGBE_FLOW_TX | SXGBE_FLOW_RX)
+
+#define SF_DMA_MODE 1          /* DMA STORE-AND-FORWARD Operation Mode */
+
+/* errors */
+#define RX_GMII_ERR            0x01
+#define RX_WATCHDOG_ERR                0x02
+#define RX_CRC_ERR             0x03
+#define RX_GAINT_ERR           0x04
+#define RX_IP_HDR_ERR          0x05
+#define RX_PAYLOAD_ERR         0x06
+#define RX_OVERFLOW_ERR                0x07
+
+/* pkt type */
+#define RX_LEN_PKT             0x00
+#define RX_MACCTL_PKT          0x01
+#define RX_DCBCTL_PKT          0x02
+#define RX_ARP_PKT             0x03
+#define RX_OAM_PKT             0x04
+#define RX_UNTAG_PKT           0x05
+#define RX_OTHER_PKT           0x07
+#define RX_SVLAN_PKT           0x08
+#define RX_CVLAN_PKT           0x09
+#define RX_DVLAN_OCVLAN_ICVLAN_PKT             0x0A
+#define RX_DVLAN_OSVLAN_ISVLAN_PKT             0x0B
+#define RX_DVLAN_OSVLAN_ICVLAN_PKT             0x0C
+#define RX_DVLAN_OCVLAN_ISVLAN_PKT             0x0D
+
+#define RX_NOT_IP_PKT          0x00
+#define RX_IPV4_TCP_PKT                0x01
+#define RX_IPV4_UDP_PKT                0x02
+#define RX_IPV4_ICMP_PKT       0x03
+#define RX_IPV4_UNKNOWN_PKT    0x07
+#define RX_IPV6_TCP_PKT                0x09
+#define RX_IPV6_UDP_PKT                0x0A
+#define RX_IPV6_ICMP_PKT       0x0B
+#define RX_IPV6_UNKNOWN_PKT    0x0F
+
+#define RX_NO_PTP              0x00
+#define RX_PTP_SYNC            0x01
+#define RX_PTP_FOLLOW_UP       0x02
+#define RX_PTP_DELAY_REQ       0x03
+#define RX_PTP_DELAY_RESP      0x04
+#define RX_PTP_PDELAY_REQ      0x05
+#define RX_PTP_PDELAY_RESP     0x06
+#define RX_PTP_PDELAY_FOLLOW_UP        0x07
+#define RX_PTP_ANNOUNCE                0x08
+#define RX_PTP_MGMT            0x09
+#define RX_PTP_SIGNAL          0x0A
+#define RX_PTP_RESV_MSG                0x0F
+
+/* EEE-LPI mode  flags*/
+#define TX_ENTRY_LPI_MODE      0x10
+#define TX_EXIT_LPI_MODE       0x20
+#define RX_ENTRY_LPI_MODE      0x40
+#define RX_EXIT_LPI_MODE       0x80
+
+/* EEE-LPI Interrupt status flag */
+#define LPI_INT_STATUS         BIT(5)
+
+/* EEE-LPI Default timer values */
+#define LPI_LINK_STATUS_TIMER  0x3E8
+#define LPI_MAC_WAIT_TIMER     0x00
+
+/* EEE-LPI Control and status definitions */
+#define LPI_CTRL_STATUS_TXA    BIT(19)
+#define LPI_CTRL_STATUS_PLSDIS BIT(18)
+#define LPI_CTRL_STATUS_PLS    BIT(17)
+#define LPI_CTRL_STATUS_LPIEN  BIT(16)
+#define LPI_CTRL_STATUS_TXRSTP BIT(11)
+#define LPI_CTRL_STATUS_RXRSTP BIT(10)
+#define LPI_CTRL_STATUS_RLPIST BIT(9)
+#define LPI_CTRL_STATUS_TLPIST BIT(8)
+#define LPI_CTRL_STATUS_RLPIEX BIT(3)
+#define LPI_CTRL_STATUS_RLPIEN BIT(2)
+#define LPI_CTRL_STATUS_TLPIEX BIT(1)
+#define LPI_CTRL_STATUS_TLPIEN BIT(0)
+
+enum dma_irq_status {
+       tx_hard_error   = BIT(0),
+       tx_bump_tc      = BIT(1),
+       handle_tx       = BIT(2),
+       rx_hard_error   = BIT(3),
+       rx_bump_tc      = BIT(4),
+       handle_rx       = BIT(5),
+};
+
+#define NETIF_F_HW_VLAN_ALL     (NETIF_F_HW_VLAN_CTAG_RX |     \
+                                NETIF_F_HW_VLAN_STAG_RX |      \
+                                NETIF_F_HW_VLAN_CTAG_TX |      \
+                                NETIF_F_HW_VLAN_STAG_TX |      \
+                                NETIF_F_HW_VLAN_CTAG_FILTER |  \
+                                NETIF_F_HW_VLAN_STAG_FILTER)
+
+/* MMC control defines */
+#define SXGBE_MMC_CTRL_CNT_FRZ  0x00000008
+
+/* SXGBE HW ADDR regs */
+#define SXGBE_ADDR_HIGH(reg)    (((reg > 15) ? 0x00000800 : 0x00000040) + \
+                                (reg * 8))
+#define SXGBE_ADDR_LOW(reg)     (((reg > 15) ? 0x00000804 : 0x00000044) + \
+                                (reg * 8))
+#define SXGBE_MAX_PERFECT_ADDRESSES 32 /* Maximum unicast perfect filtering */
+#define SXGBE_FRAME_FILTER       0x00000004      /* Frame Filter */
+
+/* SXGBE Frame Filter defines */
+#define SXGBE_FRAME_FILTER_PR    0x00000001      /* Promiscuous Mode */
+#define SXGBE_FRAME_FILTER_HUC   0x00000002      /* Hash Unicast */
+#define SXGBE_FRAME_FILTER_HMC   0x00000004      /* Hash Multicast */
+#define SXGBE_FRAME_FILTER_DAIF  0x00000008      /* DA Inverse Filtering */
+#define SXGBE_FRAME_FILTER_PM    0x00000010      /* Pass all multicast */
+#define SXGBE_FRAME_FILTER_DBF   0x00000020      /* Disable Broadcast frames */
+#define SXGBE_FRAME_FILTER_SAIF  0x00000100      /* Inverse Filtering */
+#define SXGBE_FRAME_FILTER_SAF   0x00000200      /* Source Address Filter */
+#define SXGBE_FRAME_FILTER_HPF   0x00000400      /* Hash or perfect Filter */
+#define SXGBE_FRAME_FILTER_RA    0x80000000      /* Receive all mode */
+
+#define SXGBE_HASH_TABLE_SIZE    64
+#define SXGBE_HASH_HIGH          0x00000008      /* Multicast Hash Table High */
+#define SXGBE_HASH_LOW           0x0000000c      /* Multicast Hash Table Low */
+
+#define SXGBE_HI_REG_AE          0x80000000
+
+/* Minimum and maximum MTU */
+#define MIN_MTU         68
+#define MAX_MTU         9000
+
+#define SXGBE_FOR_EACH_QUEUE(max_queues, queue_num)                    \
+       for (queue_num = 0; queue_num < max_queues; queue_num++)
+
+#define DRV_VERSION "1.0.0"
+
+#define SXGBE_MAX_RX_CHANNELS  16
+#define SXGBE_MAX_TX_CHANNELS  16
+
+#define START_MAC_REG_OFFSET   0x0000
+#define MAX_MAC_REG_OFFSET     0x0DFC
+#define START_MTL_REG_OFFSET   0x1000
+#define MAX_MTL_REG_OFFSET     0x18FC
+#define START_DMA_REG_OFFSET   0x3000
+#define MAX_DMA_REG_OFFSET     0x38FC
+
+#define REG_SPACE_SIZE         0x2000
+
+/* sxgbe statistics counters */
+struct sxgbe_extra_stats {
+       /* TX/RX IRQ events */
+       unsigned long tx_underflow_irq;
+       unsigned long tx_process_stopped_irq;
+       unsigned long tx_ctxt_desc_err;
+       unsigned long tx_threshold;
+       unsigned long rx_threshold;
+       unsigned long tx_pkt_n;
+       unsigned long rx_pkt_n;
+       unsigned long normal_irq_n;
+       unsigned long tx_normal_irq_n;
+       unsigned long rx_normal_irq_n;
+       unsigned long napi_poll;
+       unsigned long tx_clean;
+       unsigned long tx_reset_ic_bit;
+       unsigned long rx_process_stopped_irq;
+       unsigned long rx_underflow_irq;
+
+       /* Bus access errors */
+       unsigned long fatal_bus_error_irq;
+       unsigned long tx_read_transfer_err;
+       unsigned long tx_write_transfer_err;
+       unsigned long tx_desc_access_err;
+       unsigned long tx_buffer_access_err;
+       unsigned long tx_data_transfer_err;
+       unsigned long rx_read_transfer_err;
+       unsigned long rx_write_transfer_err;
+       unsigned long rx_desc_access_err;
+       unsigned long rx_buffer_access_err;
+       unsigned long rx_data_transfer_err;
+
+       /* EEE-LPI stats */
+       unsigned long tx_lpi_entry_n;
+       unsigned long tx_lpi_exit_n;
+       unsigned long rx_lpi_entry_n;
+       unsigned long rx_lpi_exit_n;
+       unsigned long eee_wakeup_error_n;
+
+       /* RX specific */
+       /* L2 error */
+       unsigned long rx_code_gmii_err;
+       unsigned long rx_watchdog_err;
+       unsigned long rx_crc_err;
+       unsigned long rx_gaint_pkt_err;
+       unsigned long ip_hdr_err;
+       unsigned long ip_payload_err;
+       unsigned long overflow_error;
+
+       /* L2 Pkt type */
+       unsigned long len_pkt;
+       unsigned long mac_ctl_pkt;
+       unsigned long dcb_ctl_pkt;
+       unsigned long arp_pkt;
+       unsigned long oam_pkt;
+       unsigned long untag_okt;
+       unsigned long other_pkt;
+       unsigned long svlan_tag_pkt;
+       unsigned long cvlan_tag_pkt;
+       unsigned long dvlan_ocvlan_icvlan_pkt;
+       unsigned long dvlan_osvlan_isvlan_pkt;
+       unsigned long dvlan_osvlan_icvlan_pkt;
+       unsigned long dvan_ocvlan_icvlan_pkt;
+
+       /* L3/L4 Pkt type */
+       unsigned long not_ip_pkt;
+       unsigned long ip4_tcp_pkt;
+       unsigned long ip4_udp_pkt;
+       unsigned long ip4_icmp_pkt;
+       unsigned long ip4_unknown_pkt;
+       unsigned long ip6_tcp_pkt;
+       unsigned long ip6_udp_pkt;
+       unsigned long ip6_icmp_pkt;
+       unsigned long ip6_unknown_pkt;
+
+       /* Filter specific */
+       unsigned long vlan_filter_match;
+       unsigned long sa_filter_fail;
+       unsigned long da_filter_fail;
+       unsigned long hash_filter_pass;
+       unsigned long l3_filter_match;
+       unsigned long l4_filter_match;
+
+       /* RX context specific */
+       unsigned long timestamp_dropped;
+       unsigned long rx_msg_type_no_ptp;
+       unsigned long rx_ptp_type_sync;
+       unsigned long rx_ptp_type_follow_up;
+       unsigned long rx_ptp_type_delay_req;
+       unsigned long rx_ptp_type_delay_resp;
+       unsigned long rx_ptp_type_pdelay_req;
+       unsigned long rx_ptp_type_pdelay_resp;
+       unsigned long rx_ptp_type_pdelay_follow_up;
+       unsigned long rx_ptp_announce;
+       unsigned long rx_ptp_mgmt;
+       unsigned long rx_ptp_signal;
+       unsigned long rx_ptp_resv_msg_type;
+};
+
+struct mac_link {
+       int port;
+       int duplex;
+       int speed;
+};
+
+struct mii_regs {
+       unsigned int addr;      /* MII Address */
+       unsigned int data;      /* MII Data */
+};
+
+struct sxgbe_core_ops {
+       /* MAC core initialization */
+       void (*core_init)(void __iomem *ioaddr);
+       /* Dump MAC registers */
+       void (*dump_regs)(void __iomem *ioaddr);
+       /* Handle extra events on specific interrupts hw dependent */
+       int (*host_irq_status)(void __iomem *ioaddr,
+                              struct sxgbe_extra_stats *x);
+       /* Set power management mode (e.g. magic frame) */
+       void (*pmt)(void __iomem *ioaddr, unsigned long mode);
+       /* Set/Get Unicast MAC addresses */
+       void (*set_umac_addr)(void __iomem *ioaddr, unsigned char *addr,
+                             unsigned int reg_n);
+       void (*get_umac_addr)(void __iomem *ioaddr, unsigned char *addr,
+                             unsigned int reg_n);
+       void (*enable_rx)(void __iomem *ioaddr, bool enable);
+       void (*enable_tx)(void __iomem *ioaddr, bool enable);
+
+       /* controller version specific operations */
+       int (*get_controller_version)(void __iomem *ioaddr);
+
+       /* If supported then get the optional core features */
+       unsigned int (*get_hw_feature)(void __iomem *ioaddr,
+                                      unsigned char feature_index);
+       /* adjust SXGBE speed */
+       void (*set_speed)(void __iomem *ioaddr, unsigned char speed);
+
+       /* EEE-LPI specific operations */
+       void (*set_eee_mode)(void __iomem *ioaddr);
+       void (*reset_eee_mode)(void __iomem *ioaddr);
+       void (*set_eee_timer)(void __iomem *ioaddr, const int ls,
+                             const int tw);
+       void (*set_eee_pls)(void __iomem *ioaddr, const int link);
+
+       /* Enable disable checksum offload operations */
+       void (*enable_rx_csum)(void __iomem *ioaddr);
+       void (*disable_rx_csum)(void __iomem *ioaddr);
+};
+
+const struct sxgbe_core_ops *sxgbe_get_core_ops(void);
+
+struct sxgbe_ops {
+       const struct sxgbe_core_ops *mac;
+       const struct sxgbe_desc_ops *desc;
+       const struct sxgbe_dma_ops *dma;
+       const struct sxgbe_mtl_ops *mtl;
+       struct mii_regs mii;    /* MII register Addresses */
+       struct mac_link link;
+       unsigned int ctrl_uid;
+       unsigned int ctrl_id;
+};
+
+/* SXGBE private data structures */
+struct sxgbe_tx_queue {
+       unsigned int irq_no;
+       struct sxgbe_priv_data *priv_ptr;
+       struct sxgbe_tx_norm_desc *dma_tx;
+       dma_addr_t dma_tx_phy;
+       dma_addr_t *tx_skbuff_dma;
+       struct sk_buff **tx_skbuff;
+       struct timer_list txtimer;
+       spinlock_t tx_lock;     /* lock for tx queues */
+       unsigned int cur_tx;
+       unsigned int dirty_tx;
+       u32 tx_count_frames;
+       u32 tx_coal_frames;
+       u32 tx_coal_timer;
+       int hwts_tx_en;
+       u16 prev_mss;
+       u8 queue_no;
+};
+
+struct sxgbe_rx_queue {
+       struct sxgbe_priv_data *priv_ptr;
+       struct sxgbe_rx_norm_desc *dma_rx;
+       struct sk_buff **rx_skbuff;
+       unsigned int cur_rx;
+       unsigned int dirty_rx;
+       unsigned int irq_no;
+       u32 rx_riwt;
+       dma_addr_t *rx_skbuff_dma;
+       dma_addr_t dma_rx_phy;
+       u8 queue_no;
+};
+
+/* SXGBE HW capabilities */
+struct sxgbe_hw_features {
+       /****** CAP [0] *******/
+       unsigned int pmt_remote_wake_up;
+       unsigned int pmt_magic_frame;
+       /* IEEE 1588-2008 */
+       unsigned int atime_stamp;
+
+       unsigned int eee;
+
+       unsigned int tx_csum_offload;
+       unsigned int rx_csum_offload;
+       unsigned int multi_macaddr;
+       unsigned int tstamp_srcselect;
+       unsigned int sa_vlan_insert;
+
+       /****** CAP [1] *******/
+       unsigned int rxfifo_size;
+       unsigned int txfifo_size;
+       unsigned int atstmap_hword;
+       unsigned int dcb_enable;
+       unsigned int splithead_enable;
+       unsigned int tcpseg_offload;
+       unsigned int debug_mem;
+       unsigned int rss_enable;
+       unsigned int hash_tsize;
+       unsigned int l3l4_filer_size;
+
+       /* This value is in bytes and
+        * as mentioned in HW features
+        * of SXGBE data book
+        */
+       unsigned int rx_mtl_qsize;
+       unsigned int tx_mtl_qsize;
+
+       /****** CAP [2] *******/
+       /* TX and RX number of channels */
+       unsigned int rx_mtl_queues;
+       unsigned int tx_mtl_queues;
+       unsigned int rx_dma_channels;
+       unsigned int tx_dma_channels;
+       unsigned int pps_output_count;
+       unsigned int aux_input_count;
+};
+
+struct sxgbe_priv_data {
+       /* DMA descriptos */
+       struct sxgbe_tx_queue *txq[SXGBE_TX_QUEUES];
+       struct sxgbe_rx_queue *rxq[SXGBE_RX_QUEUES];
+       u8 cur_rx_qnum;
+
+       unsigned int dma_tx_size;
+       unsigned int dma_rx_size;
+       unsigned int dma_buf_sz;
+       u32 rx_riwt;
+
+       struct napi_struct napi;
+
+       void __iomem *ioaddr;
+       struct net_device *dev;
+       struct device *device;
+       struct sxgbe_ops *hw;   /* sxgbe specific ops */
+       int no_csum_insertion;
+       int irq;
+       int rxcsum_insertion;
+       spinlock_t stats_lock;  /* lock for tx/rx statatics */
+
+       struct phy_device *phydev;
+       int oldlink;
+       int speed;
+       int oldduplex;
+       struct mii_bus *mii;
+       int mii_irq[PHY_MAX_ADDR];
+       u8 rx_pause;
+       u8 tx_pause;
+
+       struct sxgbe_extra_stats xstats;
+       struct sxgbe_plat_data *plat;
+       struct sxgbe_hw_features hw_cap;
+
+       u32 msg_enable;
+
+       struct clk *sxgbe_clk;
+       int clk_csr;
+       unsigned int mode;
+       unsigned int default_addend;
+
+       /* advanced time stamp support */
+       u32 adv_ts;
+       int use_riwt;
+       struct ptp_clock *ptp_clock;
+
+       /* tc control */
+       int tx_tc;
+       int rx_tc;
+       /* EEE-LPI specific members */
+       struct timer_list eee_ctrl_timer;
+       bool tx_path_in_lpi_mode;
+       int lpi_irq;
+       int eee_enabled;
+       int eee_active;
+       int tx_lpi_timer;
+};
+
+/* Function prototypes */
+struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
+                                       struct sxgbe_plat_data *plat_dat,
+                                       void __iomem *addr);
+int sxgbe_drv_remove(struct net_device *ndev);
+void sxgbe_set_ethtool_ops(struct net_device *netdev);
+int sxgbe_mdio_unregister(struct net_device *ndev);
+int sxgbe_mdio_register(struct net_device *ndev);
+int sxgbe_register_platform(void);
+void sxgbe_unregister_platform(void);
+
+#ifdef CONFIG_PM
+int sxgbe_suspend(struct net_device *ndev);
+int sxgbe_resume(struct net_device *ndev);
+int sxgbe_freeze(struct net_device *ndev);
+int sxgbe_restore(struct net_device *ndev);
+#endif /* CONFIG_PM */
+
+const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);
+
+void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv);
+bool sxgbe_eee_init(struct sxgbe_priv_data * const priv);
+#endif /* __SXGBE_COMMON_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_core.c
new file mode 100644 (file)
index 0000000..66d4a74
--- /dev/null
@@ -0,0 +1,262 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+
+/* MAC core initialization */
+static void sxgbe_core_init(void __iomem *ioaddr)
+{
+       u32 regval;
+
+       /* TX configuration */
+       regval = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+       /* Other configurable parameters IFP, IPG, ISR, ISM
+        * needs to be set if needed
+        */
+       regval |= SXGBE_TX_JABBER_DISABLE;
+       writel(regval, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+
+       /* RX configuration */
+       regval = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+       /* Other configurable parameters CST, SPEN, USP, GPSLCE
+        * WD, LM, S2KP, HDSMS, GPSL, ELEN, ARPEN needs to be
+        * set if needed
+        */
+       regval |= SXGBE_RX_JUMBPKT_ENABLE | SXGBE_RX_ACS_ENABLE;
+       writel(regval, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+/* Dump MAC registers */
+static void sxgbe_core_dump_regs(void __iomem *ioaddr)
+{
+}
+
+static int sxgbe_get_lpi_status(void __iomem *ioaddr, const u32 irq_status)
+{
+       int status = 0;
+       int lpi_status;
+
+       /* Reading this register shall clear all the LPI status bits */
+       lpi_status = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+
+       if (lpi_status & LPI_CTRL_STATUS_TLPIEN)
+               status |= TX_ENTRY_LPI_MODE;
+       if (lpi_status & LPI_CTRL_STATUS_TLPIEX)
+               status |= TX_EXIT_LPI_MODE;
+       if (lpi_status & LPI_CTRL_STATUS_RLPIEN)
+               status |= RX_ENTRY_LPI_MODE;
+       if (lpi_status & LPI_CTRL_STATUS_RLPIEX)
+               status |= RX_EXIT_LPI_MODE;
+
+       return status;
+}
+
+/* Handle extra events on specific interrupts hw dependent */
+static int sxgbe_core_host_irq_status(void __iomem *ioaddr,
+                                     struct sxgbe_extra_stats *x)
+{
+       int irq_status, status = 0;
+
+       irq_status = readl(ioaddr + SXGBE_CORE_INT_STATUS_REG);
+
+       if (unlikely(irq_status & LPI_INT_STATUS))
+               status |= sxgbe_get_lpi_status(ioaddr, irq_status);
+
+       return status;
+}
+
+/* Set power management mode (e.g. magic frame) */
+static void sxgbe_core_pmt(void __iomem *ioaddr, unsigned long mode)
+{
+}
+
+/* Set/Get Unicast MAC addresses */
+static void sxgbe_core_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+                                    unsigned int reg_n)
+{
+       u32 high_word, low_word;
+
+       high_word = (addr[5] << 8) || (addr[4]);
+       low_word = ((addr[3] << 24) || (addr[2] << 16) ||
+                   (addr[1] << 8) || (addr[0]));
+       writel(high_word, ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
+       writel(low_word, ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
+}
+
+static void sxgbe_core_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+                                    unsigned int reg_n)
+{
+       u32 high_word, low_word;
+
+       high_word = readl(ioaddr + SXGBE_CORE_ADD_HIGHOFFSET(reg_n));
+       low_word = readl(ioaddr + SXGBE_CORE_ADD_LOWOFFSET(reg_n));
+
+       /* extract and assign address */
+       addr[5] = (high_word & 0x0000FF00) >> 8;
+       addr[4] = (high_word & 0x000000FF);
+       addr[3] = (low_word & 0xFF000000) >> 24;
+       addr[2] = (low_word & 0x00FF0000) >> 16;
+       addr[1] = (low_word & 0x0000FF00) >> 8;
+       addr[0] = (low_word & 0x000000FF);
+}
+
+static void sxgbe_enable_tx(void __iomem *ioaddr, bool enable)
+{
+       u32 tx_config;
+
+       tx_config = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+       tx_config &= ~SXGBE_TX_ENABLE;
+
+       if (enable)
+               tx_config |= SXGBE_TX_ENABLE;
+       writel(tx_config, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+}
+
+static void sxgbe_enable_rx(void __iomem *ioaddr, bool enable)
+{
+       u32 rx_config;
+
+       rx_config = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+       rx_config &= ~SXGBE_RX_ENABLE;
+
+       if (enable)
+               rx_config |= SXGBE_RX_ENABLE;
+       writel(rx_config, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+static int sxgbe_get_controller_version(void __iomem *ioaddr)
+{
+       return readl(ioaddr + SXGBE_CORE_VERSION_REG);
+}
+
+/* If supported then get the optional core features */
+static unsigned int sxgbe_get_hw_feature(void __iomem *ioaddr,
+                                        unsigned char feature_index)
+{
+       return readl(ioaddr + (SXGBE_CORE_HW_FEA_REG(feature_index)));
+}
+
+static void sxgbe_core_set_speed(void __iomem *ioaddr, unsigned char speed)
+{
+       u32 tx_cfg = readl(ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+
+       /* clear the speed bits */
+       tx_cfg &= ~0x60000000;
+       tx_cfg |= (speed << SXGBE_SPEED_LSHIFT);
+
+       /* set the speed */
+       writel(tx_cfg, ioaddr + SXGBE_CORE_TX_CONFIG_REG);
+}
+
+static void  sxgbe_set_eee_mode(void __iomem *ioaddr)
+{
+       u32 ctrl;
+
+       /* Enable the LPI mode for transmit path with Tx automate bit set.
+        * When Tx Automate bit is set, MAC internally handles the entry
+        * to LPI mode after all outstanding and pending packets are
+        * transmitted.
+        */
+       ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+       ctrl |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA;
+       writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+}
+
+static void  sxgbe_reset_eee_mode(void __iomem *ioaddr)
+{
+       u32 ctrl;
+
+       ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+       ctrl &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_TXA);
+       writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+}
+
+static void  sxgbe_set_eee_pls(void __iomem *ioaddr, const int link)
+{
+       u32 ctrl;
+
+       ctrl = readl(ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+
+       /* If the PHY link status is UP then set PLS */
+       if (link)
+               ctrl |= LPI_CTRL_STATUS_PLS;
+       else
+               ctrl &= ~LPI_CTRL_STATUS_PLS;
+
+       writel(ctrl, ioaddr + SXGBE_CORE_LPI_CTRL_STATUS);
+}
+
+static void  sxgbe_set_eee_timer(void __iomem *ioaddr,
+                                const int ls, const int tw)
+{
+       int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
+
+       /* Program the timers in the LPI timer control register:
+        * LS: minimum time (ms) for which the link
+        *  status from PHY should be ok before transmitting
+        *  the LPI pattern.
+        * TW: minimum time (us) for which the core waits
+        *  after it has stopped transmitting the LPI pattern.
+        */
+       writel(value, ioaddr + SXGBE_CORE_LPI_TIMER_CTRL);
+}
+
+static void sxgbe_enable_rx_csum(void __iomem *ioaddr)
+{
+       u32 ctrl;
+
+       ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+       ctrl |= SXGBE_RX_CSUMOFFLOAD_ENABLE;
+       writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+static void sxgbe_disable_rx_csum(void __iomem *ioaddr)
+{
+       u32 ctrl;
+
+       ctrl = readl(ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+       ctrl &= ~SXGBE_RX_CSUMOFFLOAD_ENABLE;
+       writel(ctrl, ioaddr + SXGBE_CORE_RX_CONFIG_REG);
+}
+
+const struct sxgbe_core_ops core_ops = {
+       .core_init              = sxgbe_core_init,
+       .dump_regs              = sxgbe_core_dump_regs,
+       .host_irq_status        = sxgbe_core_host_irq_status,
+       .pmt                    = sxgbe_core_pmt,
+       .set_umac_addr          = sxgbe_core_set_umac_addr,
+       .get_umac_addr          = sxgbe_core_get_umac_addr,
+       .enable_rx              = sxgbe_enable_rx,
+       .enable_tx              = sxgbe_enable_tx,
+       .get_controller_version = sxgbe_get_controller_version,
+       .get_hw_feature         = sxgbe_get_hw_feature,
+       .set_speed              = sxgbe_core_set_speed,
+       .set_eee_mode           = sxgbe_set_eee_mode,
+       .reset_eee_mode         = sxgbe_reset_eee_mode,
+       .set_eee_timer          = sxgbe_set_eee_timer,
+       .set_eee_pls            = sxgbe_set_eee_pls,
+       .enable_rx_csum         = sxgbe_enable_rx_csum,
+       .disable_rx_csum        = sxgbe_disable_rx_csum,
+};
+
+const struct sxgbe_core_ops *sxgbe_get_core_ops(void)
+{
+       return &core_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.c
new file mode 100644 (file)
index 0000000..e896dbb
--- /dev/null
@@ -0,0 +1,515 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_dma.h"
+#include "sxgbe_desc.h"
+
+/* DMA TX descriptor ring initialization */
+static void sxgbe_init_tx_desc(struct sxgbe_tx_norm_desc *p)
+{
+       p->tdes23.tx_rd_des23.own_bit = 0;
+}
+
+static void sxgbe_tx_desc_enable_tse(struct sxgbe_tx_norm_desc *p, u8 is_tse,
+                                    u32 total_hdr_len, u32 tcp_hdr_len,
+                                    u32 tcp_payload_len)
+{
+       p->tdes23.tx_rd_des23.tse_bit = is_tse;
+       p->tdes23.tx_rd_des23.buf1_size = total_hdr_len;
+       p->tdes23.tx_rd_des23.tcp_hdr_len = tcp_hdr_len / 4;
+       p->tdes23.tx_rd_des23.tx_pkt_len.tcp_payload_len  = tcp_payload_len;
+}
+
+/* Assign buffer lengths for descriptor */
+static void sxgbe_prepare_tx_desc(struct sxgbe_tx_norm_desc *p, u8 is_fd,
+                                 int buf1_len, int pkt_len, int cksum)
+{
+       p->tdes23.tx_rd_des23.first_desc = is_fd;
+       p->tdes23.tx_rd_des23.buf1_size = buf1_len;
+
+       p->tdes23.tx_rd_des23.tx_pkt_len.cksum_pktlen.total_pkt_len = pkt_len;
+
+       if (cksum)
+               p->tdes23.tx_rd_des23.tx_pkt_len.cksum_pktlen.cksum_ctl = cic_full;
+}
+
+/* Set VLAN control information */
+static void sxgbe_tx_vlanctl_desc(struct sxgbe_tx_norm_desc *p, int vlan_ctl)
+{
+       p->tdes23.tx_rd_des23.vlan_tag_ctl = vlan_ctl;
+}
+
+/* Set the owner of Normal descriptor */
+static void sxgbe_set_tx_owner(struct sxgbe_tx_norm_desc *p)
+{
+       p->tdes23.tx_rd_des23.own_bit = 1;
+}
+
+/* Get the owner of Normal descriptor */
+static int sxgbe_get_tx_owner(struct sxgbe_tx_norm_desc *p)
+{
+       return p->tdes23.tx_rd_des23.own_bit;
+}
+
+/* Invoked by the xmit function to close the tx descriptor */
+static void sxgbe_close_tx_desc(struct sxgbe_tx_norm_desc *p)
+{
+       p->tdes23.tx_rd_des23.last_desc = 1;
+       p->tdes23.tx_rd_des23.int_on_com = 1;
+}
+
+/* Clean the tx descriptor as soon as the tx irq is received */
+static void sxgbe_release_tx_desc(struct sxgbe_tx_norm_desc *p)
+{
+       memset(p, 0, sizeof(*p));
+}
+
+/* Clear interrupt on tx frame completion. When this bit is
+ * set an interrupt happens as soon as the frame is transmitted
+ */
+static void sxgbe_clear_tx_ic(struct sxgbe_tx_norm_desc *p)
+{
+       p->tdes23.tx_rd_des23.int_on_com = 0;
+}
+
+/* Last tx segment reports the transmit status */
+static int sxgbe_get_tx_ls(struct sxgbe_tx_norm_desc *p)
+{
+       return p->tdes23.tx_rd_des23.last_desc;
+}
+
+/* Get the buffer size from the descriptor */
+static int sxgbe_get_tx_len(struct sxgbe_tx_norm_desc *p)
+{
+       return p->tdes23.tx_rd_des23.buf1_size;
+}
+
+/* Set tx timestamp enable bit */
+static void sxgbe_tx_enable_tstamp(struct sxgbe_tx_norm_desc *p)
+{
+       p->tdes23.tx_rd_des23.timestmp_enable = 1;
+}
+
+/* get tx timestamp status */
+static int sxgbe_get_tx_timestamp_status(struct sxgbe_tx_norm_desc *p)
+{
+       return p->tdes23.tx_rd_des23.timestmp_enable;
+}
+
+/* TX Context Descripto Specific */
+static void sxgbe_tx_ctxt_desc_set_ctxt(struct sxgbe_tx_ctxt_desc *p)
+{
+       p->ctxt_bit = 1;
+}
+
+/* Set the owner of TX context descriptor */
+static void sxgbe_tx_ctxt_desc_set_owner(struct sxgbe_tx_ctxt_desc *p)
+{
+       p->own_bit = 1;
+}
+
+/* Get the owner of TX context descriptor */
+static int sxgbe_tx_ctxt_desc_get_owner(struct sxgbe_tx_ctxt_desc *p)
+{
+       return p->own_bit;
+}
+
+/* Set TX mss in TX context Descriptor */
+static void sxgbe_tx_ctxt_desc_set_mss(struct sxgbe_tx_ctxt_desc *p, u16 mss)
+{
+       p->maxseg_size = mss;
+}
+
+/* Get TX mss from TX context Descriptor */
+static int sxgbe_tx_ctxt_desc_get_mss(struct sxgbe_tx_ctxt_desc *p)
+{
+       return p->maxseg_size;
+}
+
+/* Set TX tcmssv in TX context Descriptor */
+static void sxgbe_tx_ctxt_desc_set_tcmssv(struct sxgbe_tx_ctxt_desc *p)
+{
+       p->tcmssv = 1;
+}
+
+/* Reset TX ostc in TX context Descriptor */
+static void sxgbe_tx_ctxt_desc_reset_ostc(struct sxgbe_tx_ctxt_desc *p)
+{
+       p->ostc = 0;
+}
+
+/* Set IVLAN information */
+static void sxgbe_tx_ctxt_desc_set_ivlantag(struct sxgbe_tx_ctxt_desc *p,
+                                           int is_ivlanvalid, int ivlan_tag,
+                                           int ivlan_ctl)
+{
+       if (is_ivlanvalid) {
+               p->ivlan_tag_valid = is_ivlanvalid;
+               p->ivlan_tag = ivlan_tag;
+               p->ivlan_tag_ctl = ivlan_ctl;
+       }
+}
+
+/* Return IVLAN Tag */
+static int sxgbe_tx_ctxt_desc_get_ivlantag(struct sxgbe_tx_ctxt_desc *p)
+{
+       return p->ivlan_tag;
+}
+
+/* Set VLAN Tag */
+static void sxgbe_tx_ctxt_desc_set_vlantag(struct sxgbe_tx_ctxt_desc *p,
+                                          int is_vlanvalid, int vlan_tag)
+{
+       if (is_vlanvalid) {
+               p->vltag_valid = is_vlanvalid;
+               p->vlan_tag = vlan_tag;
+       }
+}
+
+/* Return VLAN Tag */
+static int sxgbe_tx_ctxt_desc_get_vlantag(struct sxgbe_tx_ctxt_desc *p)
+{
+       return p->vlan_tag;
+}
+
+/* Set Time stamp */
+static void sxgbe_tx_ctxt_desc_set_tstamp(struct sxgbe_tx_ctxt_desc *p,
+                                         u8 ostc_enable, u64 tstamp)
+{
+       if (ostc_enable) {
+               p->ostc = ostc_enable;
+               p->tstamp_lo = (u32) tstamp;
+               p->tstamp_hi = (u32) (tstamp>>32);
+       }
+}
+/* Close TX context descriptor */
+static void sxgbe_tx_ctxt_desc_close(struct sxgbe_tx_ctxt_desc *p)
+{
+       p->own_bit = 1;
+}
+
+/* WB status of context descriptor */
+static int sxgbe_tx_ctxt_desc_get_cde(struct sxgbe_tx_ctxt_desc *p)
+{
+       return p->ctxt_desc_err;
+}
+
+/* DMA RX descriptor ring initialization */
+static void sxgbe_init_rx_desc(struct sxgbe_rx_norm_desc *p, int disable_rx_ic,
+                              int mode, int end)
+{
+       p->rdes23.rx_rd_des23.own_bit = 1;
+       if (disable_rx_ic)
+               p->rdes23.rx_rd_des23.int_on_com = disable_rx_ic;
+}
+
+/* Get RX own bit */
+static int sxgbe_get_rx_owner(struct sxgbe_rx_norm_desc *p)
+{
+       return p->rdes23.rx_rd_des23.own_bit;
+}
+
+/* Set RX own bit */
+static void sxgbe_set_rx_owner(struct sxgbe_rx_norm_desc *p)
+{
+       p->rdes23.rx_rd_des23.own_bit = 1;
+}
+
+/* Get the receive frame size */
+static int sxgbe_get_rx_frame_len(struct sxgbe_rx_norm_desc *p)
+{
+       return p->rdes23.rx_wb_des23.pkt_len;
+}
+
+/* Return first Descriptor status */
+static int sxgbe_get_rx_fd_status(struct sxgbe_rx_norm_desc *p)
+{
+       return p->rdes23.rx_wb_des23.first_desc;
+}
+
+/* Return Last Descriptor status */
+static int sxgbe_get_rx_ld_status(struct sxgbe_rx_norm_desc *p)
+{
+       return p->rdes23.rx_wb_des23.last_desc;
+}
+
+
+/* Return the RX status looking at the WB fields */
+static int sxgbe_rx_wbstatus(struct sxgbe_rx_norm_desc *p,
+                            struct sxgbe_extra_stats *x, int *checksum)
+{
+       int status = 0;
+
+       *checksum = CHECKSUM_UNNECESSARY;
+       if (p->rdes23.rx_wb_des23.err_summary) {
+               switch (p->rdes23.rx_wb_des23.err_l2_type) {
+               case RX_GMII_ERR:
+                       status = -EINVAL;
+                       x->rx_code_gmii_err++;
+                       break;
+               case RX_WATCHDOG_ERR:
+                       status = -EINVAL;
+                       x->rx_watchdog_err++;
+                       break;
+               case RX_CRC_ERR:
+                       status = -EINVAL;
+                       x->rx_crc_err++;
+                       break;
+               case RX_GAINT_ERR:
+                       status = -EINVAL;
+                       x->rx_gaint_pkt_err++;
+                       break;
+               case RX_IP_HDR_ERR:
+                       *checksum = CHECKSUM_NONE;
+                       x->ip_hdr_err++;
+                       break;
+               case RX_PAYLOAD_ERR:
+                       *checksum = CHECKSUM_NONE;
+                       x->ip_payload_err++;
+                       break;
+               case RX_OVERFLOW_ERR:
+                       status = -EINVAL;
+                       x->overflow_error++;
+                       break;
+               default:
+                       pr_err("Invalid Error type\n");
+                       break;
+               }
+       } else {
+               switch (p->rdes23.rx_wb_des23.err_l2_type) {
+               case RX_LEN_PKT:
+                       x->len_pkt++;
+                       break;
+               case RX_MACCTL_PKT:
+                       x->mac_ctl_pkt++;
+                       break;
+               case RX_DCBCTL_PKT:
+                       x->dcb_ctl_pkt++;
+                       break;
+               case RX_ARP_PKT:
+                       x->arp_pkt++;
+                       break;
+               case RX_OAM_PKT:
+                       x->oam_pkt++;
+                       break;
+               case RX_UNTAG_PKT:
+                       x->untag_okt++;
+                       break;
+               case RX_OTHER_PKT:
+                       x->other_pkt++;
+                       break;
+               case RX_SVLAN_PKT:
+                       x->svlan_tag_pkt++;
+                       break;
+               case RX_CVLAN_PKT:
+                       x->cvlan_tag_pkt++;
+                       break;
+               case RX_DVLAN_OCVLAN_ICVLAN_PKT:
+                       x->dvlan_ocvlan_icvlan_pkt++;
+                       break;
+               case RX_DVLAN_OSVLAN_ISVLAN_PKT:
+                       x->dvlan_osvlan_isvlan_pkt++;
+                       break;
+               case RX_DVLAN_OSVLAN_ICVLAN_PKT:
+                       x->dvlan_osvlan_icvlan_pkt++;
+                       break;
+               case RX_DVLAN_OCVLAN_ISVLAN_PKT:
+                       x->dvlan_ocvlan_icvlan_pkt++;
+                       break;
+               default:
+                       pr_err("Invalid L2 Packet type\n");
+                       break;
+               }
+       }
+
+       /* L3/L4 Pkt type */
+       switch (p->rdes23.rx_wb_des23.layer34_pkt_type) {
+       case RX_NOT_IP_PKT:
+               x->not_ip_pkt++;
+               break;
+       case RX_IPV4_TCP_PKT:
+               x->ip4_tcp_pkt++;
+               break;
+       case RX_IPV4_UDP_PKT:
+               x->ip4_udp_pkt++;
+               break;
+       case RX_IPV4_ICMP_PKT:
+               x->ip4_icmp_pkt++;
+               break;
+       case RX_IPV4_UNKNOWN_PKT:
+               x->ip4_unknown_pkt++;
+               break;
+       case RX_IPV6_TCP_PKT:
+               x->ip6_tcp_pkt++;
+               break;
+       case RX_IPV6_UDP_PKT:
+               x->ip6_udp_pkt++;
+               break;
+       case RX_IPV6_ICMP_PKT:
+               x->ip6_icmp_pkt++;
+               break;
+       case RX_IPV6_UNKNOWN_PKT:
+               x->ip6_unknown_pkt++;
+               break;
+       default:
+               pr_err("Invalid L3/L4 Packet type\n");
+               break;
+       }
+
+       /* Filter */
+       if (p->rdes23.rx_wb_des23.vlan_filter_match)
+               x->vlan_filter_match++;
+
+       if (p->rdes23.rx_wb_des23.sa_filter_fail) {
+               status = -EINVAL;
+               x->sa_filter_fail++;
+       }
+       if (p->rdes23.rx_wb_des23.da_filter_fail) {
+               status = -EINVAL;
+               x->da_filter_fail++;
+       }
+       if (p->rdes23.rx_wb_des23.hash_filter_pass)
+               x->hash_filter_pass++;
+
+       if (p->rdes23.rx_wb_des23.l3_filter_match)
+               x->l3_filter_match++;
+
+       if (p->rdes23.rx_wb_des23.l4_filter_match)
+               x->l4_filter_match++;
+
+       return status;
+}
+
+/* Get own bit of context descriptor */
+static int sxgbe_get_rx_ctxt_owner(struct sxgbe_rx_ctxt_desc *p)
+{
+       return p->own_bit;
+}
+
+/* Set own bit for context descriptor */
+static void sxgbe_set_ctxt_rx_owner(struct sxgbe_rx_ctxt_desc *p)
+{
+       p->own_bit = 1;
+}
+
+
+/* Return the reception status looking at Context control information */
+static void sxgbe_rx_ctxt_wbstatus(struct sxgbe_rx_ctxt_desc *p,
+                                  struct sxgbe_extra_stats *x)
+{
+       if (p->tstamp_dropped)
+               x->timestamp_dropped++;
+
+       /* ptp */
+       if (p->ptp_msgtype == RX_NO_PTP)
+               x->rx_msg_type_no_ptp++;
+       else if (p->ptp_msgtype == RX_PTP_SYNC)
+               x->rx_ptp_type_sync++;
+       else if (p->ptp_msgtype == RX_PTP_FOLLOW_UP)
+               x->rx_ptp_type_follow_up++;
+       else if (p->ptp_msgtype == RX_PTP_DELAY_REQ)
+               x->rx_ptp_type_delay_req++;
+       else if (p->ptp_msgtype == RX_PTP_DELAY_RESP)
+               x->rx_ptp_type_delay_resp++;
+       else if (p->ptp_msgtype == RX_PTP_PDELAY_REQ)
+               x->rx_ptp_type_pdelay_req++;
+       else if (p->ptp_msgtype == RX_PTP_PDELAY_RESP)
+               x->rx_ptp_type_pdelay_resp++;
+       else if (p->ptp_msgtype == RX_PTP_PDELAY_FOLLOW_UP)
+               x->rx_ptp_type_pdelay_follow_up++;
+       else if (p->ptp_msgtype == RX_PTP_ANNOUNCE)
+               x->rx_ptp_announce++;
+       else if (p->ptp_msgtype == RX_PTP_MGMT)
+               x->rx_ptp_mgmt++;
+       else if (p->ptp_msgtype == RX_PTP_SIGNAL)
+               x->rx_ptp_signal++;
+       else if (p->ptp_msgtype == RX_PTP_RESV_MSG)
+               x->rx_ptp_resv_msg_type++;
+}
+
+/* Get rx timestamp status */
+static int sxgbe_get_rx_ctxt_tstamp_status(struct sxgbe_rx_ctxt_desc *p)
+{
+       if ((p->tstamp_hi == 0xffffffff) && (p->tstamp_lo == 0xffffffff)) {
+               pr_err("Time stamp corrupted\n");
+               return 0;
+       }
+
+       return p->tstamp_available;
+}
+
+
+static u64 sxgbe_get_rx_timestamp(struct sxgbe_rx_ctxt_desc *p)
+{
+       u64 ns;
+
+       ns = p->tstamp_lo;
+       ns |= ((u64)p->tstamp_hi) << 32;
+
+       return ns;
+}
+
+static const struct sxgbe_desc_ops desc_ops = {
+       .init_tx_desc                   = sxgbe_init_tx_desc,
+       .tx_desc_enable_tse             = sxgbe_tx_desc_enable_tse,
+       .prepare_tx_desc                = sxgbe_prepare_tx_desc,
+       .tx_vlanctl_desc                = sxgbe_tx_vlanctl_desc,
+       .set_tx_owner                   = sxgbe_set_tx_owner,
+       .get_tx_owner                   = sxgbe_get_tx_owner,
+       .close_tx_desc                  = sxgbe_close_tx_desc,
+       .release_tx_desc                = sxgbe_release_tx_desc,
+       .clear_tx_ic                    = sxgbe_clear_tx_ic,
+       .get_tx_ls                      = sxgbe_get_tx_ls,
+       .get_tx_len                     = sxgbe_get_tx_len,
+       .tx_enable_tstamp               = sxgbe_tx_enable_tstamp,
+       .get_tx_timestamp_status        = sxgbe_get_tx_timestamp_status,
+       .tx_ctxt_desc_set_ctxt          = sxgbe_tx_ctxt_desc_set_ctxt,
+       .tx_ctxt_desc_set_owner         = sxgbe_tx_ctxt_desc_set_owner,
+       .get_tx_ctxt_owner              = sxgbe_tx_ctxt_desc_get_owner,
+       .tx_ctxt_desc_set_mss           = sxgbe_tx_ctxt_desc_set_mss,
+       .tx_ctxt_desc_get_mss           = sxgbe_tx_ctxt_desc_get_mss,
+       .tx_ctxt_desc_set_tcmssv        = sxgbe_tx_ctxt_desc_set_tcmssv,
+       .tx_ctxt_desc_reset_ostc        = sxgbe_tx_ctxt_desc_reset_ostc,
+       .tx_ctxt_desc_set_ivlantag      = sxgbe_tx_ctxt_desc_set_ivlantag,
+       .tx_ctxt_desc_get_ivlantag      = sxgbe_tx_ctxt_desc_get_ivlantag,
+       .tx_ctxt_desc_set_vlantag       = sxgbe_tx_ctxt_desc_set_vlantag,
+       .tx_ctxt_desc_get_vlantag       = sxgbe_tx_ctxt_desc_get_vlantag,
+       .tx_ctxt_set_tstamp             = sxgbe_tx_ctxt_desc_set_tstamp,
+       .close_tx_ctxt_desc             = sxgbe_tx_ctxt_desc_close,
+       .get_tx_ctxt_cde                = sxgbe_tx_ctxt_desc_get_cde,
+       .init_rx_desc                   = sxgbe_init_rx_desc,
+       .get_rx_owner                   = sxgbe_get_rx_owner,
+       .set_rx_owner                   = sxgbe_set_rx_owner,
+       .get_rx_frame_len               = sxgbe_get_rx_frame_len,
+       .get_rx_fd_status               = sxgbe_get_rx_fd_status,
+       .get_rx_ld_status               = sxgbe_get_rx_ld_status,
+       .rx_wbstatus                    = sxgbe_rx_wbstatus,
+       .get_rx_ctxt_owner              = sxgbe_get_rx_ctxt_owner,
+       .set_rx_ctxt_owner              = sxgbe_set_ctxt_rx_owner,
+       .rx_ctxt_wbstatus               = sxgbe_rx_ctxt_wbstatus,
+       .get_rx_ctxt_tstamp_status      = sxgbe_get_rx_ctxt_tstamp_status,
+       .get_timestamp                  = sxgbe_get_rx_timestamp,
+};
+
+const struct sxgbe_desc_ops *sxgbe_get_desc_ops(void)
+{
+       return &desc_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_desc.h
new file mode 100644 (file)
index 0000000..838cb9f
--- /dev/null
@@ -0,0 +1,298 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 __SXGBE_DESC_H__
+#define __SXGBE_DESC_H__
+
+#define SXGBE_DESC_SIZE_BYTES  16
+
+/* forward declaration */
+struct sxgbe_extra_stats;
+
+/* 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 */
+};
+
+struct sxgbe_tx_norm_desc {
+       u64 tdes01; /* buf1 address */
+       union {
+               /* TX Read-Format Desc 2,3 */
+               struct {
+                       /* TDES2 */
+                       u32 buf1_size:14;
+                       u32 vlan_tag_ctl:2;
+                       u32 buf2_size:14;
+                       u32 timestmp_enable:1;
+                       u32 int_on_com:1;
+                       /* TDES3 */
+                       union {
+                               u32 tcp_payload_len:18;
+                               struct {
+                                       u32 total_pkt_len:15;
+                                       u32 reserved1:1;
+                                       u32 cksum_ctl:2;
+                               } cksum_pktlen;
+                       } tx_pkt_len;
+
+                       u32 tse_bit:1;
+                       u32 tcp_hdr_len:4;
+                       u32 sa_insert_ctl:3;
+                       u32 crc_pad_ctl:2;
+                       u32 last_desc:1;
+                       u32 first_desc:1;
+                       u32 ctxt_bit:1;
+                       u32 own_bit:1;
+               } tx_rd_des23;
+
+               /* tx write back Desc 2,3 */
+               struct {
+                       /* WB TES2 */
+                       u32 reserved1;
+                       /* WB TES3 */
+                       u32 reserved2:31;
+                       u32 own_bit:1;
+               } tx_wb_des23;
+       } tdes23;
+};
+
+struct sxgbe_rx_norm_desc {
+       union {
+               u32 rdes0; /* buf1 address */
+               struct {
+                       u32 out_vlan_tag:16;
+                       u32 in_vlan_tag:16;
+               } wb_rx_des0;
+       } rd_wb_des0;
+
+       union {
+               u32 rdes1;      /* buf2 address or buf1[63:32] */
+               u32 rss_hash;   /* Write-back RX */
+       } rd_wb_des1;
+
+       union {
+               /* RX Read format Desc 2,3 */
+               struct{
+                       /* RDES2 */
+                       u32 buf2_addr;
+                       /* RDES3 */
+                       u32 buf2_hi_addr:30;
+                       u32 int_on_com:1;
+                       u32 own_bit:1;
+               } rx_rd_des23;
+
+               /* RX write back */
+               struct{
+                       /* WB RDES2 */
+                       u32 hdr_len:10;
+                       u32 rdes2_reserved:2;
+                       u32 elrd_val:1;
+                       u32 iovt_sel:1;
+                       u32 res_pkt:1;
+                       u32 vlan_filter_match:1;
+                       u32 sa_filter_fail:1;
+                       u32 da_filter_fail:1;
+                       u32 hash_filter_pass:1;
+                       u32 macaddr_filter_match:8;
+                       u32 l3_filter_match:1;
+                       u32 l4_filter_match:1;
+                       u32 l34_filter_num:3;
+
+                       /* WB RDES3 */
+                       u32 pkt_len:14;
+                       u32 rdes3_reserved:1;
+                       u32 err_summary:1;
+                       u32 err_l2_type:4;
+                       u32 layer34_pkt_type:4;
+                       u32 no_coagulation_pkt:1;
+                       u32 in_seq_pkt:1;
+                       u32 rss_valid:1;
+                       u32 context_des_avail:1;
+                       u32 last_desc:1;
+                       u32 first_desc:1;
+                       u32 recv_context_desc:1;
+                       u32 own_bit:1;
+               } rx_wb_des23;
+       } rdes23;
+};
+
+/* Context descriptor structure */
+struct sxgbe_tx_ctxt_desc {
+       u32 tstamp_lo;
+       u32 tstamp_hi;
+       u32 maxseg_size:15;
+       u32 reserved1:1;
+       u32 ivlan_tag:16;
+       u32 vlan_tag:16;
+       u32 vltag_valid:1;
+       u32 ivlan_tag_valid:1;
+       u32 ivlan_tag_ctl:2;
+       u32 reserved2:3;
+       u32 ctxt_desc_err:1;
+       u32 reserved3:2;
+       u32 ostc:1;
+       u32 tcmssv:1;
+       u32 reserved4:2;
+       u32 ctxt_bit:1;
+       u32 own_bit:1;
+};
+
+struct sxgbe_rx_ctxt_desc {
+       u32 tstamp_lo;
+       u32 tstamp_hi;
+       u32 reserved1;
+       u32 ptp_msgtype:4;
+       u32 tstamp_available:1;
+       u32 ptp_rsp_err:1;
+       u32 tstamp_dropped:1;
+       u32 reserved2:23;
+       u32 rx_ctxt_desc:1;
+       u32 own_bit:1;
+};
+
+struct sxgbe_desc_ops {
+       /* DMA TX descriptor ring initialization */
+       void (*init_tx_desc)(struct sxgbe_tx_norm_desc *p);
+
+       /* Invoked by the xmit function to prepare the tx descriptor */
+       void (*tx_desc_enable_tse)(struct sxgbe_tx_norm_desc *p, u8 is_tse,
+                                  u32 total_hdr_len, u32 tcp_hdr_len,
+                                  u32 tcp_payload_len);
+
+       /* Assign buffer lengths for descriptor */
+       void (*prepare_tx_desc)(struct sxgbe_tx_norm_desc *p, u8 is_fd,
+                               int buf1_len, int pkt_len, int cksum);
+
+       /* Set VLAN control information */
+       void (*tx_vlanctl_desc)(struct sxgbe_tx_norm_desc *p, int vlan_ctl);
+
+       /* Set the owner of the descriptor */
+       void (*set_tx_owner)(struct sxgbe_tx_norm_desc *p);
+
+       /* Get the owner of the descriptor */
+       int (*get_tx_owner)(struct sxgbe_tx_norm_desc *p);
+
+       /* Invoked by the xmit function to close the tx descriptor */
+       void (*close_tx_desc)(struct sxgbe_tx_norm_desc *p);
+
+       /* Clean the tx descriptor as soon as the tx irq is received */
+       void (*release_tx_desc)(struct sxgbe_tx_norm_desc *p);
+
+       /* 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 sxgbe_tx_norm_desc *p);
+
+       /* Last tx segment reports the transmit status */
+       int (*get_tx_ls)(struct sxgbe_tx_norm_desc *p);
+
+       /* Get the buffer size from the descriptor */
+       int (*get_tx_len)(struct sxgbe_tx_norm_desc *p);
+
+       /* Set tx timestamp enable bit */
+       void (*tx_enable_tstamp)(struct sxgbe_tx_norm_desc *p);
+
+       /* get tx timestamp status */
+       int (*get_tx_timestamp_status)(struct sxgbe_tx_norm_desc *p);
+
+       /* TX Context Descripto Specific */
+       void (*tx_ctxt_desc_set_ctxt)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Set the owner of the TX context descriptor */
+       void (*tx_ctxt_desc_set_owner)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Get the owner of the TX context descriptor */
+       int (*get_tx_ctxt_owner)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Set TX mss */
+       void (*tx_ctxt_desc_set_mss)(struct sxgbe_tx_ctxt_desc *p, u16 mss);
+
+       /* Set TX mss */
+       int (*tx_ctxt_desc_get_mss)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Set TX tcmssv */
+       void (*tx_ctxt_desc_set_tcmssv)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Reset TX ostc */
+       void (*tx_ctxt_desc_reset_ostc)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Set IVLAN information */
+       void (*tx_ctxt_desc_set_ivlantag)(struct sxgbe_tx_ctxt_desc *p,
+                                         int is_ivlanvalid, int ivlan_tag,
+                                         int ivlan_ctl);
+
+       /* Return IVLAN Tag */
+       int (*tx_ctxt_desc_get_ivlantag)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Set VLAN Tag */
+       void (*tx_ctxt_desc_set_vlantag)(struct sxgbe_tx_ctxt_desc *p,
+                                        int is_vlanvalid, int vlan_tag);
+
+       /* Return VLAN Tag */
+       int (*tx_ctxt_desc_get_vlantag)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* Set Time stamp */
+       void (*tx_ctxt_set_tstamp)(struct sxgbe_tx_ctxt_desc *p,
+                                  u8 ostc_enable, u64 tstamp);
+
+       /* Close TX context descriptor */
+       void (*close_tx_ctxt_desc)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* WB status of context descriptor */
+       int (*get_tx_ctxt_cde)(struct sxgbe_tx_ctxt_desc *p);
+
+       /* DMA RX descriptor ring initialization */
+       void (*init_rx_desc)(struct sxgbe_rx_norm_desc *p, int disable_rx_ic,
+                            int mode, int end);
+
+       /* Get own bit */
+       int (*get_rx_owner)(struct sxgbe_rx_norm_desc *p);
+
+       /* Set own bit */
+       void (*set_rx_owner)(struct sxgbe_rx_norm_desc *p);
+
+       /* Get the receive frame size */
+       int (*get_rx_frame_len)(struct sxgbe_rx_norm_desc *p);
+
+       /* Return first Descriptor status */
+       int (*get_rx_fd_status)(struct sxgbe_rx_norm_desc *p);
+
+       /* Return first Descriptor status */
+       int (*get_rx_ld_status)(struct sxgbe_rx_norm_desc *p);
+
+       /* Return the reception status looking at the RDES1 */
+       int (*rx_wbstatus)(struct sxgbe_rx_norm_desc *p,
+                          struct sxgbe_extra_stats *x, int *checksum);
+
+       /* Get own bit */
+       int (*get_rx_ctxt_owner)(struct sxgbe_rx_ctxt_desc *p);
+
+       /* Set own bit */
+       void (*set_rx_ctxt_owner)(struct sxgbe_rx_ctxt_desc *p);
+
+       /* Return the reception status looking at Context control information */
+       void (*rx_ctxt_wbstatus)(struct sxgbe_rx_ctxt_desc *p,
+                                struct sxgbe_extra_stats *x);
+
+       /* Get rx timestamp status */
+       int (*get_rx_ctxt_tstamp_status)(struct sxgbe_rx_ctxt_desc *p);
+
+       /* Get timestamp value for rx, need to check this */
+       u64 (*get_timestamp)(struct sxgbe_rx_ctxt_desc *p);
+};
+
+const struct sxgbe_desc_ops *sxgbe_get_desc_ops(void);
+
+#endif /* __SXGBE_DESC_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
new file mode 100644 (file)
index 0000000..28f89c4
--- /dev/null
@@ -0,0 +1,382 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 <linux/io.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_dma.h"
+#include "sxgbe_reg.h"
+#include "sxgbe_desc.h"
+
+/* DMA core initialization */
+static int sxgbe_dma_init(void __iomem *ioaddr, int fix_burst, int burst_map)
+{
+       int retry_count = 10;
+       u32 reg_val;
+
+       /* reset the DMA */
+       writel(SXGBE_DMA_SOFT_RESET, ioaddr + SXGBE_DMA_MODE_REG);
+       while (retry_count--) {
+               if (!(readl(ioaddr + SXGBE_DMA_MODE_REG) &
+                     SXGBE_DMA_SOFT_RESET))
+                       break;
+               mdelay(10);
+       }
+
+       if (retry_count < 0)
+               return -EBUSY;
+
+       reg_val = readl(ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
+
+       /* if fix_burst = 0, Set UNDEF = 1 of DMA_Sys_Mode Register.
+        * if fix_burst = 1, Set UNDEF = 0 of DMA_Sys_Mode Register.
+        * burst_map is bitmap for  BLEN[4, 8, 16, 32, 64, 128 and 256].
+        * Set burst_map irrespective of fix_burst value.
+        */
+       if (!fix_burst)
+               reg_val |= SXGBE_DMA_AXI_UNDEF_BURST;
+
+       /* write burst len map */
+       reg_val |= (burst_map << SXGBE_DMA_BLENMAP_LSHIFT);
+
+       writel(reg_val, ioaddr + SXGBE_DMA_SYSBUS_MODE_REG);
+
+       return 0;
+}
+
+static void sxgbe_dma_channel_init(void __iomem *ioaddr, int cha_num,
+                                  int fix_burst, int pbl, dma_addr_t dma_tx,
+                                  dma_addr_t dma_rx, int t_rsize, int r_rsize)
+{
+       u32 reg_val;
+       dma_addr_t dma_addr;
+
+       reg_val = readl(ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num));
+       /* set the pbl */
+       if (fix_burst) {
+               reg_val |= SXGBE_DMA_PBL_X8MODE;
+               writel(reg_val, ioaddr + SXGBE_DMA_CHA_CTL_REG(cha_num));
+               /* program the TX pbl */
+               reg_val = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+               reg_val |= (pbl << SXGBE_DMA_TXPBL_LSHIFT);
+               writel(reg_val, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+               /* program the RX pbl */
+               reg_val = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num));
+               reg_val |= (pbl << SXGBE_DMA_RXPBL_LSHIFT);
+               writel(reg_val, ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cha_num));
+       }
+
+       /* program desc registers */
+       writel(upper_32_bits(dma_tx),
+              ioaddr + SXGBE_DMA_CHA_TXDESC_HADD_REG(cha_num));
+       writel(lower_32_bits(dma_tx),
+              ioaddr + SXGBE_DMA_CHA_TXDESC_LADD_REG(cha_num));
+
+       writel(upper_32_bits(dma_rx),
+              ioaddr + SXGBE_DMA_CHA_RXDESC_HADD_REG(cha_num));
+       writel(lower_32_bits(dma_rx),
+              ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num));
+
+       /* program tail pointers */
+       /* assumption: upper 32 bits are constant and
+        * same as TX/RX desc list
+        */
+       dma_addr = dma_tx + ((t_rsize - 1) * SXGBE_DESC_SIZE_BYTES);
+       writel(lower_32_bits(dma_addr),
+              ioaddr + SXGBE_DMA_CHA_TXDESC_TAILPTR_REG(cha_num));
+
+       dma_addr = dma_rx + ((r_rsize - 1) * SXGBE_DESC_SIZE_BYTES);
+       writel(lower_32_bits(dma_addr),
+              ioaddr + SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num));
+       /* program the ring sizes */
+       writel(t_rsize - 1, ioaddr + SXGBE_DMA_CHA_TXDESC_RINGLEN_REG(cha_num));
+       writel(r_rsize - 1, ioaddr + SXGBE_DMA_CHA_RXDESC_RINGLEN_REG(cha_num));
+
+       /* Enable TX/RX interrupts */
+       writel(SXGBE_DMA_ENA_INT,
+              ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(cha_num));
+}
+
+static void sxgbe_enable_dma_transmission(void __iomem *ioaddr, int cha_num)
+{
+       u32 tx_config;
+
+       tx_config = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+       tx_config |= SXGBE_TX_START_DMA;
+       writel(tx_config, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cha_num));
+}
+
+static void sxgbe_enable_dma_irq(void __iomem *ioaddr, int dma_cnum)
+{
+       /* Enable TX/RX interrupts */
+       writel(SXGBE_DMA_ENA_INT,
+              ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum));
+}
+
+static void sxgbe_disable_dma_irq(void __iomem *ioaddr, int dma_cnum)
+{
+       /* Disable TX/RX interrupts */
+       writel(0, ioaddr + SXGBE_DMA_CHA_INT_ENABLE_REG(dma_cnum));
+}
+
+static void sxgbe_dma_start_tx(void __iomem *ioaddr, int tchannels)
+{
+       int cnum;
+       u32 tx_ctl_reg;
+
+       for (cnum = 0; cnum < tchannels; cnum++) {
+               tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+               tx_ctl_reg |= SXGBE_TX_ENABLE;
+               writel(tx_ctl_reg,
+                      ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+       }
+}
+
+static void sxgbe_dma_start_tx_queue(void __iomem *ioaddr, int dma_cnum)
+{
+       u32 tx_ctl_reg;
+
+       tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+       tx_ctl_reg |= SXGBE_TX_ENABLE;
+       writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+}
+
+static void sxgbe_dma_stop_tx_queue(void __iomem *ioaddr, int dma_cnum)
+{
+       u32 tx_ctl_reg;
+
+       tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+       tx_ctl_reg &= ~(SXGBE_TX_ENABLE);
+       writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(dma_cnum));
+}
+
+static void sxgbe_dma_stop_tx(void __iomem *ioaddr, int tchannels)
+{
+       int cnum;
+       u32 tx_ctl_reg;
+
+       for (cnum = 0; cnum < tchannels; cnum++) {
+               tx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+               tx_ctl_reg &= ~(SXGBE_TX_ENABLE);
+               writel(tx_ctl_reg, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(cnum));
+       }
+}
+
+static void sxgbe_dma_start_rx(void __iomem *ioaddr, int rchannels)
+{
+       int cnum;
+       u32 rx_ctl_reg;
+
+       for (cnum = 0; cnum < rchannels; cnum++) {
+               rx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+               rx_ctl_reg |= SXGBE_RX_ENABLE;
+               writel(rx_ctl_reg,
+                      ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+       }
+}
+
+static void sxgbe_dma_stop_rx(void __iomem *ioaddr, int rchannels)
+{
+       int cnum;
+       u32 rx_ctl_reg;
+
+       for (cnum = 0; cnum < rchannels; cnum++) {
+               rx_ctl_reg = readl(ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+               rx_ctl_reg &= ~(SXGBE_RX_ENABLE);
+               writel(rx_ctl_reg, ioaddr + SXGBE_DMA_CHA_RXCTL_REG(cnum));
+       }
+}
+
+static int sxgbe_tx_dma_int_status(void __iomem *ioaddr, int channel_no,
+                                  struct sxgbe_extra_stats *x)
+{
+       u32 int_status = readl(ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+       u32 clear_val = 0;
+       u32 ret_val = 0;
+
+       /* TX Normal Interrupt Summary */
+       if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) {
+               x->normal_irq_n++;
+               if (int_status & SXGBE_DMA_INT_STATUS_TI) {
+                       ret_val |= handle_tx;
+                       x->tx_normal_irq_n++;
+                       clear_val |= SXGBE_DMA_INT_STATUS_TI;
+               }
+
+               if (int_status & SXGBE_DMA_INT_STATUS_TBU) {
+                       x->tx_underflow_irq++;
+                       ret_val |= tx_bump_tc;
+                       clear_val |= SXGBE_DMA_INT_STATUS_TBU;
+               }
+       } else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) {
+               /* TX Abnormal Interrupt Summary */
+               if (int_status & SXGBE_DMA_INT_STATUS_TPS) {
+                       ret_val |= tx_hard_error;
+                       clear_val |= SXGBE_DMA_INT_STATUS_TPS;
+                       x->tx_process_stopped_irq++;
+               }
+
+               if (int_status & SXGBE_DMA_INT_STATUS_FBE) {
+                       ret_val |= tx_hard_error;
+                       x->fatal_bus_error_irq++;
+
+                       /* Assumption: FBE bit is the combination of
+                        * all the bus access erros and cleared when
+                        * the respective error bits cleared
+                        */
+
+                       /* check for actual cause */
+                       if (int_status & SXGBE_DMA_INT_STATUS_TEB0) {
+                               x->tx_read_transfer_err++;
+                               clear_val |= SXGBE_DMA_INT_STATUS_TEB0;
+                       } else {
+                               x->tx_write_transfer_err++;
+                       }
+
+                       if (int_status & SXGBE_DMA_INT_STATUS_TEB1) {
+                               x->tx_desc_access_err++;
+                               clear_val |= SXGBE_DMA_INT_STATUS_TEB1;
+                       } else {
+                               x->tx_buffer_access_err++;
+                       }
+
+                       if (int_status & SXGBE_DMA_INT_STATUS_TEB2) {
+                               x->tx_data_transfer_err++;
+                               clear_val |= SXGBE_DMA_INT_STATUS_TEB2;
+                       }
+               }
+
+               /* context descriptor error */
+               if (int_status & SXGBE_DMA_INT_STATUS_CTXTERR) {
+                       x->tx_ctxt_desc_err++;
+                       clear_val |= SXGBE_DMA_INT_STATUS_CTXTERR;
+               }
+       }
+
+       /* clear the served bits */
+       writel(clear_val, ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+
+       return ret_val;
+}
+
+static int sxgbe_rx_dma_int_status(void __iomem *ioaddr, int channel_no,
+                                  struct sxgbe_extra_stats *x)
+{
+       u32 int_status = readl(ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+       u32 clear_val = 0;
+       u32 ret_val = 0;
+
+       /* RX Normal Interrupt Summary */
+       if (likely(int_status & SXGBE_DMA_INT_STATUS_NIS)) {
+               x->normal_irq_n++;
+               if (int_status & SXGBE_DMA_INT_STATUS_RI) {
+                       ret_val |= handle_rx;
+                       x->rx_normal_irq_n++;
+                       clear_val |= SXGBE_DMA_INT_STATUS_RI;
+               }
+       } else if (unlikely(int_status & SXGBE_DMA_INT_STATUS_AIS)) {
+               /* RX Abnormal Interrupt Summary */
+               if (int_status & SXGBE_DMA_INT_STATUS_RBU) {
+                       ret_val |= rx_bump_tc;
+                       clear_val |= SXGBE_DMA_INT_STATUS_RBU;
+                       x->rx_underflow_irq++;
+               }
+
+               if (int_status & SXGBE_DMA_INT_STATUS_RPS) {
+                       ret_val |= rx_hard_error;
+                       clear_val |= SXGBE_DMA_INT_STATUS_RPS;
+                       x->rx_process_stopped_irq++;
+               }
+
+               if (int_status & SXGBE_DMA_INT_STATUS_FBE) {
+                       ret_val |= rx_hard_error;
+                       x->fatal_bus_error_irq++;
+
+                       /* Assumption: FBE bit is the combination of
+                        * all the bus access erros and cleared when
+                        * the respective error bits cleared
+                        */
+
+                       /* check for actual cause */
+                       if (int_status & SXGBE_DMA_INT_STATUS_REB0) {
+                               x->rx_read_transfer_err++;
+                               clear_val |= SXGBE_DMA_INT_STATUS_REB0;
+                       } else {
+                               x->rx_write_transfer_err++;
+                       }
+
+                       if (int_status & SXGBE_DMA_INT_STATUS_REB1) {
+                               x->rx_desc_access_err++;
+                               clear_val |= SXGBE_DMA_INT_STATUS_REB1;
+                       } else {
+                               x->rx_buffer_access_err++;
+                       }
+
+                       if (int_status & SXGBE_DMA_INT_STATUS_REB2) {
+                               x->rx_data_transfer_err++;
+                               clear_val |= SXGBE_DMA_INT_STATUS_REB2;
+                       }
+               }
+       }
+
+       /* clear the served bits */
+       writel(clear_val, ioaddr + SXGBE_DMA_CHA_STATUS_REG(channel_no));
+
+       return ret_val;
+}
+
+/* Program the HW RX Watchdog */
+static void sxgbe_dma_rx_watchdog(void __iomem *ioaddr, u32 riwt)
+{
+       u32 que_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, que_num) {
+               writel(riwt,
+                      ioaddr + SXGBE_DMA_CHA_INT_RXWATCHTMR_REG(que_num));
+       }
+}
+
+static void sxgbe_enable_tso(void __iomem *ioaddr, u8 chan_num)
+{
+       u32 ctrl;
+
+       ctrl = readl(ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num));
+       ctrl |= SXGBE_DMA_CHA_TXCTL_TSE_ENABLE;
+       writel(ctrl, ioaddr + SXGBE_DMA_CHA_TXCTL_REG(chan_num));
+}
+
+static const struct sxgbe_dma_ops sxgbe_dma_ops = {
+       .init                           = sxgbe_dma_init,
+       .cha_init                       = sxgbe_dma_channel_init,
+       .enable_dma_transmission        = sxgbe_enable_dma_transmission,
+       .enable_dma_irq                 = sxgbe_enable_dma_irq,
+       .disable_dma_irq                = sxgbe_disable_dma_irq,
+       .start_tx                       = sxgbe_dma_start_tx,
+       .start_tx_queue                 = sxgbe_dma_start_tx_queue,
+       .stop_tx                        = sxgbe_dma_stop_tx,
+       .stop_tx_queue                  = sxgbe_dma_stop_tx_queue,
+       .start_rx                       = sxgbe_dma_start_rx,
+       .stop_rx                        = sxgbe_dma_stop_rx,
+       .tx_dma_int_status              = sxgbe_tx_dma_int_status,
+       .rx_dma_int_status              = sxgbe_rx_dma_int_status,
+       .rx_watchdog                    = sxgbe_dma_rx_watchdog,
+       .enable_tso                     = sxgbe_enable_tso,
+};
+
+const struct sxgbe_dma_ops *sxgbe_get_dma_ops(void)
+{
+       return &sxgbe_dma_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.h
new file mode 100644 (file)
index 0000000..1607b54
--- /dev/null
@@ -0,0 +1,50 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 __SXGBE_DMA_H__
+#define __SXGBE_DMA_H__
+
+/* forward declaration */
+struct sxgbe_extra_stats;
+
+#define SXGBE_DMA_BLENMAP_LSHIFT       1
+#define SXGBE_DMA_TXPBL_LSHIFT         16
+#define SXGBE_DMA_RXPBL_LSHIFT         16
+#define DEFAULT_DMA_PBL                        8
+
+struct sxgbe_dma_ops {
+       /* DMA core initialization */
+       int (*init)(void __iomem *ioaddr, int fix_burst, int burst_map);
+       void (*cha_init)(void __iomem *ioaddr, int cha_num, int fix_burst,
+                        int pbl, dma_addr_t dma_tx, dma_addr_t dma_rx,
+                        int t_rzie, int r_rsize);
+       void (*enable_dma_transmission)(void __iomem *ioaddr, int dma_cnum);
+       void (*enable_dma_irq)(void __iomem *ioaddr, int dma_cnum);
+       void (*disable_dma_irq)(void __iomem *ioaddr, int dma_cnum);
+       void (*start_tx)(void __iomem *ioaddr, int tchannels);
+       void (*start_tx_queue)(void __iomem *ioaddr, int dma_cnum);
+       void (*stop_tx)(void __iomem *ioaddr, int tchannels);
+       void (*stop_tx_queue)(void __iomem *ioaddr, int dma_cnum);
+       void (*start_rx)(void __iomem *ioaddr, int rchannels);
+       void (*stop_rx)(void __iomem *ioaddr, int rchannels);
+       int (*tx_dma_int_status)(void __iomem *ioaddr, int channel_no,
+                                struct sxgbe_extra_stats *x);
+       int (*rx_dma_int_status)(void __iomem *ioaddr, int channel_no,
+                                struct sxgbe_extra_stats *x);
+       /* Program the HW RX Watchdog */
+       void (*rx_watchdog)(void __iomem *ioaddr, u32 riwt);
+       /* Enable TSO for each DMA channel */
+       void (*enable_tso)(void __iomem *ioaddr, u8 chan_num);
+};
+
+const struct sxgbe_dma_ops *sxgbe_get_dma_ops(void);
+
+#endif /* __SXGBE_CORE_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c
new file mode 100644 (file)
index 0000000..0415fa5
--- /dev/null
@@ -0,0 +1,524 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/net_tstamp.h>
+#include <linux/phy.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+#include "sxgbe_dma.h"
+
+struct sxgbe_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int sizeof_stat;
+       int stat_offset;
+};
+
+#define SXGBE_STAT(m)                                          \
+{                                                              \
+       #m,                                                     \
+       FIELD_SIZEOF(struct sxgbe_extra_stats, m),              \
+       offsetof(struct sxgbe_priv_data, xstats.m)              \
+}
+
+static const struct sxgbe_stats sxgbe_gstrings_stats[] = {
+       /* TX/RX IRQ events */
+       SXGBE_STAT(tx_process_stopped_irq),
+       SXGBE_STAT(tx_ctxt_desc_err),
+       SXGBE_STAT(tx_threshold),
+       SXGBE_STAT(rx_threshold),
+       SXGBE_STAT(tx_pkt_n),
+       SXGBE_STAT(rx_pkt_n),
+       SXGBE_STAT(normal_irq_n),
+       SXGBE_STAT(tx_normal_irq_n),
+       SXGBE_STAT(rx_normal_irq_n),
+       SXGBE_STAT(napi_poll),
+       SXGBE_STAT(tx_clean),
+       SXGBE_STAT(tx_reset_ic_bit),
+       SXGBE_STAT(rx_process_stopped_irq),
+       SXGBE_STAT(rx_underflow_irq),
+
+       /* Bus access errors */
+       SXGBE_STAT(fatal_bus_error_irq),
+       SXGBE_STAT(tx_read_transfer_err),
+       SXGBE_STAT(tx_write_transfer_err),
+       SXGBE_STAT(tx_desc_access_err),
+       SXGBE_STAT(tx_buffer_access_err),
+       SXGBE_STAT(tx_data_transfer_err),
+       SXGBE_STAT(rx_read_transfer_err),
+       SXGBE_STAT(rx_write_transfer_err),
+       SXGBE_STAT(rx_desc_access_err),
+       SXGBE_STAT(rx_buffer_access_err),
+       SXGBE_STAT(rx_data_transfer_err),
+
+       /* EEE-LPI stats */
+       SXGBE_STAT(tx_lpi_entry_n),
+       SXGBE_STAT(tx_lpi_exit_n),
+       SXGBE_STAT(rx_lpi_entry_n),
+       SXGBE_STAT(rx_lpi_exit_n),
+       SXGBE_STAT(eee_wakeup_error_n),
+
+       /* RX specific */
+       /* L2 error */
+       SXGBE_STAT(rx_code_gmii_err),
+       SXGBE_STAT(rx_watchdog_err),
+       SXGBE_STAT(rx_crc_err),
+       SXGBE_STAT(rx_gaint_pkt_err),
+       SXGBE_STAT(ip_hdr_err),
+       SXGBE_STAT(ip_payload_err),
+       SXGBE_STAT(overflow_error),
+
+       /* L2 Pkt type */
+       SXGBE_STAT(len_pkt),
+       SXGBE_STAT(mac_ctl_pkt),
+       SXGBE_STAT(dcb_ctl_pkt),
+       SXGBE_STAT(arp_pkt),
+       SXGBE_STAT(oam_pkt),
+       SXGBE_STAT(untag_okt),
+       SXGBE_STAT(other_pkt),
+       SXGBE_STAT(svlan_tag_pkt),
+       SXGBE_STAT(cvlan_tag_pkt),
+       SXGBE_STAT(dvlan_ocvlan_icvlan_pkt),
+       SXGBE_STAT(dvlan_osvlan_isvlan_pkt),
+       SXGBE_STAT(dvlan_osvlan_icvlan_pkt),
+       SXGBE_STAT(dvan_ocvlan_icvlan_pkt),
+
+       /* L3/L4 Pkt type */
+       SXGBE_STAT(not_ip_pkt),
+       SXGBE_STAT(ip4_tcp_pkt),
+       SXGBE_STAT(ip4_udp_pkt),
+       SXGBE_STAT(ip4_icmp_pkt),
+       SXGBE_STAT(ip4_unknown_pkt),
+       SXGBE_STAT(ip6_tcp_pkt),
+       SXGBE_STAT(ip6_udp_pkt),
+       SXGBE_STAT(ip6_icmp_pkt),
+       SXGBE_STAT(ip6_unknown_pkt),
+
+       /* Filter specific */
+       SXGBE_STAT(vlan_filter_match),
+       SXGBE_STAT(sa_filter_fail),
+       SXGBE_STAT(da_filter_fail),
+       SXGBE_STAT(hash_filter_pass),
+       SXGBE_STAT(l3_filter_match),
+       SXGBE_STAT(l4_filter_match),
+
+       /* RX context specific */
+       SXGBE_STAT(timestamp_dropped),
+       SXGBE_STAT(rx_msg_type_no_ptp),
+       SXGBE_STAT(rx_ptp_type_sync),
+       SXGBE_STAT(rx_ptp_type_follow_up),
+       SXGBE_STAT(rx_ptp_type_delay_req),
+       SXGBE_STAT(rx_ptp_type_delay_resp),
+       SXGBE_STAT(rx_ptp_type_pdelay_req),
+       SXGBE_STAT(rx_ptp_type_pdelay_resp),
+       SXGBE_STAT(rx_ptp_type_pdelay_follow_up),
+       SXGBE_STAT(rx_ptp_announce),
+       SXGBE_STAT(rx_ptp_mgmt),
+       SXGBE_STAT(rx_ptp_signal),
+       SXGBE_STAT(rx_ptp_resv_msg_type),
+};
+#define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats)
+
+static int sxgbe_get_eee(struct net_device *dev,
+                        struct ethtool_eee *edata)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       if (!priv->hw_cap.eee)
+               return -EOPNOTSUPP;
+
+       edata->eee_enabled = priv->eee_enabled;
+       edata->eee_active = priv->eee_active;
+       edata->tx_lpi_timer = priv->tx_lpi_timer;
+
+       return phy_ethtool_get_eee(priv->phydev, edata);
+}
+
+static int sxgbe_set_eee(struct net_device *dev,
+                        struct ethtool_eee *edata)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       priv->eee_enabled = edata->eee_enabled;
+
+       if (!priv->eee_enabled) {
+               sxgbe_disable_eee_mode(priv);
+       } else {
+               /* We are asking for enabling the EEE but it is safe
+                * to verify all by invoking the eee_init function.
+                * In case of failure it will return an error.
+                */
+               priv->eee_enabled = sxgbe_eee_init(priv);
+               if (!priv->eee_enabled)
+                       return -EOPNOTSUPP;
+
+               /* Do not change tx_lpi_timer in case of failure */
+               priv->tx_lpi_timer = edata->tx_lpi_timer;
+       }
+
+       return phy_ethtool_set_eee(priv->phydev, edata);
+}
+
+static void sxgbe_getdrvinfo(struct net_device *dev,
+                            struct ethtool_drvinfo *info)
+{
+       strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+       strlcpy(info->version, DRV_VERSION, sizeof(info->version));
+}
+
+static int sxgbe_getsettings(struct net_device *dev,
+                            struct ethtool_cmd *cmd)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       if (priv->phydev)
+               return phy_ethtool_gset(priv->phydev, cmd);
+
+       return -EOPNOTSUPP;
+}
+
+static int sxgbe_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       if (priv->phydev)
+               return phy_ethtool_sset(priv->phydev, cmd);
+
+       return -EOPNOTSUPP;
+}
+
+static u32 sxgbe_getmsglevel(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       return priv->msg_enable;
+}
+
+static void sxgbe_setmsglevel(struct net_device *dev, u32 level)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       priv->msg_enable = level;
+}
+
+static void sxgbe_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       int i;
+       u8 *p = data;
+
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < SXGBE_STATS_LEN; i++) {
+                       memcpy(p, sxgbe_gstrings_stats[i].stat_string,
+                              ETH_GSTRING_LEN);
+                       p += ETH_GSTRING_LEN;
+               }
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+static int sxgbe_get_sset_count(struct net_device *netdev, int sset)
+{
+       int len;
+
+       switch (sset) {
+       case ETH_SS_STATS:
+               len = SXGBE_STATS_LEN;
+               return len;
+       default:
+               return -EINVAL;
+       }
+}
+
+static void sxgbe_get_ethtool_stats(struct net_device *dev,
+                                   struct ethtool_stats *dummy, u64 *data)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       int i;
+       char *p;
+
+       if (priv->eee_enabled) {
+               int val = phy_get_eee_err(priv->phydev);
+
+               if (val)
+                       priv->xstats.eee_wakeup_error_n = val;
+       }
+
+       for (i = 0; i < SXGBE_STATS_LEN; i++) {
+               p = (char *)priv + sxgbe_gstrings_stats[i].stat_offset;
+               data[i] = (sxgbe_gstrings_stats[i].sizeof_stat == sizeof(u64))
+                       ? (*(u64 *)p) : (*(u32 *)p);
+       }
+}
+
+static void sxgbe_get_channels(struct net_device *dev,
+                              struct ethtool_channels *channel)
+{
+       channel->max_rx = SXGBE_MAX_RX_CHANNELS;
+       channel->max_tx = SXGBE_MAX_TX_CHANNELS;
+       channel->rx_count = SXGBE_RX_QUEUES;
+       channel->tx_count = SXGBE_TX_QUEUES;
+}
+
+static u32 sxgbe_riwt2usec(u32 riwt, struct sxgbe_priv_data *priv)
+{
+       unsigned long clk = clk_get_rate(priv->sxgbe_clk);
+
+       if (!clk)
+               return 0;
+
+       return (riwt * 256) / (clk / 1000000);
+}
+
+static u32 sxgbe_usec2riwt(u32 usec, struct sxgbe_priv_data *priv)
+{
+       unsigned long clk = clk_get_rate(priv->sxgbe_clk);
+
+       if (!clk)
+               return 0;
+
+       return (usec * (clk / 1000000)) / 256;
+}
+
+static int sxgbe_get_coalesce(struct net_device *dev,
+                             struct ethtool_coalesce *ec)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       if (priv->use_riwt)
+               ec->rx_coalesce_usecs = sxgbe_riwt2usec(priv->rx_riwt, priv);
+
+       return 0;
+}
+
+static int sxgbe_set_coalesce(struct net_device *dev,
+                             struct ethtool_coalesce *ec)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       unsigned int rx_riwt;
+
+       if (!ec->rx_coalesce_usecs)
+               return -EINVAL;
+
+       rx_riwt = sxgbe_usec2riwt(ec->rx_coalesce_usecs, priv);
+
+       if ((rx_riwt > SXGBE_MAX_DMA_RIWT) || (rx_riwt < SXGBE_MIN_DMA_RIWT))
+               return -EINVAL;
+       else if (!priv->use_riwt)
+               return -EOPNOTSUPP;
+
+       priv->rx_riwt = rx_riwt;
+       priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);
+
+       return 0;
+}
+
+static int sxgbe_get_rss_hash_opts(struct sxgbe_priv_data *priv,
+                                  struct ethtool_rxnfc *cmd)
+{
+       cmd->data = 0;
+
+       /* Report default options for RSS on sxgbe */
+       switch (cmd->flow_type) {
+       case TCP_V4_FLOW:
+       case UDP_V4_FLOW:
+               cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+       case SCTP_V4_FLOW:
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case IPV4_FLOW:
+               cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+               break;
+       case TCP_V6_FLOW:
+       case UDP_V6_FLOW:
+               cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+       case SCTP_V6_FLOW:
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case IPV6_FLOW:
+               cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int sxgbe_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
+                          u32 *rule_locs)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_GRXFH:
+               ret = sxgbe_get_rss_hash_opts(priv, cmd);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static int sxgbe_set_rss_hash_opt(struct sxgbe_priv_data *priv,
+                                 struct ethtool_rxnfc *cmd)
+{
+       u32 reg_val = 0;
+
+       /* RSS does not support anything other than hashing
+        * to queues on src and dst IPs and ports
+        */
+       if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST |
+                         RXH_L4_B_0_1 | RXH_L4_B_2_3))
+               return -EINVAL;
+
+       switch (cmd->flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               if (!(cmd->data & RXH_IP_SRC) ||
+                   !(cmd->data & RXH_IP_DST) ||
+                   !(cmd->data & RXH_L4_B_0_1) ||
+                   !(cmd->data & RXH_L4_B_2_3))
+                       return -EINVAL;
+               reg_val = SXGBE_CORE_RSS_CTL_TCP4TE;
+               break;
+       case UDP_V4_FLOW:
+       case UDP_V6_FLOW:
+               if (!(cmd->data & RXH_IP_SRC) ||
+                   !(cmd->data & RXH_IP_DST) ||
+                   !(cmd->data & RXH_L4_B_0_1) ||
+                   !(cmd->data & RXH_L4_B_2_3))
+                       return -EINVAL;
+               reg_val = SXGBE_CORE_RSS_CTL_UDP4TE;
+               break;
+       case SCTP_V4_FLOW:
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case SCTP_V6_FLOW:
+       case IPV4_FLOW:
+       case IPV6_FLOW:
+               if (!(cmd->data & RXH_IP_SRC) ||
+                   !(cmd->data & RXH_IP_DST) ||
+                   (cmd->data & RXH_L4_B_0_1) ||
+                   (cmd->data & RXH_L4_B_2_3))
+                       return -EINVAL;
+               reg_val = SXGBE_CORE_RSS_CTL_IP2TE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Read SXGBE RSS control register and update */
+       reg_val |= readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
+       writel(reg_val, priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
+       readl(priv->ioaddr + SXGBE_CORE_RSS_CTL_REG);
+
+       return 0;
+}
+
+static int sxgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_SRXFH:
+               ret = sxgbe_set_rss_hash_opt(priv, cmd);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static void sxgbe_get_regs(struct net_device *dev,
+                          struct ethtool_regs *regs, void *space)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       u32 *reg_space = (u32 *)space;
+       int reg_offset;
+       int reg_ix = 0;
+       void __iomem *ioaddr = priv->ioaddr;
+
+       memset(reg_space, 0x0, REG_SPACE_SIZE);
+
+       /* MAC registers */
+       for (reg_offset = START_MAC_REG_OFFSET;
+            reg_offset <= MAX_MAC_REG_OFFSET; reg_offset += 4) {
+               reg_space[reg_ix] = readl(ioaddr + reg_offset);
+               reg_ix++;
+       }
+
+       /* MTL registers */
+       for (reg_offset = START_MTL_REG_OFFSET;
+            reg_offset <= MAX_MTL_REG_OFFSET; reg_offset += 4) {
+               reg_space[reg_ix] = readl(ioaddr + reg_offset);
+               reg_ix++;
+       }
+
+       /* DMA registers */
+       for (reg_offset = START_DMA_REG_OFFSET;
+            reg_offset <= MAX_DMA_REG_OFFSET; reg_offset += 4) {
+               reg_space[reg_ix] = readl(ioaddr + reg_offset);
+               reg_ix++;
+       }
+
+       BUG_ON(reg_ix * 4 > REG_SPACE_SIZE);
+}
+
+static int sxgbe_get_regs_len(struct net_device *dev)
+{
+       return REG_SPACE_SIZE;
+}
+
+static const struct ethtool_ops sxgbe_ethtool_ops = {
+       .get_drvinfo = sxgbe_getdrvinfo,
+       .get_settings = sxgbe_getsettings,
+       .set_settings = sxgbe_setsettings,
+       .get_msglevel = sxgbe_getmsglevel,
+       .set_msglevel = sxgbe_setmsglevel,
+       .get_link = ethtool_op_get_link,
+       .get_strings = sxgbe_get_strings,
+       .get_ethtool_stats = sxgbe_get_ethtool_stats,
+       .get_sset_count = sxgbe_get_sset_count,
+       .get_channels = sxgbe_get_channels,
+       .get_coalesce = sxgbe_get_coalesce,
+       .set_coalesce = sxgbe_set_coalesce,
+       .get_rxnfc = sxgbe_get_rxnfc,
+       .set_rxnfc = sxgbe_set_rxnfc,
+       .get_regs = sxgbe_get_regs,
+       .get_regs_len = sxgbe_get_regs_len,
+       .get_eee = sxgbe_get_eee,
+       .set_eee = sxgbe_set_eee,
+};
+
+void sxgbe_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &sxgbe_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
new file mode 100644 (file)
index 0000000..a72688e
--- /dev/null
@@ -0,0 +1,2317 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/prefetch.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/sxgbe_platform.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_desc.h"
+#include "sxgbe_dma.h"
+#include "sxgbe_mtl.h"
+#include "sxgbe_reg.h"
+
+#define SXGBE_ALIGN(x) L1_CACHE_ALIGN(x)
+#define JUMBO_LEN      9000
+
+/* Module parameters */
+#define TX_TIMEO       5000
+#define DMA_TX_SIZE    512
+#define DMA_RX_SIZE    1024
+#define TC_DEFAULT     64
+#define DMA_BUFFER_SIZE        BUF_SIZE_2KiB
+/* The default timer value as per the sxgbe specification 1 sec(1000 ms) */
+#define SXGBE_DEFAULT_LPI_TIMER        1000
+
+static int debug = -1;
+static int eee_timer = SXGBE_DEFAULT_LPI_TIMER;
+
+module_param(eee_timer, int, S_IRUGO | S_IWUSR);
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+                                     NETIF_MSG_LINK | NETIF_MSG_IFUP |
+                                     NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
+
+static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id);
+static irqreturn_t sxgbe_tx_interrupt(int irq, void *dev_id);
+static irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id);
+
+#define SXGBE_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+
+#define SXGBE_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
+
+/**
+ * sxgbe_verify_args - verify the driver parameters.
+ * Description: it verifies if some wrong parameter is passed to the driver.
+ * Note that wrong parameters are replaced with the default values.
+ */
+static void sxgbe_verify_args(void)
+{
+       if (unlikely(eee_timer < 0))
+               eee_timer = SXGBE_DEFAULT_LPI_TIMER;
+}
+
+static void sxgbe_enable_eee_mode(const struct sxgbe_priv_data *priv)
+{
+       /* Check and enter in LPI mode */
+       if (!priv->tx_path_in_lpi_mode)
+               priv->hw->mac->set_eee_mode(priv->ioaddr);
+}
+
+void sxgbe_disable_eee_mode(struct sxgbe_priv_data * const priv)
+{
+       /* Exit and disable EEE in case of we are are in LPI state. */
+       priv->hw->mac->reset_eee_mode(priv->ioaddr);
+       del_timer_sync(&priv->eee_ctrl_timer);
+       priv->tx_path_in_lpi_mode = false;
+}
+
+/**
+ * sxgbe_eee_ctrl_timer
+ * @arg : data hook
+ * Description:
+ *  If there is no data transfer and if we are not in LPI state,
+ *  then MAC Transmitter can be moved to LPI state.
+ */
+static void sxgbe_eee_ctrl_timer(unsigned long arg)
+{
+       struct sxgbe_priv_data *priv = (struct sxgbe_priv_data *)arg;
+
+       sxgbe_enable_eee_mode(priv);
+       mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer));
+}
+
+/**
+ * sxgbe_eee_init
+ * @priv: private device pointer
+ * Description:
+ *  If the EEE support has been enabled while configuring the driver,
+ *  if the GMAC actually supports the EEE (from the HW cap reg) and the
+ *  phy can also manage EEE, so enable the LPI state and start the timer
+ *  to verify if the tx path can enter in LPI state.
+ */
+bool sxgbe_eee_init(struct sxgbe_priv_data * const priv)
+{
+       bool ret = false;
+
+       /* MAC core supports the EEE feature. */
+       if (priv->hw_cap.eee) {
+               /* Check if the PHY supports EEE */
+               if (phy_init_eee(priv->phydev, 1))
+                       return false;
+
+               priv->eee_active = 1;
+               init_timer(&priv->eee_ctrl_timer);
+               priv->eee_ctrl_timer.function = sxgbe_eee_ctrl_timer;
+               priv->eee_ctrl_timer.data = (unsigned long)priv;
+               priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer);
+               add_timer(&priv->eee_ctrl_timer);
+
+               priv->hw->mac->set_eee_timer(priv->ioaddr,
+                                            SXGBE_DEFAULT_LPI_TIMER,
+                                            priv->tx_lpi_timer);
+
+               pr_info("Energy-Efficient Ethernet initialized\n");
+
+               ret = true;
+       }
+
+       return ret;
+}
+
+static void sxgbe_eee_adjust(const struct sxgbe_priv_data *priv)
+{
+       /* When the EEE has been already initialised we have to
+        * modify the PLS bit in the LPI ctrl & status reg according
+        * to the PHY link status. For this reason.
+        */
+       if (priv->eee_enabled)
+               priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
+}
+
+/**
+ * sxgbe_clk_csr_set - dynamically set the MDC clock
+ * @priv: driver private structure
+ * Description: this is to dynamically set the MDC clock according to the csr
+ * clock input.
+ */
+static void sxgbe_clk_csr_set(struct sxgbe_priv_data *priv)
+{
+       u32 clk_rate = clk_get_rate(priv->sxgbe_clk);
+
+       /* assign the proper divider, this will be used during
+        * mdio communication
+        */
+       if (clk_rate < SXGBE_CSR_F_150M)
+               priv->clk_csr = SXGBE_CSR_100_150M;
+       else if (clk_rate <= SXGBE_CSR_F_250M)
+               priv->clk_csr = SXGBE_CSR_150_250M;
+       else if (clk_rate <= SXGBE_CSR_F_300M)
+               priv->clk_csr = SXGBE_CSR_250_300M;
+       else if (clk_rate <= SXGBE_CSR_F_350M)
+               priv->clk_csr = SXGBE_CSR_300_350M;
+       else if (clk_rate <= SXGBE_CSR_F_400M)
+               priv->clk_csr = SXGBE_CSR_350_400M;
+       else if (clk_rate <= SXGBE_CSR_F_500M)
+               priv->clk_csr = SXGBE_CSR_400_500M;
+}
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define SXGBE_TX_THRESH(x)     (x->dma_tx_size/4)
+
+static inline u32 sxgbe_tx_avail(struct sxgbe_tx_queue *queue, int tx_qsize)
+{
+       return queue->dirty_tx + tx_qsize - queue->cur_tx - 1;
+}
+
+/**
+ * sxgbe_adjust_link
+ * @dev: net device structure
+ * Description: it adjusts the link parameters.
+ */
+static void sxgbe_adjust_link(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       struct phy_device *phydev = priv->phydev;
+       u8 new_state = 0;
+       u8 speed = 0xff;
+
+       if (!phydev)
+               return;
+
+       /* SXGBE is not supporting auto-negotiation and
+        * half duplex mode. so, not handling duplex change
+        * in this function. only handling speed and link status
+        */
+       if (phydev->link) {
+               if (phydev->speed != priv->speed) {
+                       new_state = 1;
+                       switch (phydev->speed) {
+                       case SPEED_10000:
+                               speed = SXGBE_SPEED_10G;
+                               break;
+                       case SPEED_2500:
+                               speed = SXGBE_SPEED_2_5G;
+                               break;
+                       case SPEED_1000:
+                               speed = SXGBE_SPEED_1G;
+                               break;
+                       default:
+                               netif_err(priv, link, dev,
+                                         "Speed (%d) not supported\n",
+                                         phydev->speed);
+                       }
+
+                       priv->speed = phydev->speed;
+                       priv->hw->mac->set_speed(priv->ioaddr, speed);
+               }
+
+               if (!priv->oldlink) {
+                       new_state = 1;
+                       priv->oldlink = 1;
+               }
+       } else if (priv->oldlink) {
+               new_state = 1;
+               priv->oldlink = 0;
+               priv->speed = SPEED_UNKNOWN;
+       }
+
+       if (new_state & netif_msg_link(priv))
+               phy_print_status(phydev);
+
+       /* Alter the MAC settings for EEE */
+       sxgbe_eee_adjust(priv);
+}
+
+/**
+ * sxgbe_init_phy - PHY initialization
+ * @dev: net device structure
+ * Description: it initializes the driver's PHY state, and attaches the PHY
+ * to the mac driver.
+ *  Return value:
+ *  0 on success
+ */
+static int sxgbe_init_phy(struct net_device *ndev)
+{
+       char phy_id_fmt[MII_BUS_ID_SIZE + 3];
+       char bus_id[MII_BUS_ID_SIZE];
+       struct phy_device *phydev;
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+       int phy_iface = priv->plat->interface;
+
+       /* assign default link status */
+       priv->oldlink = 0;
+       priv->speed = SPEED_UNKNOWN;
+       priv->oldduplex = DUPLEX_UNKNOWN;
+
+       if (priv->plat->phy_bus_name)
+               snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
+                        priv->plat->phy_bus_name, priv->plat->bus_id);
+       else
+               snprintf(bus_id, MII_BUS_ID_SIZE, "sxgbe-%x",
+                        priv->plat->bus_id);
+
+       snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
+                priv->plat->phy_addr);
+       netdev_dbg(ndev, "%s: trying to attach to %s\n", __func__, phy_id_fmt);
+
+       phydev = phy_connect(ndev, phy_id_fmt, &sxgbe_adjust_link, phy_iface);
+
+       if (IS_ERR(phydev)) {
+               netdev_err(ndev, "Could not attach to PHY\n");
+               return PTR_ERR(phydev);
+       }
+
+       /* Stop Advertising 1000BASE Capability if interface is not GMII */
+       if ((phy_iface == PHY_INTERFACE_MODE_MII) ||
+           (phy_iface == PHY_INTERFACE_MODE_RMII))
+               phydev->advertising &= ~(SUPPORTED_1000baseT_Half |
+                                        SUPPORTED_1000baseT_Full);
+       if (phydev->phy_id == 0) {
+               phy_disconnect(phydev);
+               return -ENODEV;
+       }
+
+       netdev_dbg(ndev, "%s: attached to PHY (UID 0x%x) Link = %d\n",
+                  __func__, phydev->phy_id, phydev->link);
+
+       /* save phy device in private structure */
+       priv->phydev = phydev;
+
+       return 0;
+}
+
+/**
+ * sxgbe_clear_descriptors: clear descriptors
+ * @priv: driver private structure
+ * Description: this function is called to clear the tx and rx descriptors
+ * in case of both basic and extended descriptors are used.
+ */
+static void sxgbe_clear_descriptors(struct sxgbe_priv_data *priv)
+{
+       int i, j;
+       unsigned int txsize = priv->dma_tx_size;
+       unsigned int rxsize = priv->dma_rx_size;
+
+       /* Clear the Rx/Tx descriptors */
+       for (j = 0; j < SXGBE_RX_QUEUES; j++) {
+               for (i = 0; i < rxsize; i++)
+                       priv->hw->desc->init_rx_desc(&priv->rxq[j]->dma_rx[i],
+                                                    priv->use_riwt, priv->mode,
+                                                    (i == rxsize - 1));
+       }
+
+       for (j = 0; j < SXGBE_TX_QUEUES; j++) {
+               for (i = 0; i < txsize; i++)
+                       priv->hw->desc->init_tx_desc(&priv->txq[j]->dma_tx[i]);
+       }
+}
+
+static int sxgbe_init_rx_buffers(struct net_device *dev,
+                                struct sxgbe_rx_norm_desc *p, int i,
+                                unsigned int dma_buf_sz,
+                                struct sxgbe_rx_queue *rx_ring)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       struct sk_buff *skb;
+
+       skb = __netdev_alloc_skb_ip_align(dev, dma_buf_sz, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       rx_ring->rx_skbuff[i] = skb;
+       rx_ring->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
+                                                  dma_buf_sz, DMA_FROM_DEVICE);
+
+       if (dma_mapping_error(priv->device, rx_ring->rx_skbuff_dma[i])) {
+               netdev_err(dev, "%s: DMA mapping error\n", __func__);
+               dev_kfree_skb_any(skb);
+               return -EINVAL;
+       }
+
+       p->rdes23.rx_rd_des23.buf2_addr = rx_ring->rx_skbuff_dma[i];
+
+       return 0;
+}
+/**
+ * init_tx_ring - init the TX descriptor ring
+ * @dev: net device structure
+ * @tx_ring: ring to be intialised
+ * @tx_rsize: ring size
+ * Description:  this function initializes the DMA TX descriptor
+ */
+static int init_tx_ring(struct device *dev, u8 queue_no,
+                       struct sxgbe_tx_queue *tx_ring, int tx_rsize)
+{
+       /* TX ring is not allcoated */
+       if (!tx_ring) {
+               dev_err(dev, "No memory for TX queue of SXGBE\n");
+               return -ENOMEM;
+       }
+
+       /* allocate memory for TX descriptors */
+       tx_ring->dma_tx = dma_zalloc_coherent(dev,
+                                             tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
+                                             &tx_ring->dma_tx_phy, GFP_KERNEL);
+       if (!tx_ring->dma_tx)
+               return -ENOMEM;
+
+       /* allocate memory for TX skbuff array */
+       tx_ring->tx_skbuff_dma = devm_kcalloc(dev, tx_rsize,
+                                             sizeof(dma_addr_t), GFP_KERNEL);
+       if (!tx_ring->tx_skbuff_dma)
+               goto dmamem_err;
+
+       tx_ring->tx_skbuff = devm_kcalloc(dev, tx_rsize,
+                                         sizeof(struct sk_buff *), GFP_KERNEL);
+
+       if (!tx_ring->tx_skbuff)
+               goto dmamem_err;
+
+       /* assign queue number */
+       tx_ring->queue_no = queue_no;
+
+       /* initalise counters */
+       tx_ring->dirty_tx = 0;
+       tx_ring->cur_tx = 0;
+
+       /* initalise TX queue lock */
+       spin_lock_init(&tx_ring->tx_lock);
+
+       return 0;
+
+dmamem_err:
+       dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
+                         tx_ring->dma_tx, tx_ring->dma_tx_phy);
+       return -ENOMEM;
+}
+
+/**
+ * free_rx_ring - free the RX descriptor ring
+ * @dev: net device structure
+ * @rx_ring: ring to be intialised
+ * @rx_rsize: ring size
+ * Description:  this function initializes the DMA RX descriptor
+ */
+void free_rx_ring(struct device *dev, struct sxgbe_rx_queue *rx_ring,
+                 int rx_rsize)
+{
+       dma_free_coherent(dev, rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+                         rx_ring->dma_rx, rx_ring->dma_rx_phy);
+       kfree(rx_ring->rx_skbuff_dma);
+       kfree(rx_ring->rx_skbuff);
+}
+
+/**
+ * init_rx_ring - init the RX descriptor ring
+ * @dev: net device structure
+ * @rx_ring: ring to be intialised
+ * @rx_rsize: ring size
+ * Description:  this function initializes the DMA RX descriptor
+ */
+static int init_rx_ring(struct net_device *dev, u8 queue_no,
+                       struct sxgbe_rx_queue *rx_ring, int rx_rsize)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       int desc_index;
+       unsigned int bfsize = 0;
+       unsigned int ret = 0;
+
+       /* Set the max buffer size according to the MTU. */
+       bfsize = ALIGN(dev->mtu + ETH_HLEN + ETH_FCS_LEN + NET_IP_ALIGN, 8);
+
+       netif_dbg(priv, probe, dev, "%s: bfsize %d\n", __func__, bfsize);
+
+       /* RX ring is not allcoated */
+       if (rx_ring == NULL) {
+               netdev_err(dev, "No memory for RX queue\n");
+               goto error;
+       }
+
+       /* assign queue number */
+       rx_ring->queue_no = queue_no;
+
+       /* allocate memory for RX descriptors */
+       rx_ring->dma_rx = dma_zalloc_coherent(priv->device,
+                                             rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+                                             &rx_ring->dma_rx_phy, GFP_KERNEL);
+
+       if (rx_ring->dma_rx == NULL)
+               goto error;
+
+       /* allocate memory for RX skbuff array */
+       rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize,
+                                              sizeof(dma_addr_t), GFP_KERNEL);
+       if (rx_ring->rx_skbuff_dma == NULL)
+               goto dmamem_err;
+
+       rx_ring->rx_skbuff = kmalloc_array(rx_rsize,
+                                          sizeof(struct sk_buff *), GFP_KERNEL);
+       if (rx_ring->rx_skbuff == NULL)
+               goto rxbuff_err;
+
+       /* initialise the buffers */
+       for (desc_index = 0; desc_index < rx_rsize; desc_index++) {
+               struct sxgbe_rx_norm_desc *p;
+               p = rx_ring->dma_rx + desc_index;
+               ret = sxgbe_init_rx_buffers(dev, p, desc_index,
+                                           bfsize, rx_ring);
+               if (ret)
+                       goto err_init_rx_buffers;
+       }
+
+       /* initalise counters */
+       rx_ring->cur_rx = 0;
+       rx_ring->dirty_rx = (unsigned int)(desc_index - rx_rsize);
+       priv->dma_buf_sz = bfsize;
+
+       return 0;
+
+err_init_rx_buffers:
+       while (--desc_index >= 0)
+               free_rx_ring(priv->device, rx_ring, desc_index);
+       kfree(rx_ring->rx_skbuff);
+rxbuff_err:
+       kfree(rx_ring->rx_skbuff_dma);
+dmamem_err:
+       dma_free_coherent(priv->device,
+                         rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+                         rx_ring->dma_rx, rx_ring->dma_rx_phy);
+error:
+       return -ENOMEM;
+}
+/**
+ * free_tx_ring - free the TX descriptor ring
+ * @dev: net device structure
+ * @tx_ring: ring to be intialised
+ * @tx_rsize: ring size
+ * Description:  this function initializes the DMA TX descriptor
+ */
+void free_tx_ring(struct device *dev, struct sxgbe_tx_queue *tx_ring,
+                 int tx_rsize)
+{
+       dma_free_coherent(dev, tx_rsize * sizeof(struct sxgbe_tx_norm_desc),
+                         tx_ring->dma_tx, tx_ring->dma_tx_phy);
+}
+
+/**
+ * init_dma_desc_rings - init the RX/TX descriptor rings
+ * @dev: net device structure
+ * Description:  this function initializes the DMA RX/TX descriptors
+ * and allocates the socket buffers. It suppors the chained and ring
+ * modes.
+ */
+static int init_dma_desc_rings(struct net_device *netd)
+{
+       int queue_num, ret;
+       struct sxgbe_priv_data *priv = netdev_priv(netd);
+       int tx_rsize = priv->dma_tx_size;
+       int rx_rsize = priv->dma_rx_size;
+
+       /* Allocate memory for queue structures and TX descs */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               ret = init_tx_ring(priv->device, queue_num,
+                                  priv->txq[queue_num], tx_rsize);
+               if (ret) {
+                       dev_err(&netd->dev, "TX DMA ring allocation failed!\n");
+                       goto txalloc_err;
+               }
+
+               /* save private pointer in each ring this
+                * pointer is needed during cleaing TX queue
+                */
+               priv->txq[queue_num]->priv_ptr = priv;
+       }
+
+       /* Allocate memory for queue structures and RX descs */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+               ret = init_rx_ring(netd, queue_num,
+                                  priv->rxq[queue_num], rx_rsize);
+               if (ret) {
+                       netdev_err(netd, "RX DMA ring allocation failed!!\n");
+                       goto rxalloc_err;
+               }
+
+               /* save private pointer in each ring this
+                * pointer is needed during cleaing TX queue
+                */
+               priv->rxq[queue_num]->priv_ptr = priv;
+       }
+
+       sxgbe_clear_descriptors(priv);
+
+       return 0;
+
+txalloc_err:
+       while (queue_num--)
+               free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
+       return ret;
+
+rxalloc_err:
+       while (queue_num--)
+               free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+       return ret;
+}
+
+static void tx_free_ring_skbufs(struct sxgbe_tx_queue *txqueue)
+{
+       int dma_desc;
+       struct sxgbe_priv_data *priv = txqueue->priv_ptr;
+       int tx_rsize = priv->dma_tx_size;
+
+       for (dma_desc = 0; dma_desc < tx_rsize; dma_desc++) {
+               struct sxgbe_tx_norm_desc *tdesc = txqueue->dma_tx + dma_desc;
+
+               if (txqueue->tx_skbuff_dma[dma_desc])
+                       dma_unmap_single(priv->device,
+                                        txqueue->tx_skbuff_dma[dma_desc],
+                                        priv->hw->desc->get_tx_len(tdesc),
+                                        DMA_TO_DEVICE);
+
+               dev_kfree_skb_any(txqueue->tx_skbuff[dma_desc]);
+               txqueue->tx_skbuff[dma_desc] = NULL;
+               txqueue->tx_skbuff_dma[dma_desc] = 0;
+       }
+}
+
+
+static void dma_free_tx_skbufs(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               struct sxgbe_tx_queue *tqueue = priv->txq[queue_num];
+               tx_free_ring_skbufs(tqueue);
+       }
+}
+
+static void free_dma_desc_resources(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+       int tx_rsize = priv->dma_tx_size;
+       int rx_rsize = priv->dma_rx_size;
+
+       /* Release the DMA TX buffers */
+       dma_free_tx_skbufs(priv);
+
+       /* Release the TX ring memory also */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               free_tx_ring(priv->device, priv->txq[queue_num], tx_rsize);
+       }
+
+       /* Release the RX ring memory also */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+               free_rx_ring(priv->device, priv->rxq[queue_num], rx_rsize);
+       }
+}
+
+static int txring_mem_alloc(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               priv->txq[queue_num] = devm_kmalloc(priv->device,
+                                                   sizeof(struct sxgbe_tx_queue), GFP_KERNEL);
+               if (!priv->txq[queue_num])
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int rxring_mem_alloc(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+               priv->rxq[queue_num] = devm_kmalloc(priv->device,
+                                                   sizeof(struct sxgbe_rx_queue), GFP_KERNEL);
+               if (!priv->rxq[queue_num])
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ *  sxgbe_mtl_operation_mode - HW MTL operation mode
+ *  @priv: driver private structure
+ *  Description: it sets the MTL operation mode: tx/rx MTL thresholds
+ *  or Store-And-Forward capability.
+ */
+static void sxgbe_mtl_operation_mode(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       /* TX/RX threshold control */
+       if (likely(priv->plat->force_sf_dma_mode)) {
+               /* set TC mode for TX QUEUES */
+               SXGBE_FOR_EACH_QUEUE(priv->hw_cap.tx_mtl_queues, queue_num)
+                       priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, queue_num,
+                                                      SXGBE_MTL_SFMODE);
+               priv->tx_tc = SXGBE_MTL_SFMODE;
+
+               /* set TC mode for RX QUEUES */
+               SXGBE_FOR_EACH_QUEUE(priv->hw_cap.rx_mtl_queues, queue_num)
+                       priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, queue_num,
+                                                      SXGBE_MTL_SFMODE);
+               priv->rx_tc = SXGBE_MTL_SFMODE;
+       } else if (unlikely(priv->plat->force_thresh_dma_mode)) {
+               /* set TC mode for TX QUEUES */
+               SXGBE_FOR_EACH_QUEUE(priv->hw_cap.tx_mtl_queues, queue_num)
+                       priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr, queue_num,
+                                                      priv->tx_tc);
+               /* set TC mode for RX QUEUES */
+               SXGBE_FOR_EACH_QUEUE(priv->hw_cap.rx_mtl_queues, queue_num)
+                       priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr, queue_num,
+                                                      priv->rx_tc);
+       } else {
+               pr_err("ERROR: %s: Invalid TX threshold mode\n", __func__);
+       }
+}
+
+/**
+ * sxgbe_tx_queue_clean:
+ * @priv: driver private structure
+ * Description: it reclaims resources after transmission completes.
+ */
+static void sxgbe_tx_queue_clean(struct sxgbe_tx_queue *tqueue)
+{
+       struct sxgbe_priv_data *priv = tqueue->priv_ptr;
+       unsigned int tx_rsize = priv->dma_tx_size;
+       struct netdev_queue *dev_txq;
+       u8 queue_no = tqueue->queue_no;
+
+       dev_txq = netdev_get_tx_queue(priv->dev, queue_no);
+
+       spin_lock(&tqueue->tx_lock);
+
+       priv->xstats.tx_clean++;
+       while (tqueue->dirty_tx != tqueue->cur_tx) {
+               unsigned int entry = tqueue->dirty_tx % tx_rsize;
+               struct sk_buff *skb = tqueue->tx_skbuff[entry];
+               struct sxgbe_tx_norm_desc *p;
+
+               p = tqueue->dma_tx + entry;
+
+               /* Check if the descriptor is owned by the DMA. */
+               if (priv->hw->desc->get_tx_owner(p))
+                       break;
+
+               if (netif_msg_tx_done(priv))
+                       pr_debug("%s: curr %d, dirty %d\n",
+                                __func__, tqueue->cur_tx, tqueue->dirty_tx);
+
+               if (likely(tqueue->tx_skbuff_dma[entry])) {
+                       dma_unmap_single(priv->device,
+                                        tqueue->tx_skbuff_dma[entry],
+                                        priv->hw->desc->get_tx_len(p),
+                                        DMA_TO_DEVICE);
+                       tqueue->tx_skbuff_dma[entry] = 0;
+               }
+
+               if (likely(skb)) {
+                       dev_kfree_skb(skb);
+                       tqueue->tx_skbuff[entry] = NULL;
+               }
+
+               priv->hw->desc->release_tx_desc(p);
+
+               tqueue->dirty_tx++;
+       }
+
+       /* wake up queue */
+       if (unlikely(netif_tx_queue_stopped(dev_txq) &&
+                    sxgbe_tx_avail(tqueue, tx_rsize) > SXGBE_TX_THRESH(priv))) {
+               netif_tx_lock(priv->dev);
+               if (netif_tx_queue_stopped(dev_txq) &&
+                   sxgbe_tx_avail(tqueue, tx_rsize) > SXGBE_TX_THRESH(priv)) {
+                       if (netif_msg_tx_done(priv))
+                               pr_debug("%s: restart transmit\n", __func__);
+                       netif_tx_wake_queue(dev_txq);
+               }
+               netif_tx_unlock(priv->dev);
+       }
+
+       spin_unlock(&tqueue->tx_lock);
+}
+
+/**
+ * sxgbe_tx_clean:
+ * @priv: driver private structure
+ * Description: it reclaims resources after transmission completes.
+ */
+static void sxgbe_tx_all_clean(struct sxgbe_priv_data * const priv)
+{
+       u8 queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               struct sxgbe_tx_queue *tqueue = priv->txq[queue_num];
+
+               sxgbe_tx_queue_clean(tqueue);
+       }
+
+       if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
+               sxgbe_enable_eee_mode(priv);
+               mod_timer(&priv->eee_ctrl_timer, SXGBE_LPI_TIMER(eee_timer));
+       }
+}
+
+/**
+ * sxgbe_restart_tx_queue: irq tx error mng function
+ * @priv: driver private structure
+ * Description: it cleans the descriptors and restarts the transmission
+ * in case of errors.
+ */
+static void sxgbe_restart_tx_queue(struct sxgbe_priv_data *priv, int queue_num)
+{
+       struct sxgbe_tx_queue *tx_ring = priv->txq[queue_num];
+       struct netdev_queue *dev_txq = netdev_get_tx_queue(priv->dev,
+                                                          queue_num);
+
+       /* stop the queue */
+       netif_tx_stop_queue(dev_txq);
+
+       /* stop the tx dma */
+       priv->hw->dma->stop_tx_queue(priv->ioaddr, queue_num);
+
+       /* free the skbuffs of the ring */
+       tx_free_ring_skbufs(tx_ring);
+
+       /* initalise counters */
+       tx_ring->cur_tx = 0;
+       tx_ring->dirty_tx = 0;
+
+       /* start the tx dma */
+       priv->hw->dma->start_tx_queue(priv->ioaddr, queue_num);
+
+       priv->dev->stats.tx_errors++;
+
+       /* wakeup the queue */
+       netif_tx_wake_queue(dev_txq);
+}
+
+/**
+ * sxgbe_reset_all_tx_queues: irq tx error mng function
+ * @priv: driver private structure
+ * Description: it cleans all the descriptors and
+ * restarts the transmission on all queues in case of errors.
+ */
+static void sxgbe_reset_all_tx_queues(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       /* On TX timeout of net device, resetting of all queues
+        * may not be proper way, revisit this later if needed
+        */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num)
+               sxgbe_restart_tx_queue(priv, queue_num);
+}
+
+/**
+ * sxgbe_get_hw_features: get XMAC capabilities from the HW cap. register.
+ * @priv: driver private structure
+ * Description:
+ *  new GMAC chip generations have a new register to indicate the
+ *  presence of the optional feature/functions.
+ *  This can be also used to override the value passed through the
+ *  platform and necessary for old MAC10/100 and GMAC chips.
+ */
+static int sxgbe_get_hw_features(struct sxgbe_priv_data * const priv)
+{
+       int rval = 0;
+       struct sxgbe_hw_features *features = &priv->hw_cap;
+
+       /* Read First Capability Register CAP[0] */
+       rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 0);
+       if (rval) {
+               features->pmt_remote_wake_up =
+                       SXGBE_HW_FEAT_PMT_TEMOTE_WOP(rval);
+               features->pmt_magic_frame = SXGBE_HW_FEAT_PMT_MAGIC_PKT(rval);
+               features->atime_stamp = SXGBE_HW_FEAT_IEEE1500_2008(rval);
+               features->tx_csum_offload =
+                       SXGBE_HW_FEAT_TX_CSUM_OFFLOAD(rval);
+               features->rx_csum_offload =
+                       SXGBE_HW_FEAT_RX_CSUM_OFFLOAD(rval);
+               features->multi_macaddr = SXGBE_HW_FEAT_MACADDR_COUNT(rval);
+               features->tstamp_srcselect = SXGBE_HW_FEAT_TSTMAP_SRC(rval);
+               features->sa_vlan_insert = SXGBE_HW_FEAT_SRCADDR_VLAN(rval);
+               features->eee = SXGBE_HW_FEAT_EEE(rval);
+       }
+
+       /* Read First Capability Register CAP[1] */
+       rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 1);
+       if (rval) {
+               features->rxfifo_size = SXGBE_HW_FEAT_RX_FIFO_SIZE(rval);
+               features->txfifo_size = SXGBE_HW_FEAT_TX_FIFO_SIZE(rval);
+               features->atstmap_hword = SXGBE_HW_FEAT_TX_FIFO_SIZE(rval);
+               features->dcb_enable = SXGBE_HW_FEAT_DCB(rval);
+               features->splithead_enable = SXGBE_HW_FEAT_SPLIT_HDR(rval);
+               features->tcpseg_offload = SXGBE_HW_FEAT_TSO(rval);
+               features->debug_mem = SXGBE_HW_FEAT_DEBUG_MEM_IFACE(rval);
+               features->rss_enable = SXGBE_HW_FEAT_RSS(rval);
+               features->hash_tsize = SXGBE_HW_FEAT_HASH_TABLE_SIZE(rval);
+               features->l3l4_filer_size = SXGBE_HW_FEAT_L3L4_FILTER_NUM(rval);
+       }
+
+       /* Read First Capability Register CAP[2] */
+       rval = priv->hw->mac->get_hw_feature(priv->ioaddr, 2);
+       if (rval) {
+               features->rx_mtl_queues = SXGBE_HW_FEAT_RX_MTL_QUEUES(rval);
+               features->tx_mtl_queues = SXGBE_HW_FEAT_TX_MTL_QUEUES(rval);
+               features->rx_dma_channels = SXGBE_HW_FEAT_RX_DMA_CHANNELS(rval);
+               features->tx_dma_channels = SXGBE_HW_FEAT_TX_DMA_CHANNELS(rval);
+               features->pps_output_count = SXGBE_HW_FEAT_PPS_OUTPUTS(rval);
+               features->aux_input_count = SXGBE_HW_FEAT_AUX_SNAPSHOTS(rval);
+       }
+
+       return rval;
+}
+
+/**
+ * sxgbe_check_ether_addr: check if the MAC addr is valid
+ * @priv: driver private structure
+ * Description:
+ * it is to verify if the MAC address is valid, in case of failures it
+ * generates a random MAC address
+ */
+static void sxgbe_check_ether_addr(struct sxgbe_priv_data *priv)
+{
+       if (!is_valid_ether_addr(priv->dev->dev_addr)) {
+               priv->hw->mac->get_umac_addr((void __iomem *)
+                                            priv->ioaddr,
+                                            priv->dev->dev_addr, 0);
+               if (!is_valid_ether_addr(priv->dev->dev_addr))
+                       eth_hw_addr_random(priv->dev);
+       }
+       dev_info(priv->device, "device MAC address %pM\n",
+                priv->dev->dev_addr);
+}
+
+/**
+ * sxgbe_init_dma_engine: DMA init.
+ * @priv: driver private structure
+ * Description:
+ * It inits the DMA invoking the specific SXGBE callback.
+ * Some DMA parameters can be passed from the platform;
+ * in case of these are not passed a default is kept for the MAC or GMAC.
+ */
+static int sxgbe_init_dma_engine(struct sxgbe_priv_data *priv)
+{
+       int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_map = 0;
+       int queue_num;
+
+       if (priv->plat->dma_cfg) {
+               pbl = priv->plat->dma_cfg->pbl;
+               fixed_burst = priv->plat->dma_cfg->fixed_burst;
+               burst_map = priv->plat->dma_cfg->burst_map;
+       }
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num)
+               priv->hw->dma->cha_init(priv->ioaddr, queue_num,
+                                       fixed_burst, pbl,
+                                       (priv->txq[queue_num])->dma_tx_phy,
+                                       (priv->rxq[queue_num])->dma_rx_phy,
+                                       priv->dma_tx_size, priv->dma_rx_size);
+
+       return priv->hw->dma->init(priv->ioaddr, fixed_burst, burst_map);
+}
+
+/**
+ * sxgbe_init_mtl_engine: MTL init.
+ * @priv: driver private structure
+ * Description:
+ * It inits the MTL invoking the specific SXGBE callback.
+ */
+static void sxgbe_init_mtl_engine(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               priv->hw->mtl->mtl_set_txfifosize(priv->ioaddr, queue_num,
+                                                 priv->hw_cap.tx_mtl_qsize);
+               priv->hw->mtl->mtl_enable_txqueue(priv->ioaddr, queue_num);
+       }
+}
+
+/**
+ * sxgbe_disable_mtl_engine: MTL disable.
+ * @priv: driver private structure
+ * Description:
+ * It disables the MTL queues by invoking the specific SXGBE callback.
+ */
+static void sxgbe_disable_mtl_engine(struct sxgbe_priv_data *priv)
+{
+       int queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num)
+               priv->hw->mtl->mtl_disable_txqueue(priv->ioaddr, queue_num);
+}
+
+
+/**
+ * sxgbe_tx_timer: mitigation sw timer for tx.
+ * @data: data pointer
+ * Description:
+ * This is the timer handler to directly invoke the sxgbe_tx_clean.
+ */
+static void sxgbe_tx_timer(unsigned long data)
+{
+       struct sxgbe_tx_queue *p = (struct sxgbe_tx_queue *)data;
+       sxgbe_tx_queue_clean(p);
+}
+
+/**
+ * sxgbe_init_tx_coalesce: init tx mitigation options.
+ * @priv: driver private structure
+ * Description:
+ * This inits the transmit coalesce parameters: i.e. timer rate,
+ * timer handler and default threshold used for enabling the
+ * interrupt on completion bit.
+ */
+static void sxgbe_tx_init_coalesce(struct sxgbe_priv_data *priv)
+{
+       u8 queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               struct sxgbe_tx_queue *p = priv->txq[queue_num];
+               p->tx_coal_frames =  SXGBE_TX_FRAMES;
+               p->tx_coal_timer = SXGBE_COAL_TX_TIMER;
+               init_timer(&p->txtimer);
+               p->txtimer.expires = SXGBE_COAL_TIMER(p->tx_coal_timer);
+               p->txtimer.data = (unsigned long)&priv->txq[queue_num];
+               p->txtimer.function = sxgbe_tx_timer;
+               add_timer(&p->txtimer);
+       }
+}
+
+static void sxgbe_tx_del_timer(struct sxgbe_priv_data *priv)
+{
+       u8 queue_num;
+
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               struct sxgbe_tx_queue *p = priv->txq[queue_num];
+               del_timer_sync(&p->txtimer);
+       }
+}
+
+/**
+ *  sxgbe_open - open entry point of the driver
+ *  @dev : pointer to the device structure.
+ *  Description:
+ *  This function is the open entry point of the driver.
+ *  Return value:
+ *  0 on success and an appropriate (-)ve integer as defined in errno.h
+ *  file on failure.
+ */
+static int sxgbe_open(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       int ret, queue_num;
+
+       clk_prepare_enable(priv->sxgbe_clk);
+
+       sxgbe_check_ether_addr(priv);
+
+       /* Init the phy */
+       ret = sxgbe_init_phy(dev);
+       if (ret) {
+               netdev_err(dev, "%s: Cannot attach to PHY (error: %d)\n",
+                          __func__, ret);
+               goto phy_error;
+       }
+
+       /* Create and initialize the TX/RX descriptors chains. */
+       priv->dma_tx_size = SXGBE_ALIGN(DMA_TX_SIZE);
+       priv->dma_rx_size = SXGBE_ALIGN(DMA_RX_SIZE);
+       priv->dma_buf_sz = SXGBE_ALIGN(DMA_BUFFER_SIZE);
+       priv->tx_tc = TC_DEFAULT;
+       priv->rx_tc = TC_DEFAULT;
+       init_dma_desc_rings(dev);
+
+       /* DMA initialization and SW reset */
+       ret = sxgbe_init_dma_engine(priv);
+       if (ret < 0) {
+               netdev_err(dev, "%s: DMA initialization failed\n", __func__);
+               goto init_error;
+       }
+
+       /*  MTL initialization */
+       sxgbe_init_mtl_engine(priv);
+
+       /* Copy the MAC addr into the HW  */
+       priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
+
+       /* Initialize the MAC Core */
+       priv->hw->mac->core_init(priv->ioaddr);
+
+       /* Request the IRQ lines */
+       ret = devm_request_irq(priv->device, priv->irq, sxgbe_common_interrupt,
+                              IRQF_SHARED, dev->name, dev);
+       if (unlikely(ret < 0)) {
+               netdev_err(dev, "%s: ERROR: allocating the IRQ %d (error: %d)\n",
+                          __func__, priv->irq, ret);
+               goto init_error;
+       }
+
+       /* If the LPI irq is different from the mac irq
+        * register a dedicated handler
+        */
+       if (priv->lpi_irq != dev->irq) {
+               ret = devm_request_irq(priv->device, priv->lpi_irq,
+                                      sxgbe_common_interrupt,
+                                      IRQF_SHARED, dev->name, dev);
+               if (unlikely(ret < 0)) {
+                       netdev_err(dev, "%s: ERROR: allocating the LPI IRQ %d (%d)\n",
+                                  __func__, priv->lpi_irq, ret);
+                       goto init_error;
+               }
+       }
+
+       /* Request TX DMA irq lines */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+               ret = devm_request_irq(priv->device,
+                                      (priv->txq[queue_num])->irq_no,
+                                      sxgbe_tx_interrupt, 0,
+                                      dev->name, priv->txq[queue_num]);
+               if (unlikely(ret < 0)) {
+                       netdev_err(dev, "%s: ERROR: allocating TX IRQ %d (error: %d)\n",
+                                  __func__, priv->irq, ret);
+                       goto init_error;
+               }
+       }
+
+       /* Request RX DMA irq lines */
+       SXGBE_FOR_EACH_QUEUE(SXGBE_RX_QUEUES, queue_num) {
+               ret = devm_request_irq(priv->device,
+                                      (priv->rxq[queue_num])->irq_no,
+                                      sxgbe_rx_interrupt, 0,
+                                      dev->name, priv->rxq[queue_num]);
+               if (unlikely(ret < 0)) {
+                       netdev_err(dev, "%s: ERROR: allocating TX IRQ %d (error: %d)\n",
+                                  __func__, priv->irq, ret);
+                       goto init_error;
+               }
+       }
+
+       /* Enable the MAC Rx/Tx */
+       priv->hw->mac->enable_tx(priv->ioaddr, true);
+       priv->hw->mac->enable_rx(priv->ioaddr, true);
+
+       /* Set the HW DMA mode and the COE */
+       sxgbe_mtl_operation_mode(priv);
+
+       /* Extra statistics */
+       memset(&priv->xstats, 0, sizeof(struct sxgbe_extra_stats));
+
+       priv->xstats.tx_threshold = priv->tx_tc;
+       priv->xstats.rx_threshold = priv->rx_tc;
+
+       /* Start the ball rolling... */
+       netdev_dbg(dev, "DMA RX/TX processes started...\n");
+       priv->hw->dma->start_tx(priv->ioaddr, SXGBE_TX_QUEUES);
+       priv->hw->dma->start_rx(priv->ioaddr, SXGBE_RX_QUEUES);
+
+       if (priv->phydev)
+               phy_start(priv->phydev);
+
+       /* initalise TX coalesce parameters */
+       sxgbe_tx_init_coalesce(priv);
+
+       if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
+               priv->rx_riwt = SXGBE_MAX_DMA_RIWT;
+               priv->hw->dma->rx_watchdog(priv->ioaddr, SXGBE_MAX_DMA_RIWT);
+       }
+
+       priv->tx_lpi_timer = SXGBE_DEFAULT_LPI_TIMER;
+       priv->eee_enabled = sxgbe_eee_init(priv);
+
+       napi_enable(&priv->napi);
+       netif_start_queue(dev);
+
+       return 0;
+
+init_error:
+       free_dma_desc_resources(priv);
+       if (priv->phydev)
+               phy_disconnect(priv->phydev);
+phy_error:
+       clk_disable_unprepare(priv->sxgbe_clk);
+
+       return ret;
+}
+
+/**
+ *  sxgbe_release - close entry point of the driver
+ *  @dev : device pointer.
+ *  Description:
+ *  This is the stop entry point of the driver.
+ */
+static int sxgbe_release(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       if (priv->eee_enabled)
+               del_timer_sync(&priv->eee_ctrl_timer);
+
+       /* Stop and disconnect the PHY */
+       if (priv->phydev) {
+               phy_stop(priv->phydev);
+               phy_disconnect(priv->phydev);
+               priv->phydev = NULL;
+       }
+
+       netif_tx_stop_all_queues(dev);
+
+       napi_disable(&priv->napi);
+
+       /* delete TX timers */
+       sxgbe_tx_del_timer(priv);
+
+       /* Stop TX/RX DMA and clear the descriptors */
+       priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES);
+       priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES);
+
+       /* disable MTL queue */
+       sxgbe_disable_mtl_engine(priv);
+
+       /* Release and free the Rx/Tx resources */
+       free_dma_desc_resources(priv);
+
+       /* Disable the MAC Rx/Tx */
+       priv->hw->mac->enable_tx(priv->ioaddr, false);
+       priv->hw->mac->enable_rx(priv->ioaddr, false);
+
+       clk_disable_unprepare(priv->sxgbe_clk);
+
+       return 0;
+}
+
+/* Prepare first Tx descriptor for doing TSO operation */
+void sxgbe_tso_prepare(struct sxgbe_priv_data *priv,
+                      struct sxgbe_tx_norm_desc *first_desc,
+                      struct sk_buff *skb)
+{
+       unsigned int total_hdr_len, tcp_hdr_len;
+
+       /* Write first Tx descriptor with appropriate value */
+       tcp_hdr_len = tcp_hdrlen(skb);
+       total_hdr_len = skb_transport_offset(skb) + tcp_hdr_len;
+
+       first_desc->tdes01 = dma_map_single(priv->device, skb->data,
+                                           total_hdr_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(priv->device, first_desc->tdes01))
+               pr_err("%s: TX dma mapping failed!!\n", __func__);
+
+       first_desc->tdes23.tx_rd_des23.first_desc = 1;
+       priv->hw->desc->tx_desc_enable_tse(first_desc, 1, total_hdr_len,
+                                          tcp_hdr_len,
+                                          skb->len - total_hdr_len);
+}
+
+/**
+ *  sxgbe_xmit: Tx entry point of the driver
+ *  @skb : the socket buffer
+ *  @dev : device pointer
+ *  Description : this is the tx entry point of the driver.
+ *  It programs the chain or the ring and supports oversized frames
+ *  and SG feature.
+ */
+static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned int entry, frag_num;
+       int cksum_flag = 0;
+       struct netdev_queue *dev_txq;
+       unsigned txq_index = skb_get_queue_mapping(skb);
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       unsigned int tx_rsize = priv->dma_tx_size;
+       struct sxgbe_tx_queue *tqueue = priv->txq[txq_index];
+       struct sxgbe_tx_norm_desc *tx_desc, *first_desc;
+       struct sxgbe_tx_ctxt_desc *ctxt_desc = NULL;
+       int nr_frags = skb_shinfo(skb)->nr_frags;
+       int no_pagedlen = skb_headlen(skb);
+       int is_jumbo = 0;
+       u16 cur_mss = skb_shinfo(skb)->gso_size;
+       u32 ctxt_desc_req = 0;
+
+       /* get the TX queue handle */
+       dev_txq = netdev_get_tx_queue(dev, txq_index);
+
+       if (unlikely(skb_is_gso(skb) && tqueue->prev_mss != cur_mss))
+               ctxt_desc_req = 1;
+
+       if (unlikely(vlan_tx_tag_present(skb) ||
+                    ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+                     tqueue->hwts_tx_en)))
+               ctxt_desc_req = 1;
+
+       /* get the spinlock */
+       spin_lock(&tqueue->tx_lock);
+
+       if (priv->tx_path_in_lpi_mode)
+               sxgbe_disable_eee_mode(priv);
+
+       if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) < nr_frags + 1)) {
+               if (!netif_tx_queue_stopped(dev_txq)) {
+                       netif_tx_stop_queue(dev_txq);
+                       netdev_err(dev, "%s: Tx Ring is full when %d queue is awake\n",
+                                  __func__, txq_index);
+               }
+               /* release the spin lock in case of BUSY */
+               spin_unlock(&tqueue->tx_lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       entry = tqueue->cur_tx % tx_rsize;
+       tx_desc = tqueue->dma_tx + entry;
+
+       first_desc = tx_desc;
+       if (ctxt_desc_req)
+               ctxt_desc = (struct sxgbe_tx_ctxt_desc *)first_desc;
+
+       /* save the skb address */
+       tqueue->tx_skbuff[entry] = skb;
+
+       if (!is_jumbo) {
+               if (likely(skb_is_gso(skb))) {
+                       /* TSO support */
+                       if (unlikely(tqueue->prev_mss != cur_mss)) {
+                               priv->hw->desc->tx_ctxt_desc_set_mss(
+                                               ctxt_desc, cur_mss);
+                               priv->hw->desc->tx_ctxt_desc_set_tcmssv(
+                                               ctxt_desc);
+                               priv->hw->desc->tx_ctxt_desc_reset_ostc(
+                                               ctxt_desc);
+                               priv->hw->desc->tx_ctxt_desc_set_ctxt(
+                                               ctxt_desc);
+                               priv->hw->desc->tx_ctxt_desc_set_owner(
+                                               ctxt_desc);
+
+                               entry = (++tqueue->cur_tx) % tx_rsize;
+                               first_desc = tqueue->dma_tx + entry;
+
+                               tqueue->prev_mss = cur_mss;
+                       }
+                       sxgbe_tso_prepare(priv, first_desc, skb);
+               } else {
+                       tx_desc->tdes01 = dma_map_single(priv->device,
+                                                        skb->data, no_pagedlen, DMA_TO_DEVICE);
+                       if (dma_mapping_error(priv->device, tx_desc->tdes01))
+                               netdev_err(dev, "%s: TX dma mapping failed!!\n",
+                                          __func__);
+
+                       priv->hw->desc->prepare_tx_desc(tx_desc, 1, no_pagedlen,
+                                                       no_pagedlen, cksum_flag);
+               }
+       }
+
+       for (frag_num = 0; frag_num < nr_frags; frag_num++) {
+               const skb_frag_t *frag = &skb_shinfo(skb)->frags[frag_num];
+               int len = skb_frag_size(frag);
+
+               entry = (++tqueue->cur_tx) % tx_rsize;
+               tx_desc = tqueue->dma_tx + entry;
+               tx_desc->tdes01 = skb_frag_dma_map(priv->device, frag, 0, len,
+                                                  DMA_TO_DEVICE);
+
+               tqueue->tx_skbuff_dma[entry] = tx_desc->tdes01;
+               tqueue->tx_skbuff[entry] = NULL;
+
+               /* prepare the descriptor */
+               priv->hw->desc->prepare_tx_desc(tx_desc, 0, len,
+                                               len, cksum_flag);
+               /* memory barrier to flush descriptor */
+               wmb();
+
+               /* set the owner */
+               priv->hw->desc->set_tx_owner(tx_desc);
+       }
+
+       /* close the descriptors */
+       priv->hw->desc->close_tx_desc(tx_desc);
+
+       /* memory barrier to flush descriptor */
+       wmb();
+
+       tqueue->tx_count_frames += nr_frags + 1;
+       if (tqueue->tx_count_frames > tqueue->tx_coal_frames) {
+               priv->hw->desc->clear_tx_ic(tx_desc);
+               priv->xstats.tx_reset_ic_bit++;
+               mod_timer(&tqueue->txtimer,
+                         SXGBE_COAL_TIMER(tqueue->tx_coal_timer));
+       } else {
+               tqueue->tx_count_frames = 0;
+       }
+
+       /* set owner for first desc */
+       priv->hw->desc->set_tx_owner(first_desc);
+
+       /* memory barrier to flush descriptor */
+       wmb();
+
+       tqueue->cur_tx++;
+
+       /* display current ring */
+       netif_dbg(priv, pktdata, dev, "%s: curr %d dirty=%d entry=%d, first=%p, nfrags=%d\n",
+                 __func__, tqueue->cur_tx % tx_rsize,
+                 tqueue->dirty_tx % tx_rsize, entry,
+                 first_desc, nr_frags);
+
+       if (unlikely(sxgbe_tx_avail(tqueue, tx_rsize) <= (MAX_SKB_FRAGS + 1))) {
+               netif_dbg(priv, hw, dev, "%s: stop transmitted packets\n",
+                         __func__);
+               netif_tx_stop_queue(dev_txq);
+       }
+
+       dev->stats.tx_bytes += skb->len;
+
+       if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+                    tqueue->hwts_tx_en)) {
+               /* declare that device is doing timestamping */
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
+               priv->hw->desc->tx_enable_tstamp(first_desc);
+       }
+
+       if (!tqueue->hwts_tx_en)
+               skb_tx_timestamp(skb);
+
+       priv->hw->dma->enable_dma_transmission(priv->ioaddr, txq_index);
+
+       spin_unlock(&tqueue->tx_lock);
+
+       return NETDEV_TX_OK;
+}
+
+/**
+ * sxgbe_rx_refill: refill used skb preallocated buffers
+ * @priv: driver private structure
+ * Description : this is to reallocate the skb for the reception process
+ * that is based on zero-copy.
+ */
+static void sxgbe_rx_refill(struct sxgbe_priv_data *priv)
+{
+       unsigned int rxsize = priv->dma_rx_size;
+       int bfsize = priv->dma_buf_sz;
+       u8 qnum = priv->cur_rx_qnum;
+
+       for (; priv->rxq[qnum]->cur_rx - priv->rxq[qnum]->dirty_rx > 0;
+            priv->rxq[qnum]->dirty_rx++) {
+               unsigned int entry = priv->rxq[qnum]->dirty_rx % rxsize;
+               struct sxgbe_rx_norm_desc *p;
+
+               p = priv->rxq[qnum]->dma_rx + entry;
+
+               if (likely(priv->rxq[qnum]->rx_skbuff[entry] == NULL)) {
+                       struct sk_buff *skb;
+
+                       skb = netdev_alloc_skb_ip_align(priv->dev, bfsize);
+
+                       if (unlikely(skb == NULL))
+                               break;
+
+                       priv->rxq[qnum]->rx_skbuff[entry] = skb;
+                       priv->rxq[qnum]->rx_skbuff_dma[entry] =
+                               dma_map_single(priv->device, skb->data, bfsize,
+                                              DMA_FROM_DEVICE);
+
+                       p->rdes23.rx_rd_des23.buf2_addr =
+                               priv->rxq[qnum]->rx_skbuff_dma[entry];
+               }
+
+               /* Added memory barrier for RX descriptor modification */
+               wmb();
+               priv->hw->desc->set_rx_owner(p);
+               /* Added memory barrier for RX descriptor modification */
+               wmb();
+       }
+}
+
+/**
+ * sxgbe_rx: receive the frames from the remote host
+ * @priv: driver private structure
+ * @limit: napi bugget.
+ * Description :  this the function called by the napi poll method.
+ * It gets all the frames inside the ring.
+ */
+static int sxgbe_rx(struct sxgbe_priv_data *priv, int limit)
+{
+       u8 qnum = priv->cur_rx_qnum;
+       unsigned int rxsize = priv->dma_rx_size;
+       unsigned int entry = priv->rxq[qnum]->cur_rx;
+       unsigned int next_entry = 0;
+       unsigned int count = 0;
+       int checksum;
+       int status;
+
+       while (count < limit) {
+               struct sxgbe_rx_norm_desc *p;
+               struct sk_buff *skb;
+               int frame_len;
+
+               p = priv->rxq[qnum]->dma_rx + entry;
+
+               if (priv->hw->desc->get_rx_owner(p))
+                       break;
+
+               count++;
+
+               next_entry = (++priv->rxq[qnum]->cur_rx) % rxsize;
+               prefetch(priv->rxq[qnum]->dma_rx + next_entry);
+
+               /* Read the status of the incoming frame and also get checksum
+                * value based on whether it is enabled in SXGBE hardware or
+                * not.
+                */
+               status = priv->hw->desc->rx_wbstatus(p, &priv->xstats,
+                                                    &checksum);
+               if (unlikely(status < 0)) {
+                       entry = next_entry;
+                       continue;
+               }
+               if (unlikely(!priv->rxcsum_insertion))
+                       checksum = CHECKSUM_NONE;
+
+               skb = priv->rxq[qnum]->rx_skbuff[entry];
+
+               if (unlikely(!skb))
+                       netdev_err(priv->dev, "rx descriptor is not consistent\n");
+
+               prefetch(skb->data - NET_IP_ALIGN);
+               priv->rxq[qnum]->rx_skbuff[entry] = NULL;
+
+               frame_len = priv->hw->desc->get_rx_frame_len(p);
+
+               skb_put(skb, frame_len);
+
+               skb->ip_summed = checksum;
+               if (checksum == CHECKSUM_NONE)
+                       netif_receive_skb(skb);
+               else
+                       napi_gro_receive(&priv->napi, skb);
+
+               entry = next_entry;
+       }
+
+       sxgbe_rx_refill(priv);
+
+       return count;
+}
+
+/**
+ *  sxgbe_poll - sxgbe poll method (NAPI)
+ *  @napi : pointer to the napi structure.
+ *  @budget : maximum number of packets that the current CPU can receive from
+ *           all interfaces.
+ *  Description :
+ *  To look at the incoming frames and clear the tx resources.
+ */
+static int sxgbe_poll(struct napi_struct *napi, int budget)
+{
+       struct sxgbe_priv_data *priv = container_of(napi,
+                                                   struct sxgbe_priv_data, napi);
+       int work_done = 0;
+       u8 qnum = priv->cur_rx_qnum;
+
+       priv->xstats.napi_poll++;
+       /* first, clean the tx queues */
+       sxgbe_tx_all_clean(priv);
+
+       work_done = sxgbe_rx(priv, budget);
+       if (work_done < budget) {
+               napi_complete(napi);
+               priv->hw->dma->enable_dma_irq(priv->ioaddr, qnum);
+       }
+
+       return work_done;
+}
+
+/**
+ *  sxgbe_tx_timeout
+ *  @dev : Pointer to net device structure
+ *  Description: this function is called when a packet transmission fails to
+ *   complete within a reasonable time. The driver will mark the error in the
+ *   netdev structure and arrange for the device to be reset to a sane state
+ *   in order to transmit a new packet.
+ */
+static void sxgbe_tx_timeout(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       sxgbe_reset_all_tx_queues(priv);
+}
+
+/**
+ *  sxgbe_common_interrupt - main ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the main driver interrupt service routine.
+ *  It calls the DMA ISR and also the core ISR to manage PMT, MMC, LPI
+ *  interrupts.
+ */
+static irqreturn_t sxgbe_common_interrupt(int irq, void *dev_id)
+{
+       struct net_device *netdev = (struct net_device *)dev_id;
+       struct sxgbe_priv_data *priv = netdev_priv(netdev);
+       int status;
+
+       status = priv->hw->mac->host_irq_status(priv->ioaddr, &priv->xstats);
+       /* For LPI we need to save the tx status */
+       if (status & TX_ENTRY_LPI_MODE) {
+               priv->xstats.tx_lpi_entry_n++;
+               priv->tx_path_in_lpi_mode = true;
+       }
+       if (status & TX_EXIT_LPI_MODE) {
+               priv->xstats.tx_lpi_exit_n++;
+               priv->tx_path_in_lpi_mode = false;
+       }
+       if (status & RX_ENTRY_LPI_MODE)
+               priv->xstats.rx_lpi_entry_n++;
+       if (status & RX_EXIT_LPI_MODE)
+               priv->xstats.rx_lpi_exit_n++;
+
+       return IRQ_HANDLED;
+}
+
+/**
+ *  sxgbe_tx_interrupt - TX DMA ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the tx dma interrupt service routine.
+ */
+static irqreturn_t sxgbe_tx_interrupt(int irq, void *dev_id)
+{
+       int status;
+       struct sxgbe_tx_queue *txq = (struct sxgbe_tx_queue *)dev_id;
+       struct sxgbe_priv_data *priv = txq->priv_ptr;
+
+       /* get the channel status */
+       status = priv->hw->dma->tx_dma_int_status(priv->ioaddr, txq->queue_no,
+                                                 &priv->xstats);
+       /* check for normal path */
+       if (likely((status & handle_tx)))
+               napi_schedule(&priv->napi);
+
+       /* check for unrecoverable error */
+       if (unlikely((status & tx_hard_error)))
+               sxgbe_restart_tx_queue(priv, txq->queue_no);
+
+       /* check for TC configuration change */
+       if (unlikely((status & tx_bump_tc) &&
+                    (priv->tx_tc != SXGBE_MTL_SFMODE) &&
+                    (priv->tx_tc < 512))) {
+               /* step of TX TC is 32 till 128, otherwise 64 */
+               priv->tx_tc += (priv->tx_tc < 128) ? 32 : 64;
+               priv->hw->mtl->set_tx_mtl_mode(priv->ioaddr,
+                                              txq->queue_no, priv->tx_tc);
+               priv->xstats.tx_threshold = priv->tx_tc;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ *  sxgbe_rx_interrupt - RX DMA ISR
+ *  @irq: interrupt number.
+ *  @dev_id: to pass the net device pointer.
+ *  Description: this is the rx dma interrupt service routine.
+ */
+static irqreturn_t sxgbe_rx_interrupt(int irq, void *dev_id)
+{
+       int status;
+       struct sxgbe_rx_queue *rxq = (struct sxgbe_rx_queue *)dev_id;
+       struct sxgbe_priv_data *priv = rxq->priv_ptr;
+
+       /* get the channel status */
+       status = priv->hw->dma->rx_dma_int_status(priv->ioaddr, rxq->queue_no,
+                                                 &priv->xstats);
+
+       if (likely((status & handle_rx) && (napi_schedule_prep(&priv->napi)))) {
+               priv->hw->dma->disable_dma_irq(priv->ioaddr, rxq->queue_no);
+               __napi_schedule(&priv->napi);
+       }
+
+       /* check for TC configuration change */
+       if (unlikely((status & rx_bump_tc) &&
+                    (priv->rx_tc != SXGBE_MTL_SFMODE) &&
+                    (priv->rx_tc < 128))) {
+               /* step of TC is 32 */
+               priv->rx_tc += 32;
+               priv->hw->mtl->set_rx_mtl_mode(priv->ioaddr,
+                                              rxq->queue_no, priv->rx_tc);
+               priv->xstats.rx_threshold = priv->rx_tc;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static inline u64 sxgbe_get_stat64(void __iomem *ioaddr, int reg_lo, int reg_hi)
+{
+       u64 val = readl(ioaddr + reg_lo);
+
+       val |= ((u64)readl(ioaddr + reg_hi)) << 32;
+
+       return val;
+}
+
+
+/*  sxgbe_get_stats64 - entry point to see statistical information of device
+ *  @dev : device pointer.
+ *  @stats : pointer to hold all the statistical information of device.
+ *  Description:
+ *  This function is a driver entry point whenever ifconfig command gets
+ *  executed to see device statistics. Statistics are number of
+ *  bytes sent or received, errors occured etc.
+ *  Return value:
+ *  This function returns various statistical information of device.
+ */
+static struct rtnl_link_stats64 *sxgbe_get_stats64(struct net_device *dev,
+                                                  struct rtnl_link_stats64 *stats)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       void __iomem *ioaddr = priv->ioaddr;
+       u64 count;
+
+       spin_lock(&priv->stats_lock);
+       /* Freeze the counter registers before reading value otherwise it may
+        * get updated by hardware while we are reading them
+        */
+       writel(SXGBE_MMC_CTRL_CNT_FRZ, ioaddr + SXGBE_MMC_CTL_REG);
+
+       stats->rx_bytes = sxgbe_get_stat64(ioaddr,
+                                          SXGBE_MMC_RXOCTETLO_GCNT_REG,
+                                          SXGBE_MMC_RXOCTETHI_GCNT_REG);
+
+       stats->rx_packets = sxgbe_get_stat64(ioaddr,
+                                            SXGBE_MMC_RXFRAMELO_GBCNT_REG,
+                                            SXGBE_MMC_RXFRAMEHI_GBCNT_REG);
+
+       stats->multicast = sxgbe_get_stat64(ioaddr,
+                                           SXGBE_MMC_RXMULTILO_GCNT_REG,
+                                           SXGBE_MMC_RXMULTIHI_GCNT_REG);
+
+       stats->rx_crc_errors = sxgbe_get_stat64(ioaddr,
+                                               SXGBE_MMC_RXCRCERRLO_REG,
+                                               SXGBE_MMC_RXCRCERRHI_REG);
+
+       stats->rx_length_errors = sxgbe_get_stat64(ioaddr,
+                                                 SXGBE_MMC_RXLENERRLO_REG,
+                                                 SXGBE_MMC_RXLENERRHI_REG);
+
+       stats->rx_missed_errors = sxgbe_get_stat64(ioaddr,
+                                                  SXGBE_MMC_RXFIFOOVERFLOWLO_GBCNT_REG,
+                                                  SXGBE_MMC_RXFIFOOVERFLOWHI_GBCNT_REG);
+
+       stats->tx_bytes = sxgbe_get_stat64(ioaddr,
+                                          SXGBE_MMC_TXOCTETLO_GCNT_REG,
+                                          SXGBE_MMC_TXOCTETHI_GCNT_REG);
+
+       count = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXFRAMELO_GBCNT_REG,
+                                SXGBE_MMC_TXFRAMEHI_GBCNT_REG);
+
+       stats->tx_errors = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXFRAMELO_GCNT_REG,
+                                           SXGBE_MMC_TXFRAMEHI_GCNT_REG);
+       stats->tx_errors = count - stats->tx_errors;
+       stats->tx_packets = count;
+       stats->tx_fifo_errors = sxgbe_get_stat64(ioaddr, SXGBE_MMC_TXUFLWLO_GBCNT_REG,
+                                                SXGBE_MMC_TXUFLWHI_GBCNT_REG);
+       writel(0, ioaddr + SXGBE_MMC_CTL_REG);
+       spin_unlock(&priv->stats_lock);
+
+       return stats;
+}
+
+/*  sxgbe_set_features - entry point to set offload features of the device.
+ *  @dev : device pointer.
+ *  @features : features which are required to be set.
+ *  Description:
+ *  This function is a driver entry point and called by Linux kernel whenever
+ *  any device features are set or reset by user.
+ *  Return value:
+ *  This function returns 0 after setting or resetting device features.
+ */
+static int sxgbe_set_features(struct net_device *dev,
+                             netdev_features_t features)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       netdev_features_t changed = dev->features ^ features;
+
+       if (changed & NETIF_F_RXCSUM) {
+               if (features & NETIF_F_RXCSUM) {
+                       priv->hw->mac->enable_rx_csum(priv->ioaddr);
+                       priv->rxcsum_insertion = true;
+               } else {
+                       priv->hw->mac->disable_rx_csum(priv->ioaddr);
+                       priv->rxcsum_insertion = false;
+               }
+       }
+
+       return 0;
+}
+
+/*  sxgbe_change_mtu - entry point to change MTU size for the device.
+ *  @dev : device pointer.
+ *  @new_mtu : the new MTU size for the device.
+ *  Description: the Maximum Transfer Unit (MTU) is used by the network layer
+ *  to drive packet transmission. Ethernet has an MTU of 1500 octets
+ *  (ETH_DATA_LEN). This value can be changed with ifconfig.
+ *  Return value:
+ *  0 on success and an appropriate (-)ve integer as defined in errno.h
+ *  file on failure.
+ */
+static int sxgbe_change_mtu(struct net_device *dev, int new_mtu)
+{
+       /* RFC 791, page 25, "Every internet module must be able to forward
+        * a datagram of 68 octets without further fragmentation."
+        */
+       if (new_mtu < MIN_MTU || (new_mtu > MAX_MTU)) {
+               netdev_err(dev, "invalid MTU, MTU should be in between %d and %d\n",
+                          MIN_MTU, MAX_MTU);
+               return -EINVAL;
+       }
+
+       /* Return if the buffer sizes will not change */
+       if (dev->mtu == new_mtu)
+               return 0;
+
+       dev->mtu = new_mtu;
+
+       if (!netif_running(dev))
+               return 0;
+
+       /* Recevice ring buffer size is needed to be set based on MTU. If MTU is
+        * changed then reinitilisation of the receive ring buffers need to be
+        * done. Hence bring interface down and bring interface back up
+        */
+       sxgbe_release(dev);
+       return sxgbe_open(dev);
+}
+
+static void sxgbe_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+                               unsigned int reg_n)
+{
+       unsigned long data;
+
+       data = (addr[5] << 8) | addr[4];
+       /* For MAC Addr registers se have to set the Address Enable (AE)
+        * bit that has no effect on the High Reg 0 where the bit 31 (MO)
+        * is RO.
+        */
+       writel(data | SXGBE_HI_REG_AE, ioaddr + SXGBE_ADDR_HIGH(reg_n));
+       data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+       writel(data, ioaddr + SXGBE_ADDR_LOW(reg_n));
+}
+
+/**
+ * sxgbe_set_rx_mode - entry point for setting different receive mode of
+ * a device. unicast, multicast addressing
+ * @dev : pointer to the device structure
+ * Description:
+ * This function is a driver entry point which gets called by the kernel
+ * whenever different receive mode like unicast, multicast and promiscuous
+ * must be enabled/disabled.
+ * Return value:
+ * void.
+ */
+static void sxgbe_set_rx_mode(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       void __iomem *ioaddr = (void __iomem *)priv->ioaddr;
+       unsigned int value = 0;
+       u32 mc_filter[2];
+       struct netdev_hw_addr *ha;
+       int reg = 1;
+
+       netdev_dbg(dev, "%s: # mcasts %d, # unicast %d\n",
+                  __func__, netdev_mc_count(dev), netdev_uc_count(dev));
+
+       if (dev->flags & IFF_PROMISC) {
+               value = SXGBE_FRAME_FILTER_PR;
+
+       } else if ((netdev_mc_count(dev) > SXGBE_HASH_TABLE_SIZE) ||
+                  (dev->flags & IFF_ALLMULTI)) {
+               value = SXGBE_FRAME_FILTER_PM;  /* pass all multi */
+               writel(0xffffffff, ioaddr + SXGBE_HASH_HIGH);
+               writel(0xffffffff, ioaddr + SXGBE_HASH_LOW);
+
+       } else if (!netdev_mc_empty(dev)) {
+               /* Hash filter for multicast */
+               value = SXGBE_FRAME_FILTER_HMC;
+
+               memset(mc_filter, 0, sizeof(mc_filter));
+               netdev_for_each_mc_addr(ha, dev) {
+                       /* The upper 6 bits of the calculated CRC are used to
+                        * index the contens of the hash table
+                        */
+                       int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
+
+                       /* The most significant bit determines the register to
+                        * use (H/L) while the other 5 bits determine the bit
+                        * within the register.
+                        */
+                       mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+               }
+               writel(mc_filter[0], ioaddr + SXGBE_HASH_LOW);
+               writel(mc_filter[1], ioaddr + SXGBE_HASH_HIGH);
+       }
+
+       /* Handle multiple unicast addresses (perfect filtering) */
+       if (netdev_uc_count(dev) > SXGBE_MAX_PERFECT_ADDRESSES)
+               /* Switch to promiscuous mode if more than 16 addrs
+                * are required
+                */
+               value |= SXGBE_FRAME_FILTER_PR;
+       else {
+               netdev_for_each_uc_addr(ha, dev) {
+                       sxgbe_set_umac_addr(ioaddr, ha->addr, reg);
+                       reg++;
+               }
+       }
+#ifdef FRAME_FILTER_DEBUG
+       /* Enable Receive all mode (to debug filtering_fail errors) */
+       value |= SXGBE_FRAME_FILTER_RA;
+#endif
+       writel(value, ioaddr + SXGBE_FRAME_FILTER);
+
+       netdev_dbg(dev, "Filter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n",
+                  readl(ioaddr + SXGBE_FRAME_FILTER),
+                  readl(ioaddr + SXGBE_HASH_HIGH),
+                  readl(ioaddr + SXGBE_HASH_LOW));
+}
+
+/**
+ * sxgbe_config - entry point for changing configuration mode passed on by
+ * ifconfig
+ * @dev : pointer to the device structure
+ * @map : pointer to the device mapping structure
+ * Description:
+ * This function is a driver entry point which gets called by the kernel
+ * whenever some device configuration is changed.
+ * Return value:
+ * This function returns 0 if success and appropriate error otherwise.
+ */
+static int sxgbe_config(struct net_device *dev, struct ifmap *map)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       /* Can't act on a running interface */
+       if (dev->flags & IFF_UP)
+               return -EBUSY;
+
+       /* Don't allow changing the I/O address */
+       if (map->base_addr != (unsigned long)priv->ioaddr) {
+               netdev_warn(dev, "can't change I/O address\n");
+               return -EOPNOTSUPP;
+       }
+
+       /* Don't allow changing the IRQ */
+       if (map->irq != priv->irq) {
+               netdev_warn(dev, "not change IRQ number %d\n", priv->irq);
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * sxgbe_poll_controller - entry point for polling receive by device
+ * @dev : pointer to the device structure
+ * Description:
+ * This function is used by NETCONSOLE and other diagnostic tools
+ * to allow network I/O with interrupts disabled.
+ * Return value:
+ * Void.
+ */
+static void sxgbe_poll_controller(struct net_device *dev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+       disable_irq(priv->irq);
+       sxgbe_rx_interrupt(priv->irq, dev);
+       enable_irq(priv->irq);
+}
+#endif
+
+/*  sxgbe_ioctl - Entry point for the Ioctl
+ *  @dev: Device pointer.
+ *  @rq: An IOCTL specefic structure, that can contain a pointer to
+ *  a proprietary structure used to pass information to the driver.
+ *  @cmd: IOCTL command
+ *  Description:
+ *  Currently it supports the phy_mii_ioctl(...) and HW time stamping.
+ */
+static int sxgbe_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(dev);
+       int ret = -EOPNOTSUPP;
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               if (!priv->phydev)
+                       return -EINVAL;
+               ret = phy_mii_ioctl(priv->phydev, rq, cmd);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static const struct net_device_ops sxgbe_netdev_ops = {
+       .ndo_open               = sxgbe_open,
+       .ndo_start_xmit         = sxgbe_xmit,
+       .ndo_stop               = sxgbe_release,
+       .ndo_get_stats64        = sxgbe_get_stats64,
+       .ndo_change_mtu         = sxgbe_change_mtu,
+       .ndo_set_features       = sxgbe_set_features,
+       .ndo_set_rx_mode        = sxgbe_set_rx_mode,
+       .ndo_tx_timeout         = sxgbe_tx_timeout,
+       .ndo_do_ioctl           = sxgbe_ioctl,
+       .ndo_set_config         = sxgbe_config,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = sxgbe_poll_controller,
+#endif
+       .ndo_set_mac_address    = eth_mac_addr,
+};
+
+/* Get the hardware ops */
+static void sxgbe_get_ops(struct sxgbe_ops * const ops_ptr)
+{
+       ops_ptr->mac            = sxgbe_get_core_ops();
+       ops_ptr->desc           = sxgbe_get_desc_ops();
+       ops_ptr->dma            = sxgbe_get_dma_ops();
+       ops_ptr->mtl            = sxgbe_get_mtl_ops();
+
+       /* set the MDIO communication Address/Data regisers */
+       ops_ptr->mii.addr       = SXGBE_MDIO_SCMD_ADD_REG;
+       ops_ptr->mii.data       = SXGBE_MDIO_SCMD_DATA_REG;
+
+       /* Assigning the default link settings
+        * no SXGBE defined default values to be set in registers,
+        * so assigning as 0 for port and duplex
+        */
+       ops_ptr->link.port      = 0;
+       ops_ptr->link.duplex    = 0;
+       ops_ptr->link.speed     = SXGBE_SPEED_10G;
+}
+
+/**
+ *  sxgbe_hw_init - Init the GMAC device
+ *  @priv: driver private structure
+ *  Description: this function checks the HW capability
+ *  (if supported) and sets the driver's features.
+ */
+static int sxgbe_hw_init(struct sxgbe_priv_data * const priv)
+{
+       u32 ctrl_ids;
+
+       priv->hw = kmalloc(sizeof(*priv->hw), GFP_KERNEL);
+       if(!priv->hw)
+               return -ENOMEM;
+
+       /* get the hardware ops */
+       sxgbe_get_ops(priv->hw);
+
+       /* get the controller id */
+       ctrl_ids = priv->hw->mac->get_controller_version(priv->ioaddr);
+       priv->hw->ctrl_uid = (ctrl_ids & 0x00ff0000) >> 16;
+       priv->hw->ctrl_id = (ctrl_ids & 0x000000ff);
+       pr_info("user ID: 0x%x, Controller ID: 0x%x\n",
+               priv->hw->ctrl_uid, priv->hw->ctrl_id);
+
+       /* get the H/W features */
+       if (!sxgbe_get_hw_features(priv))
+               pr_info("Hardware features not found\n");
+
+       if (priv->hw_cap.tx_csum_offload)
+               pr_info("TX Checksum offload supported\n");
+
+       if (priv->hw_cap.rx_csum_offload)
+               pr_info("RX Checksum offload supported\n");
+
+       return 0;
+}
+
+/**
+ * sxgbe_drv_probe
+ * @device: device pointer
+ * @plat_dat: platform data pointer
+ * @addr: iobase memory address
+ * Description: this is the main probe function used to
+ * call the alloc_etherdev, allocate the priv structure.
+ */
+struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
+                                       struct sxgbe_plat_data *plat_dat,
+                                       void __iomem *addr)
+{
+       struct sxgbe_priv_data *priv;
+       struct net_device *ndev;
+       int ret;
+       u8 queue_num;
+
+       ndev = alloc_etherdev_mqs(sizeof(struct sxgbe_priv_data),
+                                 SXGBE_TX_QUEUES, SXGBE_RX_QUEUES);
+       if (!ndev)
+               return NULL;
+
+       SET_NETDEV_DEV(ndev, device);
+
+       priv = netdev_priv(ndev);
+       priv->device = device;
+       priv->dev = ndev;
+
+       sxgbe_set_ethtool_ops(ndev);
+       priv->plat = plat_dat;
+       priv->ioaddr = addr;
+
+       /* Verify driver arguments */
+       sxgbe_verify_args();
+
+       /* Init MAC and get the capabilities */
+       ret = sxgbe_hw_init(priv);
+       if (ret)
+               goto error_free_netdev;
+
+       /* allocate memory resources for Descriptor rings */
+       ret = txring_mem_alloc(priv);
+       if (ret)
+               goto error_free_netdev;
+
+       ret = rxring_mem_alloc(priv);
+       if (ret)
+               goto error_free_netdev;
+
+       ndev->netdev_ops = &sxgbe_netdev_ops;
+
+       ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+               NETIF_F_RXCSUM | NETIF_F_TSO | NETIF_F_TSO6 |
+               NETIF_F_GRO;
+       ndev->features |= ndev->hw_features | NETIF_F_HIGHDMA;
+       ndev->watchdog_timeo = msecs_to_jiffies(TX_TIMEO);
+
+       /* assign filtering support */
+       ndev->priv_flags |= IFF_UNICAST_FLT;
+
+       priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+       /* Enable TCP segmentation offload for all DMA channels */
+       if (priv->hw_cap.tcpseg_offload) {
+               SXGBE_FOR_EACH_QUEUE(SXGBE_TX_QUEUES, queue_num) {
+                       priv->hw->dma->enable_tso(priv->ioaddr, queue_num);
+               }
+       }
+
+       /* Enable Rx checksum offload */
+       if (priv->hw_cap.rx_csum_offload) {
+               priv->hw->mac->enable_rx_csum(priv->ioaddr);
+               priv->rxcsum_insertion = true;
+       }
+
+       /* Initialise pause frame settings */
+       priv->rx_pause = 1;
+       priv->tx_pause = 1;
+
+       /* Rx Watchdog is available, enable depend on platform data */
+       if (!priv->plat->riwt_off) {
+               priv->use_riwt = 1;
+               pr_info("Enable RX Mitigation via HW Watchdog Timer\n");
+       }
+
+       netif_napi_add(ndev, &priv->napi, sxgbe_poll, 64);
+
+       spin_lock_init(&priv->stats_lock);
+
+       priv->sxgbe_clk = clk_get(priv->device, SXGBE_RESOURCE_NAME);
+       if (IS_ERR(priv->sxgbe_clk)) {
+               netdev_warn(ndev, "%s: warning: cannot get CSR clock\n",
+                           __func__);
+               goto error_clk_get;
+       }
+
+       /* If a specific clk_csr value is passed from the platform
+        * this means that the CSR Clock Range selection cannot be
+        * changed at run-time and it is fixed. Viceversa the driver'll try to
+        * set the MDC clock dynamically according to the csr actual
+        * clock input.
+        */
+       if (!priv->plat->clk_csr)
+               sxgbe_clk_csr_set(priv);
+       else
+               priv->clk_csr = priv->plat->clk_csr;
+
+       /* MDIO bus Registration */
+       ret = sxgbe_mdio_register(ndev);
+       if (ret < 0) {
+               netdev_dbg(ndev, "%s: MDIO bus (id: %d) registration failed\n",
+                          __func__, priv->plat->bus_id);
+               goto error_mdio_register;
+       }
+
+       ret = register_netdev(ndev);
+       if (ret) {
+               pr_err("%s: ERROR %i registering the device\n", __func__, ret);
+               goto error_netdev_register;
+       }
+
+       sxgbe_check_ether_addr(priv);
+
+       return priv;
+
+error_mdio_register:
+       clk_put(priv->sxgbe_clk);
+error_clk_get:
+error_netdev_register:
+       netif_napi_del(&priv->napi);
+error_free_netdev:
+       free_netdev(ndev);
+
+       return NULL;
+}
+
+/**
+ * sxgbe_drv_remove
+ * @ndev: net device pointer
+ * Description: this function resets the TX/RX processes, disables the MAC RX/TX
+ * changes the link status, releases the DMA descriptor rings.
+ */
+int sxgbe_drv_remove(struct net_device *ndev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+       netdev_info(ndev, "%s: removing driver\n", __func__);
+
+       priv->hw->dma->stop_rx(priv->ioaddr, SXGBE_RX_QUEUES);
+       priv->hw->dma->stop_tx(priv->ioaddr, SXGBE_TX_QUEUES);
+
+       priv->hw->mac->enable_tx(priv->ioaddr, false);
+       priv->hw->mac->enable_rx(priv->ioaddr, false);
+
+       netif_napi_del(&priv->napi);
+
+       sxgbe_mdio_unregister(ndev);
+
+       unregister_netdev(ndev);
+
+       free_netdev(ndev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+int sxgbe_suspend(struct net_device *ndev)
+{
+       return 0;
+}
+
+int sxgbe_resume(struct net_device *ndev)
+{
+       return 0;
+}
+
+int sxgbe_freeze(struct net_device *ndev)
+{
+       return -ENOSYS;
+}
+
+int sxgbe_restore(struct net_device *ndev)
+{
+       return -ENOSYS;
+}
+#endif /* CONFIG_PM */
+
+/* Driver is configured as Platform driver */
+static int __init sxgbe_init(void)
+{
+       int ret;
+
+       ret = sxgbe_register_platform();
+       if (ret)
+               goto err;
+       return 0;
+err:
+       pr_err("driver registration failed\n");
+       return ret;
+}
+
+static void __exit sxgbe_exit(void)
+{
+       sxgbe_unregister_platform();
+}
+
+module_init(sxgbe_init);
+module_exit(sxgbe_exit);
+
+#ifndef MODULE
+static int __init sxgbe_cmdline_opt(char *str)
+{
+       char *opt;
+
+       if (!str || !*str)
+               return -EINVAL;
+       while ((opt = strsep(&str, ",")) != NULL) {
+               if (!strncmp(opt, "eee_timer:", 6)) {
+                       if (kstrtoint(opt + 10, 0, &eee_timer))
+                               goto err;
+               }
+       }
+       return 0;
+
+err:
+       pr_err("%s: ERROR broken module parameter conversion\n", __func__);
+       return -EINVAL;
+}
+
+__setup("sxgbeeth=", sxgbe_cmdline_opt);
+#endif /* MODULE */
+
+
+
+MODULE_DESCRIPTION("SAMSUNG 10G/2.5G/1G Ethernet PLATFORM driver");
+
+MODULE_PARM_DESC(debug, "Message Level (-1: default, 0: no output, 16: all)");
+MODULE_PARM_DESC(eee_timer, "EEE-LPI Default LS timer value");
+
+MODULE_AUTHOR("Siva Reddy Kallam <siva.kallam@samsung.com>");
+MODULE_AUTHOR("ByungHo An <bh74.an@samsung.com>");
+MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
+MODULE_AUTHOR("Vipul Pandya <vipul.pandya@samsung.com>");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mdio.c
new file mode 100644 (file)
index 0000000..b0eb0a2
--- /dev/null
@@ -0,0 +1,251 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/slab.h>
+#include <linux/sxgbe_platform.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+
+#define SXGBE_SMA_WRITE_CMD    0x01 /* write command */
+#define SXGBE_SMA_PREAD_CMD    0x02 /* post read  increament address */
+#define SXGBE_SMA_READ_CMD     0x03 /* read command */
+#define SXGBE_SMA_SKIP_ADDRFRM 0x00040000 /* skip the address frame */
+#define SXGBE_MII_BUSY         0x00800000 /* mii busy */
+
+static int sxgbe_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_data)
+{
+       unsigned long fin_time = jiffies + 3 * HZ; /* 3 seconds */
+
+       while (!time_after(jiffies, fin_time)) {
+               if (!(readl(ioaddr + mii_data) & SXGBE_MII_BUSY))
+                       return 0;
+               cpu_relax();
+       }
+
+       return -EBUSY;
+}
+
+static void sxgbe_mdio_ctrl_data(struct sxgbe_priv_data *sp, u32 cmd,
+                                u16 phydata)
+{
+       u32 reg = phydata;
+
+       reg |= (cmd << 16) | SXGBE_SMA_SKIP_ADDRFRM |
+              ((sp->clk_csr & 0x7) << 19) | SXGBE_MII_BUSY;
+       writel(reg, sp->ioaddr + sp->hw->mii.data);
+}
+
+static void sxgbe_mdio_c45(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
+                          int phyreg, u16 phydata)
+{
+       u32 reg;
+
+       /* set mdio address register */
+       reg = ((phyreg >> 16) & 0x1f) << 21;
+       reg |= (phyaddr << 16) | (phyreg & 0xffff);
+       writel(reg, sp->ioaddr + sp->hw->mii.addr);
+
+       sxgbe_mdio_ctrl_data(sp, cmd, phydata);
+}
+
+static void sxgbe_mdio_c22(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
+                          int phyreg, u16 phydata)
+{
+       u32 reg;
+
+       writel(1 << phyaddr, sp->ioaddr + SXGBE_MDIO_CLAUSE22_PORT_REG);
+
+       /* set mdio address register */
+       reg = (phyaddr << 16) | (phyreg & 0x1f);
+       writel(reg, sp->ioaddr + sp->hw->mii.addr);
+
+       sxgbe_mdio_ctrl_data(sp, cmd, phydata);
+}
+
+static int sxgbe_mdio_access(struct sxgbe_priv_data *sp, u32 cmd, int phyaddr,
+                            int phyreg, u16 phydata)
+{
+       const struct mii_regs *mii = &sp->hw->mii;
+       int rc;
+
+       rc = sxgbe_mdio_busy_wait(sp->ioaddr, mii->data);
+       if (rc < 0)
+               return rc;
+
+       if (phyreg & MII_ADDR_C45) {
+               sxgbe_mdio_c45(sp, cmd, phyaddr, phyreg, phydata);
+       } else {
+                /* Ports 0-3 only support C22. */
+               if (phyaddr >= 4)
+                       return -ENODEV;
+
+               sxgbe_mdio_c22(sp, cmd, phyaddr, phyreg, phydata);
+       }
+
+       return sxgbe_mdio_busy_wait(sp->ioaddr, mii->data);
+}
+
+/**
+ * sxgbe_mdio_read
+ * @bus: points to the mii_bus structure
+ * @phyaddr: address of phy port
+ * @phyreg: address of register with in phy register
+ * Description: this function used for C45 and C22 MDIO Read
+ */
+static int sxgbe_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
+{
+       struct net_device *ndev = bus->priv;
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+       int rc;
+
+       rc = sxgbe_mdio_access(priv, SXGBE_SMA_READ_CMD, phyaddr, phyreg, 0);
+       if (rc < 0)
+               return rc;
+
+       return readl(priv->ioaddr + priv->hw->mii.data) & 0xffff;
+}
+
+/**
+ * sxgbe_mdio_write
+ * @bus: points to the mii_bus structure
+ * @phyaddr: address of phy port
+ * @phyreg: address of phy registers
+ * @phydata: data to be written into phy register
+ * Description: this function is used for C45 and C22 MDIO write
+ */
+static int sxgbe_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
+                            u16 phydata)
+{
+       struct net_device *ndev = bus->priv;
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+       return sxgbe_mdio_access(priv, SXGBE_SMA_WRITE_CMD, phyaddr, phyreg,
+                                phydata);
+}
+
+int sxgbe_mdio_register(struct net_device *ndev)
+{
+       struct mii_bus *mdio_bus;
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+       struct sxgbe_mdio_bus_data *mdio_data = priv->plat->mdio_bus_data;
+       int err, phy_addr;
+       int *irqlist;
+       bool act;
+
+       /* allocate the new mdio bus */
+       mdio_bus = mdiobus_alloc();
+       if (!mdio_bus) {
+               netdev_err(ndev, "%s: mii bus allocation failed\n", __func__);
+               return -ENOMEM;
+       }
+
+       if (mdio_data->irqs)
+               irqlist = mdio_data->irqs;
+       else
+               irqlist = priv->mii_irq;
+
+       /* assign mii bus fields */
+       mdio_bus->name = "samsxgbe";
+       mdio_bus->read = &sxgbe_mdio_read;
+       mdio_bus->write = &sxgbe_mdio_write;
+       snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+                mdio_bus->name, priv->plat->bus_id);
+       mdio_bus->priv = ndev;
+       mdio_bus->phy_mask = mdio_data->phy_mask;
+       mdio_bus->parent = priv->device;
+
+       /* register with kernel subsystem */
+       err = mdiobus_register(mdio_bus);
+       if (err != 0) {
+               netdev_err(ndev, "mdiobus register failed\n");
+               goto mdiobus_err;
+       }
+
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+               struct phy_device *phy = mdio_bus->phy_map[phy_addr];
+
+               if (phy) {
+                       char irq_num[4];
+                       char *irq_str;
+                       /* If an IRQ was provided to be assigned after
+                        * the bus probe, do it here.
+                        */
+                       if ((mdio_data->irqs == NULL) &&
+                           (mdio_data->probed_phy_irq > 0)) {
+                               irqlist[phy_addr] = mdio_data->probed_phy_irq;
+                               phy->irq = mdio_data->probed_phy_irq;
+                       }
+
+                       /* If we're  going to bind the MAC to this PHY bus,
+                        * and no PHY number was provided to the MAC,
+                        * use the one probed here.
+                        */
+                       if (priv->plat->phy_addr == -1)
+                               priv->plat->phy_addr = phy_addr;
+
+                       act = (priv->plat->phy_addr == phy_addr);
+                       switch (phy->irq) {
+                       case PHY_POLL:
+                               irq_str = "POLL";
+                               break;
+                       case PHY_IGNORE_INTERRUPT:
+                               irq_str = "IGNORE";
+                               break;
+                       default:
+                               sprintf(irq_num, "%d", phy->irq);
+                               irq_str = irq_num;
+                               break;
+                       }
+                       netdev_info(ndev, "PHY ID %08x at %d IRQ %s (%s)%s\n",
+                                   phy->phy_id, phy_addr, irq_str,
+                                   dev_name(&phy->dev), act ? " active" : "");
+               }
+       }
+
+       if (!err) {
+               netdev_err(ndev, "PHY not found\n");
+               mdiobus_unregister(mdio_bus);
+               mdiobus_free(mdio_bus);
+               goto mdiobus_err;
+       }
+
+       priv->mii = mdio_bus;
+
+       return 0;
+
+mdiobus_err:
+       mdiobus_free(mdio_bus);
+       return err;
+}
+
+int sxgbe_mdio_unregister(struct net_device *ndev)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+       if (!priv->mii)
+               return 0;
+
+       mdiobus_unregister(priv->mii);
+       priv->mii->priv = NULL;
+       mdiobus_free(priv->mii);
+       priv->mii = NULL;
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.c
new file mode 100644 (file)
index 0000000..324681c
--- /dev/null
@@ -0,0 +1,254 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/jiffies.h>
+
+#include "sxgbe_mtl.h"
+#include "sxgbe_reg.h"
+
+static void sxgbe_mtl_init(void __iomem *ioaddr, unsigned int etsalg,
+                          unsigned int raa)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_OP_MODE_REG);
+       reg_val &= ETS_RST;
+
+       /* ETS Algorith */
+       switch (etsalg & SXGBE_MTL_OPMODE_ESTMASK) {
+       case ETS_WRR:
+               reg_val &= ETS_WRR;
+               break;
+       case ETS_WFQ:
+               reg_val |= ETS_WFQ;
+               break;
+       case ETS_DWRR:
+               reg_val |= ETS_DWRR;
+               break;
+       }
+       writel(reg_val, ioaddr + SXGBE_MTL_OP_MODE_REG);
+
+       switch (raa & SXGBE_MTL_OPMODE_RAAMASK) {
+       case RAA_SP:
+               reg_val &= RAA_SP;
+               break;
+       case RAA_WSP:
+               reg_val |= RAA_WSP;
+               break;
+       }
+       writel(reg_val, ioaddr + SXGBE_MTL_OP_MODE_REG);
+}
+
+/* For Dynamic DMA channel mapping for Rx queue */
+static void sxgbe_mtl_dma_dm_rxqueue(void __iomem *ioaddr)
+{
+       writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP0_REG);
+       writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP1_REG);
+       writel(RX_QUEUE_DYNAMIC, ioaddr + SXGBE_MTL_RXQ_DMAMAP2_REG);
+}
+
+static void sxgbe_mtl_set_txfifosize(void __iomem *ioaddr, int queue_num,
+                                    int queue_fifo)
+{
+       u32 fifo_bits, reg_val;
+
+       /* 0 means 256 bytes */
+       fifo_bits = (queue_fifo / SXGBE_MTL_TX_FIFO_DIV) - 1;
+       reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+       reg_val |= (fifo_bits << SXGBE_MTL_FIFO_LSHIFT);
+       writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_set_rxfifosize(void __iomem *ioaddr, int queue_num,
+                                    int queue_fifo)
+{
+       u32 fifo_bits, reg_val;
+
+       /* 0 means 256 bytes */
+       fifo_bits = (queue_fifo / SXGBE_MTL_RX_FIFO_DIV)-1;
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val |= (fifo_bits << SXGBE_MTL_FIFO_LSHIFT);
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_enable_txqueue(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+       reg_val |= SXGBE_MTL_ENABLE_QUEUE;
+       writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_disable_txqueue(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+       reg_val &= ~SXGBE_MTL_ENABLE_QUEUE;
+       writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fc_active(void __iomem *ioaddr, int queue_num,
+                               int threshold)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val &= ~(SXGBE_MTL_FCMASK << RX_FC_ACTIVE);
+       reg_val |= (threshold << RX_FC_ACTIVE);
+
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fc_enable(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val |= SXGBE_MTL_ENABLE_FC;
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fc_deactive(void __iomem *ioaddr, int queue_num,
+                                 int threshold)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val &= ~(SXGBE_MTL_FCMASK << RX_FC_DEACTIVE);
+       reg_val |= (threshold << RX_FC_DEACTIVE);
+
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fep_enable(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val |= SXGBE_MTL_RXQ_OP_FEP;
+
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fep_disable(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val &= ~(SXGBE_MTL_RXQ_OP_FEP);
+
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fup_enable(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val |= SXGBE_MTL_RXQ_OP_FUP;
+
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_mtl_fup_disable(void __iomem *ioaddr, int queue_num)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       reg_val &= ~(SXGBE_MTL_RXQ_OP_FUP);
+
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+
+static void sxgbe_set_tx_mtl_mode(void __iomem *ioaddr, int queue_num,
+                                 int tx_mode)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+       /* TX specific MTL mode settings */
+       if (tx_mode == SXGBE_MTL_SFMODE) {
+               reg_val |= SXGBE_MTL_SFMODE;
+       } else {
+               /* set the TTC values */
+               if (tx_mode <= 64)
+                       reg_val |= MTL_CONTROL_TTC_64;
+               else if (tx_mode <= 96)
+                       reg_val |= MTL_CONTROL_TTC_96;
+               else if (tx_mode <= 128)
+                       reg_val |= MTL_CONTROL_TTC_128;
+               else if (tx_mode <= 192)
+                       reg_val |= MTL_CONTROL_TTC_192;
+               else if (tx_mode <= 256)
+                       reg_val |= MTL_CONTROL_TTC_256;
+               else if (tx_mode <= 384)
+                       reg_val |= MTL_CONTROL_TTC_384;
+               else
+                       reg_val |= MTL_CONTROL_TTC_512;
+       }
+
+       /* write into TXQ operation register */
+       writel(reg_val, ioaddr + SXGBE_MTL_TXQ_OPMODE_REG(queue_num));
+}
+
+static void sxgbe_set_rx_mtl_mode(void __iomem *ioaddr, int queue_num,
+                                 int rx_mode)
+{
+       u32 reg_val;
+
+       reg_val = readl(ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+       /* RX specific MTL mode settings */
+       if (rx_mode == SXGBE_RX_MTL_SFMODE) {
+               reg_val |= SXGBE_RX_MTL_SFMODE;
+       } else {
+               if (rx_mode <= 64)
+                       reg_val |= MTL_CONTROL_RTC_64;
+               else if (rx_mode <= 96)
+                       reg_val |= MTL_CONTROL_RTC_96;
+               else if (rx_mode <= 128)
+                       reg_val |= MTL_CONTROL_RTC_128;
+       }
+
+       /* write into RXQ operation register */
+       writel(reg_val, ioaddr + SXGBE_MTL_RXQ_OPMODE_REG(queue_num));
+}
+
+static const struct sxgbe_mtl_ops mtl_ops = {
+       .mtl_set_txfifosize             = sxgbe_mtl_set_txfifosize,
+       .mtl_set_rxfifosize             = sxgbe_mtl_set_rxfifosize,
+       .mtl_enable_txqueue             = sxgbe_mtl_enable_txqueue,
+       .mtl_disable_txqueue            = sxgbe_mtl_disable_txqueue,
+       .mtl_dynamic_dma_rxqueue        = sxgbe_mtl_dma_dm_rxqueue,
+       .set_tx_mtl_mode                = sxgbe_set_tx_mtl_mode,
+       .set_rx_mtl_mode                = sxgbe_set_rx_mtl_mode,
+       .mtl_init                       = sxgbe_mtl_init,
+       .mtl_fc_active                  = sxgbe_mtl_fc_active,
+       .mtl_fc_deactive                = sxgbe_mtl_fc_deactive,
+       .mtl_fc_enable                  = sxgbe_mtl_fc_enable,
+       .mtl_fep_enable                 = sxgbe_mtl_fep_enable,
+       .mtl_fep_disable                = sxgbe_mtl_fep_disable,
+       .mtl_fup_enable                 = sxgbe_mtl_fup_enable,
+       .mtl_fup_disable                = sxgbe_mtl_fup_disable
+};
+
+const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void)
+{
+       return &mtl_ops;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_mtl.h
new file mode 100644 (file)
index 0000000..7e4810c
--- /dev/null
@@ -0,0 +1,104 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 __SXGBE_MTL_H__
+#define __SXGBE_MTL_H__
+
+#define SXGBE_MTL_OPMODE_ESTMASK       0x3
+#define SXGBE_MTL_OPMODE_RAAMASK       0x1
+#define SXGBE_MTL_FCMASK               0x7
+#define SXGBE_MTL_TX_FIFO_DIV          256
+#define SXGBE_MTL_RX_FIFO_DIV          256
+
+#define SXGBE_MTL_RXQ_OP_FEP           BIT(4)
+#define SXGBE_MTL_RXQ_OP_FUP           BIT(3)
+#define SXGBE_MTL_ENABLE_FC            0x80
+
+#define ETS_WRR                                0xFFFFFF9F
+#define ETS_RST                                0xFFFFFF9F
+#define ETS_WFQ                                0x00000020
+#define ETS_DWRR                       0x00000040
+#define RAA_SP                         0xFFFFFFFB
+#define RAA_WSP                                0x00000004
+
+#define RX_QUEUE_DYNAMIC               0x80808080
+#define RX_FC_ACTIVE                   8
+#define RX_FC_DEACTIVE                 13
+
+enum ttc_control {
+       MTL_CONTROL_TTC_64 = 0x00000000,
+       MTL_CONTROL_TTC_96 = 0x00000020,
+       MTL_CONTROL_TTC_128 = 0x00000030,
+       MTL_CONTROL_TTC_192 = 0x00000040,
+       MTL_CONTROL_TTC_256 = 0x00000050,
+       MTL_CONTROL_TTC_384 = 0x00000060,
+       MTL_CONTROL_TTC_512 = 0x00000070,
+};
+
+enum rtc_control {
+       MTL_CONTROL_RTC_64 = 0x00000000,
+       MTL_CONTROL_RTC_96 = 0x00000002,
+       MTL_CONTROL_RTC_128 = 0x00000003,
+};
+
+enum flow_control_th {
+       MTL_FC_FULL_1K = 0x00000000,
+       MTL_FC_FULL_2K = 0x00000001,
+       MTL_FC_FULL_4K = 0x00000002,
+       MTL_FC_FULL_5K = 0x00000003,
+       MTL_FC_FULL_6K = 0x00000004,
+       MTL_FC_FULL_8K = 0x00000005,
+       MTL_FC_FULL_16K = 0x00000006,
+       MTL_FC_FULL_24K = 0x00000007,
+};
+
+struct sxgbe_mtl_ops {
+       void (*mtl_init)(void __iomem *ioaddr, unsigned int etsalg,
+                        unsigned int raa);
+
+       void (*mtl_set_txfifosize)(void __iomem *ioaddr, int queue_num,
+                                  int mtl_fifo);
+
+       void (*mtl_set_rxfifosize)(void __iomem *ioaddr, int queue_num,
+                                  int queue_fifo);
+
+       void (*mtl_enable_txqueue)(void __iomem *ioaddr, int queue_num);
+
+       void (*mtl_disable_txqueue)(void __iomem *ioaddr, int queue_num);
+
+       void (*set_tx_mtl_mode)(void __iomem *ioaddr, int queue_num,
+                               int tx_mode);
+
+       void (*set_rx_mtl_mode)(void __iomem *ioaddr, int queue_num,
+                               int rx_mode);
+
+       void (*mtl_dynamic_dma_rxqueue)(void __iomem *ioaddr);
+
+       void (*mtl_fc_active)(void __iomem *ioaddr, int queue_num,
+                             int threshold);
+
+       void (*mtl_fc_deactive)(void __iomem *ioaddr, int queue_num,
+                               int threshold);
+
+       void (*mtl_fc_enable)(void __iomem *ioaddr, int queue_num);
+
+       void (*mtl_fep_enable)(void __iomem *ioaddr, int queue_num);
+
+       void (*mtl_fep_disable)(void __iomem *ioaddr, int queue_num);
+
+       void (*mtl_fup_enable)(void __iomem *ioaddr, int queue_num);
+
+       void (*mtl_fup_disable)(void __iomem *ioaddr, int queue_num);
+};
+
+const struct sxgbe_mtl_ops *sxgbe_get_mtl_ops(void);
+
+#endif /* __SXGBE_MTL_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
new file mode 100644 (file)
index 0000000..b147d46
--- /dev/null
@@ -0,0 +1,259 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/etherdevice.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <linux/sxgbe_platform.h>
+
+#include "sxgbe_common.h"
+#include "sxgbe_reg.h"
+
+#ifdef CONFIG_OF
+static int sxgbe_probe_config_dt(struct platform_device *pdev,
+                                struct sxgbe_plat_data *plat,
+                                const char **mac)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct sxgbe_dma_cfg *dma_cfg;
+
+       if (!np)
+               return -ENODEV;
+
+       *mac = of_get_mac_address(np);
+       plat->interface = of_get_phy_mode(np);
+
+       plat->bus_id = of_alias_get_id(np, "ethernet");
+       if (plat->bus_id < 0)
+               plat->bus_id = 0;
+
+       plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
+                                          sizeof(*plat->mdio_bus_data),
+                                          GFP_KERNEL);
+
+       dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL);
+       if (!dma_cfg)
+               return -ENOMEM;
+
+       plat->dma_cfg = dma_cfg;
+       of_property_read_u32(np, "samsung,pbl", &dma_cfg->pbl);
+       if (of_property_read_u32(np, "samsung,burst-map", &dma_cfg->burst_map) == 0)
+               dma_cfg->fixed_burst = true;
+
+       return 0;
+}
+#else
+static int sxgbe_probe_config_dt(struct platform_device *pdev,
+                                struct sxgbe_plat_data *plat,
+                                const char **mac)
+{
+       return -ENOSYS;
+}
+#endif /* CONFIG_OF */
+
+/**
+ * sxgbe_platform_probe
+ * @pdev: platform device pointer
+ * Description: platform_device probe function. It allocates
+ * the necessary resources and invokes the main to init
+ * the net device, register the mdio bus etc.
+ */
+static int sxgbe_platform_probe(struct platform_device *pdev)
+{
+       int ret;
+       int i, chan;
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       void __iomem *addr;
+       struct sxgbe_priv_data *priv = NULL;
+       struct sxgbe_plat_data *plat_dat = NULL;
+       const char *mac = NULL;
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       struct device_node *node = dev->of_node;
+
+       /* Get memory resource */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               goto err_out;
+
+       addr = devm_ioremap_resource(dev, res);
+       if (IS_ERR(addr))
+               return PTR_ERR(addr);
+
+       if (pdev->dev.of_node) {
+               plat_dat = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct sxgbe_plat_data),
+                                       GFP_KERNEL);
+               if (!plat_dat)
+                       return  -ENOMEM;
+
+               ret = sxgbe_probe_config_dt(pdev, plat_dat, &mac);
+               if (ret) {
+                       pr_err("%s: main dt probe failed\n", __func__);
+                       return ret;
+               }
+       }
+
+       /* Get MAC address if available (DT) */
+       if (mac)
+               ether_addr_copy(priv->dev->dev_addr, mac);
+
+       priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr);
+       if (!priv) {
+               pr_err("%s: main driver probe failed\n", __func__);
+               goto err_out;
+       }
+
+       /* Get the SXGBE common INT information */
+       priv->irq  = irq_of_parse_and_map(node, 0);
+       if (priv->irq <= 0) {
+               dev_err(dev, "sxgbe common irq parsing failed\n");
+               goto err_drv_remove;
+       }
+
+       /* Get the TX/RX IRQ numbers */
+       for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) {
+               priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++);
+               if (priv->txq[i]->irq_no <= 0) {
+                       dev_err(dev, "sxgbe tx irq parsing failed\n");
+                       goto err_tx_irq_unmap;
+               }
+       }
+
+       for (i = 0; i < SXGBE_RX_QUEUES; i++) {
+               priv->rxq[i]->irq_no = irq_of_parse_and_map(node, chan++);
+               if (priv->rxq[i]->irq_no <= 0) {
+                       dev_err(dev, "sxgbe rx irq parsing failed\n");
+                       goto err_rx_irq_unmap;
+               }
+       }
+
+       priv->lpi_irq = irq_of_parse_and_map(node, chan);
+       if (priv->lpi_irq <= 0) {
+               dev_err(dev, "sxgbe lpi irq parsing failed\n");
+               goto err_rx_irq_unmap;
+       }
+
+       platform_set_drvdata(pdev, priv->dev);
+
+       pr_debug("platform driver registration completed\n");
+
+       return 0;
+
+err_rx_irq_unmap:
+       while (--i)
+               irq_dispose_mapping(priv->rxq[i]->irq_no);
+       i = SXGBE_TX_QUEUES;
+err_tx_irq_unmap:
+       while (--i)
+               irq_dispose_mapping(priv->txq[i]->irq_no);
+       irq_dispose_mapping(priv->irq);
+err_drv_remove:
+       sxgbe_drv_remove(ndev);
+err_out:
+       return -ENODEV;
+}
+
+/**
+ * sxgbe_platform_remove
+ * @pdev: platform device pointer
+ * Description: this function calls the main to free the net resources
+ * and calls the platforms hook and release the resources (e.g. mem).
+ */
+static int sxgbe_platform_remove(struct platform_device *pdev)
+{
+       struct net_device *ndev = platform_get_drvdata(pdev);
+       int ret = sxgbe_drv_remove(ndev);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int sxgbe_platform_suspend(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+
+       return sxgbe_suspend(ndev);
+}
+
+static int sxgbe_platform_resume(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+
+       return sxgbe_resume(ndev);
+}
+
+static int sxgbe_platform_freeze(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+
+       return sxgbe_freeze(ndev);
+}
+
+static int sxgbe_platform_restore(struct device *dev)
+{
+       struct net_device *ndev = dev_get_drvdata(dev);
+
+       return sxgbe_restore(ndev);
+}
+
+static const struct dev_pm_ops sxgbe_platform_pm_ops = {
+       .suspend        = sxgbe_platform_suspend,
+       .resume         = sxgbe_platform_resume,
+       .freeze         = sxgbe_platform_freeze,
+       .thaw           = sxgbe_platform_restore,
+       .restore        = sxgbe_platform_restore,
+};
+#else
+static const struct dev_pm_ops sxgbe_platform_pm_ops;
+#endif /* CONFIG_PM */
+
+static const struct of_device_id sxgbe_dt_ids[] = {
+       { .compatible = "samsung,sxgbe-v2.0a"},
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sxgbe_dt_ids);
+
+static struct platform_driver sxgbe_platform_driver = {
+       .probe  = sxgbe_platform_probe,
+       .remove = sxgbe_platform_remove,
+       .driver = {
+               .name           = SXGBE_RESOURCE_NAME,
+               .owner          = THIS_MODULE,
+               .pm             = &sxgbe_platform_pm_ops,
+               .of_match_table = of_match_ptr(sxgbe_dt_ids),
+       },
+};
+
+int sxgbe_register_platform(void)
+{
+       int err;
+
+       err = platform_driver_register(&sxgbe_platform_driver);
+       if (err)
+               pr_err("failed to register the platform driver\n");
+
+       return err;
+}
+
+void sxgbe_unregister_platform(void)
+{
+       platform_driver_unregister(&sxgbe_platform_driver);
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_reg.h
new file mode 100644 (file)
index 0000000..5a89acb
--- /dev/null
@@ -0,0 +1,488 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 __SXGBE_REGMAP_H__
+#define __SXGBE_REGMAP_H__
+
+/* SXGBE MAC Registers */
+#define SXGBE_CORE_TX_CONFIG_REG       0x0000
+#define SXGBE_CORE_RX_CONFIG_REG       0x0004
+#define SXGBE_CORE_PKT_FILTER_REG      0x0008
+#define SXGBE_CORE_WATCHDOG_TIMEOUT_REG 0x000C
+#define SXGBE_CORE_HASH_TABLE_REG0     0x0010
+#define SXGBE_CORE_HASH_TABLE_REG1     0x0014
+#define SXGBE_CORE_HASH_TABLE_REG2     0x0018
+#define SXGBE_CORE_HASH_TABLE_REG3     0x001C
+#define SXGBE_CORE_HASH_TABLE_REG4     0x0020
+#define SXGBE_CORE_HASH_TABLE_REG5     0x0024
+#define SXGBE_CORE_HASH_TABLE_REG6     0x0028
+#define SXGBE_CORE_HASH_TABLE_REG7     0x002C
+
+/* EEE-LPI Registers */
+#define SXGBE_CORE_LPI_CTRL_STATUS     0x00D0
+#define SXGBE_CORE_LPI_TIMER_CTRL      0x00D4
+
+/* VLAN Specific Registers */
+#define SXGBE_CORE_VLAN_TAG_REG                0x0050
+#define SXGBE_CORE_VLAN_HASHTAB_REG    0x0058
+#define SXGBE_CORE_VLAN_INSCTL_REG     0x0060
+#define SXGBE_CORE_VLAN_INNERCTL_REG   0x0064
+#define SXGBE_CORE_RX_ETHTYPE_MATCH_REG 0x006C
+
+/* Flow Contol Registers */
+#define SXGBE_CORE_TX_Q0_FLOWCTL_REG   0x0070
+#define SXGBE_CORE_TX_Q1_FLOWCTL_REG   0x0074
+#define SXGBE_CORE_TX_Q2_FLOWCTL_REG   0x0078
+#define SXGBE_CORE_TX_Q3_FLOWCTL_REG   0x007C
+#define SXGBE_CORE_TX_Q4_FLOWCTL_REG   0x0080
+#define SXGBE_CORE_TX_Q5_FLOWCTL_REG   0x0084
+#define SXGBE_CORE_TX_Q6_FLOWCTL_REG   0x0088
+#define SXGBE_CORE_TX_Q7_FLOWCTL_REG   0x008C
+#define SXGBE_CORE_RX_FLOWCTL_REG      0x0090
+#define SXGBE_CORE_RX_CTL0_REG         0x00A0
+#define SXGBE_CORE_RX_CTL1_REG         0x00A4
+#define SXGBE_CORE_RX_CTL2_REG         0x00A8
+#define SXGBE_CORE_RX_CTL3_REG         0x00AC
+
+/* Interrupt Registers */
+#define SXGBE_CORE_INT_STATUS_REG      0x00B0
+#define SXGBE_CORE_INT_ENABLE_REG      0x00B4
+#define SXGBE_CORE_RXTX_ERR_STATUS_REG 0x00B8
+#define SXGBE_CORE_PMT_CTL_STATUS_REG  0x00C0
+#define SXGBE_CORE_RWK_PKT_FILTER_REG  0x00C4
+#define SXGBE_CORE_VERSION_REG         0x0110
+#define SXGBE_CORE_DEBUG_REG           0x0114
+#define SXGBE_CORE_HW_FEA_REG(index)   (0x011C + index * 4)
+
+/* SMA(MDIO) module registers */
+#define SXGBE_MDIO_SCMD_ADD_REG                0x0200
+#define SXGBE_MDIO_SCMD_DATA_REG       0x0204
+#define SXGBE_MDIO_CCMD_WADD_REG       0x0208
+#define SXGBE_MDIO_CCMD_WDATA_REG      0x020C
+#define SXGBE_MDIO_CSCAN_PORT_REG      0x0210
+#define SXGBE_MDIO_INT_STATUS_REG      0x0214
+#define SXGBE_MDIO_INT_ENABLE_REG      0x0218
+#define SXGBE_MDIO_PORT_CONDCON_REG    0x021C
+#define SXGBE_MDIO_CLAUSE22_PORT_REG   0x0220
+
+/* port specific, addr = 0-3 */
+#define SXGBE_MDIO_DEV_BASE_REG                0x0230
+#define SXGBE_MDIO_PORT_DEV_REG(addr)                  \
+       (SXGBE_MDIO_DEV_BASE_REG + (0x10 * addr) + 0x0)
+#define SXGBE_MDIO_PORT_LSTATUS_REG(addr)              \
+       (SXGBE_MDIO_DEV_BASE_REG + (0x10 * addr) + 0x4)
+#define SXGBE_MDIO_PORT_ALIVE_REG(addr)                        \
+       (SXGBE_MDIO_DEV_BASE_REG + (0x10 * addr) + 0x8)
+
+#define SXGBE_CORE_GPIO_CTL_REG                0x0278
+#define SXGBE_CORE_GPIO_STATUS_REG     0x027C
+
+/* Address registers for filtering */
+#define SXGBE_CORE_ADD_BASE_REG                0x0300
+
+/* addr = 0-31 */
+#define SXGBE_CORE_ADD_HIGHOFFSET(addr)                        \
+       (SXGBE_CORE_ADD_BASE_REG + (0x8 * addr) + 0x0)
+#define SXGBE_CORE_ADD_LOWOFFSET(addr)                 \
+       (SXGBE_CORE_ADD_BASE_REG + (0x8 * addr) + 0x4)
+
+/* SXGBE MMC registers */
+#define SXGBE_MMC_CTL_REG              0x0800
+#define SXGBE_MMC_RXINT_STATUS_REG     0x0804
+#define SXGBE_MMC_TXINT_STATUS_REG     0x0808
+#define SXGBE_MMC_RXINT_ENABLE_REG     0x080C
+#define SXGBE_MMC_TXINT_ENABLE_REG     0x0810
+
+/* TX specific counters */
+#define SXGBE_MMC_TXOCTETHI_GBCNT_REG  0x0814
+#define SXGBE_MMC_TXOCTETLO_GBCNT_REG  0x0818
+#define SXGBE_MMC_TXFRAMELO_GBCNT_REG  0x081C
+#define SXGBE_MMC_TXFRAMEHI_GBCNT_REG  0x0820
+#define SXGBE_MMC_TXBROADLO_GCNT_REG   0x0824
+#define SXGBE_MMC_TXBROADHI_GCNT_REG   0x0828
+#define SXGBE_MMC_TXMULTILO_GCNT_REG   0x082C
+#define SXGBE_MMC_TXMULTIHI_GCNT_REG   0x0830
+#define SXGBE_MMC_TX64LO_GBCNT_REG     0x0834
+#define SXGBE_MMC_TX64HI_GBCNT_REG     0x0838
+#define SXGBE_MMC_TX65TO127LO_GBCNT_REG                0x083C
+#define SXGBE_MMC_TX65TO127HI_GBCNT_REG                0x0840
+#define SXGBE_MMC_TX128TO255LO_GBCNT_REG       0x0844
+#define SXGBE_MMC_TX128TO255HI_GBCNT_REG       0x0848
+#define SXGBE_MMC_TX256TO511LO_GBCNT_REG       0x084C
+#define SXGBE_MMC_TX256TO511HI_GBCNT_REG       0x0850
+#define SXGBE_MMC_TX512TO1023LO_GBCNT_REG      0x0854
+#define SXGBE_MMC_TX512TO1023HI_GBCNT_REG      0x0858
+#define SXGBE_MMC_TX1023TOMAXLO_GBCNT_REG      0x085C
+#define SXGBE_MMC_TX1023TOMAXHI_GBCNT_REG      0x0860
+#define SXGBE_MMC_TXUNICASTLO_GBCNT_REG                0x0864
+#define SXGBE_MMC_TXUNICASTHI_GBCNT_REG                0x0868
+#define SXGBE_MMC_TXMULTILO_GBCNT_REG          0x086C
+#define SXGBE_MMC_TXMULTIHI_GBCNT_REG          0x0870
+#define SXGBE_MMC_TXBROADLO_GBCNT_REG          0x0874
+#define SXGBE_MMC_TXBROADHI_GBCNT_REG          0x0878
+#define SXGBE_MMC_TXUFLWLO_GBCNT_REG           0x087C
+#define SXGBE_MMC_TXUFLWHI_GBCNT_REG           0x0880
+#define SXGBE_MMC_TXOCTETLO_GCNT_REG   0x0884
+#define SXGBE_MMC_TXOCTETHI_GCNT_REG   0x0888
+#define SXGBE_MMC_TXFRAMELO_GCNT_REG   0x088C
+#define SXGBE_MMC_TXFRAMEHI_GCNT_REG   0x0890
+#define SXGBE_MMC_TXPAUSELO_CNT_REG    0x0894
+#define SXGBE_MMC_TXPAUSEHI_CNT_REG    0x0898
+#define SXGBE_MMC_TXVLANLO_GCNT_REG    0x089C
+#define SXGBE_MMC_TXVLANHI_GCNT_REG    0x08A0
+
+/* RX specific counters */
+#define SXGBE_MMC_RXFRAMELO_GBCNT_REG  0x0900
+#define SXGBE_MMC_RXFRAMEHI_GBCNT_REG  0x0904
+#define SXGBE_MMC_RXOCTETLO_GBCNT_REG  0x0908
+#define SXGBE_MMC_RXOCTETHI_GBCNT_REG  0x090C
+#define SXGBE_MMC_RXOCTETLO_GCNT_REG   0x0910
+#define SXGBE_MMC_RXOCTETHI_GCNT_REG   0x0914
+#define SXGBE_MMC_RXBROADLO_GCNT_REG   0x0918
+#define SXGBE_MMC_RXBROADHI_GCNT_REG   0x091C
+#define SXGBE_MMC_RXMULTILO_GCNT_REG   0x0920
+#define SXGBE_MMC_RXMULTIHI_GCNT_REG   0x0924
+#define SXGBE_MMC_RXCRCERRLO_REG       0x0928
+#define SXGBE_MMC_RXCRCERRHI_REG       0x092C
+#define SXGBE_MMC_RXSHORT64BFRAME_ERR_REG      0x0930
+#define SXGBE_MMC_RXJABBERERR_REG              0x0934
+#define SXGBE_MMC_RXSHORT64BFRAME_COR_REG      0x0938
+#define SXGBE_MMC_RXOVERMAXFRAME_COR_REG       0x093C
+#define SXGBE_MMC_RX64LO_GBCNT_REG             0x0940
+#define SXGBE_MMC_RX64HI_GBCNT_REG             0x0944
+#define SXGBE_MMC_RX65TO127LO_GBCNT_REG                0x0948
+#define SXGBE_MMC_RX65TO127HI_GBCNT_REG                0x094C
+#define SXGBE_MMC_RX128TO255LO_GBCNT_REG       0x0950
+#define SXGBE_MMC_RX128TO255HI_GBCNT_REG       0x0954
+#define SXGBE_MMC_RX256TO511LO_GBCNT_REG       0x0958
+#define SXGBE_MMC_RX256TO511HI_GBCNT_REG       0x095C
+#define SXGBE_MMC_RX512TO1023LO_GBCNT_REG      0x0960
+#define SXGBE_MMC_RX512TO1023HI_GBCNT_REG      0x0964
+#define SXGBE_MMC_RX1023TOMAXLO_GBCNT_REG      0x0968
+#define SXGBE_MMC_RX1023TOMAXHI_GBCNT_REG      0x096C
+#define SXGBE_MMC_RXUNICASTLO_GCNT_REG         0x0970
+#define SXGBE_MMC_RXUNICASTHI_GCNT_REG         0x0974
+#define SXGBE_MMC_RXLENERRLO_REG               0x0978
+#define SXGBE_MMC_RXLENERRHI_REG               0x097C
+#define SXGBE_MMC_RXOUTOFRANGETYPELO_REG       0x0980
+#define SXGBE_MMC_RXOUTOFRANGETYPEHI_REG       0x0984
+#define SXGBE_MMC_RXPAUSELO_CNT_REG            0x0988
+#define SXGBE_MMC_RXPAUSEHI_CNT_REG            0x098C
+#define SXGBE_MMC_RXFIFOOVERFLOWLO_GBCNT_REG   0x0990
+#define SXGBE_MMC_RXFIFOOVERFLOWHI_GBCNT_REG   0x0994
+#define SXGBE_MMC_RXVLANLO_GBCNT_REG           0x0998
+#define SXGBE_MMC_RXVLANHI_GBCNT_REG           0x099C
+#define SXGBE_MMC_RXWATCHDOG_ERR_REG           0x09A0
+
+/* L3/L4 function registers */
+#define SXGBE_CORE_L34_ADDCTL_REG      0x0C00
+#define SXGBE_CORE_L34_ADDCTL_REG      0x0C00
+#define SXGBE_CORE_L34_DATA_REG                0x0C04
+
+/* ARP registers */
+#define SXGBE_CORE_ARP_ADD_REG         0x0C10
+
+/* RSS registers */
+#define SXGBE_CORE_RSS_CTL_REG         0x0C80
+#define SXGBE_CORE_RSS_ADD_REG         0x0C88
+#define SXGBE_CORE_RSS_DATA_REG                0x0C8C
+
+/* RSS control register bits */
+#define SXGBE_CORE_RSS_CTL_UDP4TE      BIT(3)
+#define SXGBE_CORE_RSS_CTL_TCP4TE      BIT(2)
+#define SXGBE_CORE_RSS_CTL_IP2TE       BIT(1)
+#define SXGBE_CORE_RSS_CTL_RSSE                BIT(0)
+
+/* IEEE 1588 registers */
+#define SXGBE_CORE_TSTAMP_CTL_REG      0x0D00
+#define SXGBE_CORE_SUBSEC_INC_REG      0x0D04
+#define SXGBE_CORE_SYSTIME_SEC_REG     0x0D0C
+#define SXGBE_CORE_SYSTIME_NSEC_REG    0x0D10
+#define SXGBE_CORE_SYSTIME_SECUP_REG   0x0D14
+#define SXGBE_CORE_TSTAMP_ADD_REG      0x0D18
+#define SXGBE_CORE_SYSTIME_HWORD_REG   0x0D1C
+#define SXGBE_CORE_TSTAMP_STATUS_REG   0x0D20
+#define SXGBE_CORE_TXTIME_STATUSNSEC_REG 0x0D30
+#define SXGBE_CORE_TXTIME_STATUSSEC_REG        0x0D34
+
+/* Auxiliary registers */
+#define SXGBE_CORE_AUX_CTL_REG                  0x0D40
+#define SXGBE_CORE_AUX_TSTAMP_NSEC_REG          0x0D48
+#define SXGBE_CORE_AUX_TSTAMP_SEC_REG           0x0D4C
+#define SXGBE_CORE_AUX_TSTAMP_INGCOR_REG        0x0D50
+#define SXGBE_CORE_AUX_TSTAMP_ENGCOR_REG        0x0D54
+#define SXGBE_CORE_AUX_TSTAMP_INGCOR_NSEC_REG   0x0D58
+#define SXGBE_CORE_AUX_TSTAMP_INGCOR_SUBNSEC_REG 0x0D5C
+#define SXGBE_CORE_AUX_TSTAMP_ENGCOR_NSEC_REG   0x0D60
+#define SXGBE_CORE_AUX_TSTAMP_ENGCOR_SUBNSEC_REG 0x0D64
+
+/* PPS registers */
+#define SXGBE_CORE_PPS_CTL_REG         0x0D70
+#define SXGBE_CORE_PPS_BASE                    0x0D80
+
+/* addr = 0 - 3 */
+#define SXGBE_CORE_PPS_TTIME_SEC_REG(addr)             \
+       (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0x0)
+#define SXGBE_CORE_PPS_TTIME_NSEC_REG(addr)            \
+       (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0x4)
+#define SXGBE_CORE_PPS_INTERVAL_REG(addr)              \
+       (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0x8)
+#define SXGBE_CORE_PPS_WIDTH_REG(addr)                 \
+       (SXGBE_CORE_PPS_BASE + (0x10 * addr) + 0xC)
+#define SXGBE_CORE_PTO_CTL_REG         0x0DC0
+#define SXGBE_CORE_SRCPORT_ITY0_REG    0x0DC4
+#define SXGBE_CORE_SRCPORT_ITY1_REG    0x0DC8
+#define SXGBE_CORE_SRCPORT_ITY2_REG    0x0DCC
+#define SXGBE_CORE_LOGMSG_LEVEL_REG    0x0DD0
+
+/* SXGBE MTL Registers */
+#define SXGBE_MTL_BASE_REG             0x1000
+#define SXGBE_MTL_OP_MODE_REG          (SXGBE_MTL_BASE_REG + 0x0000)
+#define SXGBE_MTL_DEBUG_CTL_REG                (SXGBE_MTL_BASE_REG + 0x0008)
+#define SXGBE_MTL_DEBUG_STATUS_REG     (SXGBE_MTL_BASE_REG + 0x000C)
+#define SXGBE_MTL_FIFO_DEBUGDATA_REG   (SXGBE_MTL_BASE_REG + 0x0010)
+#define SXGBE_MTL_INT_STATUS_REG       (SXGBE_MTL_BASE_REG + 0x0020)
+#define SXGBE_MTL_RXQ_DMAMAP0_REG      (SXGBE_MTL_BASE_REG + 0x0030)
+#define SXGBE_MTL_RXQ_DMAMAP1_REG      (SXGBE_MTL_BASE_REG + 0x0034)
+#define SXGBE_MTL_RXQ_DMAMAP2_REG      (SXGBE_MTL_BASE_REG + 0x0038)
+#define SXGBE_MTL_TX_PRTYMAP0_REG      (SXGBE_MTL_BASE_REG + 0x0040)
+#define SXGBE_MTL_TX_PRTYMAP1_REG      (SXGBE_MTL_BASE_REG + 0x0044)
+
+/* TC/Queue registers, qnum=0-15 */
+#define SXGBE_MTL_TC_TXBASE_REG                (SXGBE_MTL_BASE_REG + 0x0100)
+#define SXGBE_MTL_TXQ_OPMODE_REG(qnum)                         \
+       (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x00)
+#define SXGBE_MTL_SFMODE               BIT(1)
+#define SXGBE_MTL_FIFO_LSHIFT          16
+#define SXGBE_MTL_ENABLE_QUEUE         0x00000008
+#define SXGBE_MTL_TXQ_UNDERFLOW_REG(qnum)                      \
+       (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x04)
+#define SXGBE_MTL_TXQ_DEBUG_REG(qnum)                          \
+       (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x08)
+#define SXGBE_MTL_TXQ_ETSCTL_REG(qnum)                         \
+       (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x10)
+#define SXGBE_MTL_TXQ_ETSSTATUS_REG(qnum)                      \
+       (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x14)
+#define SXGBE_MTL_TXQ_QUANTWEIGHT_REG(qnum)                    \
+       (SXGBE_MTL_TC_TXBASE_REG + (qnum * 0x80) + 0x18)
+
+#define SXGBE_MTL_TC_RXBASE_REG                0x1140
+#define SXGBE_RX_MTL_SFMODE            BIT(5)
+#define SXGBE_MTL_RXQ_OPMODE_REG(qnum)                         \
+       (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x00)
+#define SXGBE_MTL_RXQ_MISPKTOVERFLOW_REG(qnum)                 \
+       (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x04)
+#define SXGBE_MTL_RXQ_DEBUG_REG(qnum)                          \
+       (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x08)
+#define SXGBE_MTL_RXQ_CTL_REG(qnum)                            \
+       (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x0C)
+#define SXGBE_MTL_RXQ_INTENABLE_REG(qnum)                      \
+       (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x30)
+#define SXGBE_MTL_RXQ_INTSTATUS_REG(qnum)                      \
+       (SXGBE_MTL_TC_RXBASE_REG + (qnum * 0x80) + 0x34)
+
+/* SXGBE DMA Registers */
+#define SXGBE_DMA_BASE_REG             0x3000
+#define SXGBE_DMA_MODE_REG             (SXGBE_DMA_BASE_REG + 0x0000)
+#define SXGBE_DMA_SOFT_RESET           BIT(0)
+#define SXGBE_DMA_SYSBUS_MODE_REG      (SXGBE_DMA_BASE_REG + 0x0004)
+#define SXGBE_DMA_AXI_UNDEF_BURST      BIT(0)
+#define SXGBE_DMA_ENHACE_ADDR_MODE     BIT(11)
+#define SXGBE_DMA_INT_STATUS_REG       (SXGBE_DMA_BASE_REG + 0x0008)
+#define SXGBE_DMA_AXI_ARCACHECTL_REG   (SXGBE_DMA_BASE_REG + 0x0010)
+#define SXGBE_DMA_AXI_AWCACHECTL_REG   (SXGBE_DMA_BASE_REG + 0x0018)
+#define SXGBE_DMA_DEBUG_STATUS0_REG    (SXGBE_DMA_BASE_REG + 0x0020)
+#define SXGBE_DMA_DEBUG_STATUS1_REG    (SXGBE_DMA_BASE_REG + 0x0024)
+#define SXGBE_DMA_DEBUG_STATUS2_REG    (SXGBE_DMA_BASE_REG + 0x0028)
+#define SXGBE_DMA_DEBUG_STATUS3_REG    (SXGBE_DMA_BASE_REG + 0x002C)
+#define SXGBE_DMA_DEBUG_STATUS4_REG    (SXGBE_DMA_BASE_REG + 0x0030)
+#define SXGBE_DMA_DEBUG_STATUS5_REG    (SXGBE_DMA_BASE_REG + 0x0034)
+
+/* Channel Registers, cha_num = 0-15 */
+#define SXGBE_DMA_CHA_BASE_REG                 \
+       (SXGBE_DMA_BASE_REG + 0x0100)
+#define SXGBE_DMA_CHA_CTL_REG(cha_num)                         \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x00)
+#define SXGBE_DMA_PBL_X8MODE                   BIT(16)
+#define SXGBE_DMA_CHA_TXCTL_TSE_ENABLE         BIT(12)
+#define SXGBE_DMA_CHA_TXCTL_REG(cha_num)                       \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x04)
+#define SXGBE_DMA_CHA_RXCTL_REG(cha_num)                       \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x08)
+#define SXGBE_DMA_CHA_TXDESC_HADD_REG(cha_num)                 \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x10)
+#define SXGBE_DMA_CHA_TXDESC_LADD_REG(cha_num)                 \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x14)
+#define SXGBE_DMA_CHA_RXDESC_HADD_REG(cha_num)                 \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x18)
+#define SXGBE_DMA_CHA_RXDESC_LADD_REG(cha_num)                 \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x1C)
+#define SXGBE_DMA_CHA_TXDESC_TAILPTR_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x24)
+#define SXGBE_DMA_CHA_RXDESC_TAILPTR_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x2C)
+#define SXGBE_DMA_CHA_TXDESC_RINGLEN_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x30)
+#define SXGBE_DMA_CHA_RXDESC_RINGLEN_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x34)
+#define SXGBE_DMA_CHA_INT_ENABLE_REG(cha_num)                  \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x38)
+#define SXGBE_DMA_CHA_INT_RXWATCHTMR_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x3C)
+#define SXGBE_DMA_CHA_TXDESC_CURADDLO_REG(cha_num)             \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x44)
+#define SXGBE_DMA_CHA_RXDESC_CURADDLO_REG(cha_num)             \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x4C)
+#define SXGBE_DMA_CHA_CURTXBUF_ADDHI_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x50)
+#define SXGBE_DMA_CHA_CURTXBUF_ADDLO_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x54)
+#define SXGBE_DMA_CHA_CURRXBUF_ADDHI_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x58)
+#define SXGBE_DMA_CHA_CURRXBUF_ADDLO_REG(cha_num)              \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x5C)
+#define SXGBE_DMA_CHA_STATUS_REG(cha_num)                      \
+       (SXGBE_DMA_CHA_BASE_REG + (cha_num * 0x80) + 0x60)
+
+/* TX DMA control register specific */
+#define SXGBE_TX_START_DMA     BIT(0)
+
+/* sxgbe tx configuration register bitfields */
+#define SXGBE_SPEED_10G                0x0
+#define SXGBE_SPEED_2_5G       0x1
+#define SXGBE_SPEED_1G         0x2
+#define SXGBE_SPEED_LSHIFT     29
+
+#define SXGBE_TX_ENABLE                BIT(0)
+#define SXGBE_TX_DISDIC_ALGO   BIT(1)
+#define SXGBE_TX_JABBER_DISABLE        BIT(16)
+
+/* sxgbe rx configuration register bitfields */
+#define SXGBE_RX_ENABLE                BIT(0)
+#define SXGBE_RX_ACS_ENABLE            BIT(1)
+#define SXGBE_RX_WATCHDOG_DISABLE      BIT(7)
+#define SXGBE_RX_JUMBPKT_ENABLE                BIT(8)
+#define SXGBE_RX_CSUMOFFLOAD_ENABLE    BIT(9)
+#define SXGBE_RX_LOOPBACK_ENABLE       BIT(10)
+#define SXGBE_RX_ARPOFFLOAD_ENABLE     BIT(31)
+
+/* sxgbe vlan Tag Register bitfields */
+#define SXGBE_VLAN_SVLAN_ENABLE                BIT(18)
+#define SXGBE_VLAN_DOUBLEVLAN_ENABLE   BIT(26)
+#define SXGBE_VLAN_INNERVLAN_ENABLE    BIT(27)
+
+/* XMAC VLAN Tag Inclusion Register(0x0060) bitfields
+ * Below fields same for  Inner VLAN Tag Inclusion
+ * Register(0x0064) register
+ */
+enum vlan_tag_ctl_tx {
+       VLAN_TAG_TX_NOP,
+       VLAN_TAG_TX_DEL,
+       VLAN_TAG_TX_INSERT,
+       VLAN_TAG_TX_REPLACE
+};
+#define SXGBE_VLAN_PRTY_CTL    BIT(18)
+#define SXGBE_VLAN_CSVL_CTL    BIT(19)
+
+/* SXGBE TX Q Flow Control Register bitfields */
+#define SXGBE_TX_FLOW_CTL_FCB  BIT(0)
+#define SXGBE_TX_FLOW_CTL_TFB  BIT(1)
+
+/* SXGBE RX Q Flow Control Register bitfields */
+#define SXGBE_RX_FLOW_CTL_ENABLE       BIT(0)
+#define SXGBE_RX_UNICAST_DETECT                BIT(1)
+#define SXGBE_RX_PRTYFLOW_CTL_ENABLE   BIT(8)
+
+/* sxgbe rx Q control0 register bitfields */
+#define SXGBE_RX_Q_ENABLE      0x2
+
+/* SXGBE hardware features bitfield specific */
+/* Capability Register 0 */
+#define SXGBE_HW_FEAT_GMII(cap)                        ((cap & 0x00000002) >> 1)
+#define SXGBE_HW_FEAT_VLAN_HASH_FILTER(cap)    ((cap & 0x00000010) >> 4)
+#define SXGBE_HW_FEAT_SMA(cap)                 ((cap & 0x00000020) >> 5)
+#define SXGBE_HW_FEAT_PMT_TEMOTE_WOP(cap)      ((cap & 0x00000040) >> 6)
+#define SXGBE_HW_FEAT_PMT_MAGIC_PKT(cap)       ((cap & 0x00000080) >> 7)
+#define SXGBE_HW_FEAT_RMON(cap)                        ((cap & 0x00000100) >> 8)
+#define SXGBE_HW_FEAT_ARP_OFFLOAD(cap)         ((cap & 0x00000200) >> 9)
+#define SXGBE_HW_FEAT_IEEE1500_2008(cap)       ((cap & 0x00001000) >> 12)
+#define SXGBE_HW_FEAT_EEE(cap)                 ((cap & 0x00002000) >> 13)
+#define SXGBE_HW_FEAT_TX_CSUM_OFFLOAD(cap)     ((cap & 0x00004000) >> 14)
+#define SXGBE_HW_FEAT_RX_CSUM_OFFLOAD(cap)     ((cap & 0x00010000) >> 16)
+#define SXGBE_HW_FEAT_MACADDR_COUNT(cap)       ((cap & 0x007C0000) >> 18)
+#define SXGBE_HW_FEAT_TSTMAP_SRC(cap)          ((cap & 0x06000000) >> 25)
+#define SXGBE_HW_FEAT_SRCADDR_VLAN(cap)                ((cap & 0x08000000) >> 27)
+
+/* Capability Register 1 */
+#define SXGBE_HW_FEAT_RX_FIFO_SIZE(cap)                ((cap & 0x0000001F))
+#define SXGBE_HW_FEAT_TX_FIFO_SIZE(cap)                ((cap & 0x000007C0) >> 6)
+#define SXGBE_HW_FEAT_IEEE1588_HWORD(cap)      ((cap & 0x00002000) >> 13)
+#define SXGBE_HW_FEAT_DCB(cap)                 ((cap & 0x00010000) >> 16)
+#define SXGBE_HW_FEAT_SPLIT_HDR(cap)           ((cap & 0x00020000) >> 17)
+#define SXGBE_HW_FEAT_TSO(cap)                 ((cap & 0x00040000) >> 18)
+#define SXGBE_HW_FEAT_DEBUG_MEM_IFACE(cap)     ((cap & 0x00080000) >> 19)
+#define SXGBE_HW_FEAT_RSS(cap)                 ((cap & 0x00100000) >> 20)
+#define SXGBE_HW_FEAT_HASH_TABLE_SIZE(cap)     ((cap & 0x03000000) >> 24)
+#define SXGBE_HW_FEAT_L3L4_FILTER_NUM(cap)     ((cap & 0x78000000) >> 27)
+
+/* Capability Register 2 */
+#define SXGBE_HW_FEAT_RX_MTL_QUEUES(cap)       ((cap & 0x0000000F))
+#define SXGBE_HW_FEAT_TX_MTL_QUEUES(cap)       ((cap & 0x000003C0) >> 6)
+#define SXGBE_HW_FEAT_RX_DMA_CHANNELS(cap)     ((cap & 0x0000F000) >> 12)
+#define SXGBE_HW_FEAT_TX_DMA_CHANNELS(cap)     ((cap & 0x003C0000) >> 18)
+#define SXGBE_HW_FEAT_PPS_OUTPUTS(cap)         ((cap & 0x07000000) >> 24)
+#define SXGBE_HW_FEAT_AUX_SNAPSHOTS(cap)       ((cap & 0x70000000) >> 28)
+
+/* DMAchannel interrupt enable specific */
+/* DMA Normal interrupt */
+#define SXGBE_DMA_INT_ENA_NIE  BIT(16) /* Normal Summary */
+#define SXGBE_DMA_INT_ENA_TIE  BIT(0)  /* Transmit Interrupt */
+#define SXGBE_DMA_INT_ENA_TUE  BIT(2)  /* Transmit Buffer Unavailable */
+#define SXGBE_DMA_INT_ENA_RIE  BIT(6)  /* Receive Interrupt */
+
+#define SXGBE_DMA_INT_NORMAL                                   \
+       (SXGBE_DMA_INT_ENA_NIE | SXGBE_DMA_INT_ENA_RIE |        \
+        SXGBE_DMA_INT_ENA_TIE | SXGBE_DMA_INT_ENA_TUE)
+
+/* DMA Abnormal interrupt */
+#define SXGBE_DMA_INT_ENA_AIE  BIT(15) /* Abnormal Summary */
+#define SXGBE_DMA_INT_ENA_TSE  BIT(1)  /* Transmit Stopped */
+#define SXGBE_DMA_INT_ENA_RUE  BIT(7)  /* Receive Buffer Unavailable */
+#define SXGBE_DMA_INT_ENA_RSE  BIT(8)  /* Receive Stopped */
+#define SXGBE_DMA_INT_ENA_FBE  BIT(12) /* Fatal Bus Error */
+#define SXGBE_DMA_INT_ENA_CDEE BIT(13) /* Context Descriptor Error */
+
+#define SXGBE_DMA_INT_ABNORMAL                                 \
+       (SXGBE_DMA_INT_ENA_AIE | SXGBE_DMA_INT_ENA_TSE |        \
+        SXGBE_DMA_INT_ENA_RUE | SXGBE_DMA_INT_ENA_RSE |        \
+        SXGBE_DMA_INT_ENA_FBE | SXGBE_DMA_INT_ENA_CDEE)
+
+#define SXGBE_DMA_ENA_INT      (SXGBE_DMA_INT_NORMAL | SXGBE_DMA_INT_ABNORMAL)
+
+/* DMA channel interrupt status specific */
+#define        SXGBE_DMA_INT_STATUS_REB2       BIT(21)
+#define        SXGBE_DMA_INT_STATUS_REB1       BIT(20)
+#define        SXGBE_DMA_INT_STATUS_REB0       BIT(19)
+#define        SXGBE_DMA_INT_STATUS_TEB2       BIT(18)
+#define        SXGBE_DMA_INT_STATUS_TEB1       BIT(17)
+#define        SXGBE_DMA_INT_STATUS_TEB0       BIT(16)
+#define        SXGBE_DMA_INT_STATUS_NIS        BIT(15)
+#define SXGBE_DMA_INT_STATUS_AIS       BIT(14)
+#define SXGBE_DMA_INT_STATUS_CTXTERR   BIT(13)
+#define SXGBE_DMA_INT_STATUS_FBE       BIT(12)
+#define SXGBE_DMA_INT_STATUS_RPS       BIT(8)
+#define SXGBE_DMA_INT_STATUS_RBU       BIT(7)
+#define SXGBE_DMA_INT_STATUS_RI                BIT(6)
+#define SXGBE_DMA_INT_STATUS_TBU       BIT(2)
+#define SXGBE_DMA_INT_STATUS_TPS       BIT(1)
+#define SXGBE_DMA_INT_STATUS_TI                BIT(0)
+
+#endif /* __SXGBE_REGMAP_H__ */
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c
new file mode 100644 (file)
index 0000000..51c3219
--- /dev/null
@@ -0,0 +1,91 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include "sxgbe_common.h"
+#include "sxgbe_xpcs.h"
+
+static int sxgbe_xpcs_read(struct net_device *ndev, unsigned int reg)
+{
+       u32 value;
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+       value = readl(priv->ioaddr + XPCS_OFFSET + reg);
+
+       return value;
+}
+
+static int sxgbe_xpcs_write(struct net_device *ndev, int reg, int data)
+{
+       struct sxgbe_priv_data *priv = netdev_priv(ndev);
+
+       writel(data, priv->ioaddr + XPCS_OFFSET + reg);
+
+       return 0;
+}
+
+int sxgbe_xpcs_init(struct net_device *ndev)
+{
+       u32 value;
+
+       value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+       /* 10G XAUI mode */
+       sxgbe_xpcs_write(ndev, SR_PCS_CONTROL2, XPCS_TYPE_SEL_X);
+       sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, XPCS_XAUI_MODE);
+       sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, value | BIT(13));
+       sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value | BIT(11));
+
+       do {
+               value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS);
+       } while ((value & XPCS_QSEQ_STATE_MPLLOFF) == XPCS_QSEQ_STATE_STABLE);
+
+       value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+       sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(11));
+
+       do {
+               value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS);
+       } while ((value & XPCS_QSEQ_STATE_MPLLOFF) != XPCS_QSEQ_STATE_STABLE);
+
+       return 0;
+}
+
+int sxgbe_xpcs_init_1G(struct net_device *ndev)
+{
+       int value;
+
+       /* 10GBASE-X PCS (1G) mode */
+       sxgbe_xpcs_write(ndev, SR_PCS_CONTROL2, XPCS_TYPE_SEL_X);
+       sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, XPCS_XAUI_MODE);
+       value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+       sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(13));
+
+       value = sxgbe_xpcs_read(ndev, SR_MII_MMD_CONTROL);
+       sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value | BIT(6));
+       sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value & ~BIT(13));
+       value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+       sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value | BIT(11));
+
+       do {
+               value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS);
+       } while ((value & XPCS_QSEQ_STATE_MPLLOFF) != XPCS_QSEQ_STATE_STABLE);
+
+       value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1);
+       sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(11));
+
+       /* Auto Negotiation cluase 37 enable */
+       value = sxgbe_xpcs_read(ndev, SR_MII_MMD_CONTROL);
+       sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value | BIT(12));
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.h
new file mode 100644 (file)
index 0000000..6b26a50
--- /dev/null
@@ -0,0 +1,38 @@
+/* 10G controller driver for Samsung SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Byungho An <bh74.an@samsung.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 __SXGBE_XPCS_H__
+#define __SXGBE_XPCS_H__
+
+/* XPCS Registers */
+#define XPCS_OFFSET                    0x1A060000
+#define SR_PCS_MMD_CONTROL1            0x030000
+#define SR_PCS_CONTROL2                        0x030007
+#define VR_PCS_MMD_XAUI_MODE_CONTROL   0x038004
+#define VR_PCS_MMD_DIGITAL_STATUS      0x038010
+#define SR_MII_MMD_CONTROL             0x1F0000
+#define SR_MII_MMD_AN_ADV              0x1F0004
+#define SR_MII_MMD_AN_LINK_PARTNER_BA  0x1F0005
+#define VR_MII_MMD_AN_CONTROL          0x1F8001
+#define VR_MII_MMD_AN_INT_STATUS       0x1F8002
+
+#define XPCS_QSEQ_STATE_STABLE         0x10
+#define XPCS_QSEQ_STATE_MPLLOFF                0x1c
+#define XPCS_TYPE_SEL_R                        0x00
+#define XPCS_TYPE_SEL_X                        0x01
+#define XPCS_TYPE_SEL_W                        0x02
+#define XPCS_XAUI_MODE                 0x00
+#define XPCS_RXAUI_MODE                        0x01
+
+int sxgbe_xpcs_init(struct net_device *ndev);
+int sxgbe_xpcs_init_1G(struct net_device *ndev);
+
+#endif /* __SXGBE_XPCS_H__ */
index 174a92f5fe5133814055cff36c14c0374901cbaf..651626e133f9b788dacc47234822c6f90190799d 100644 (file)
@@ -162,8 +162,8 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address)
        if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)
                return -EIO;
 
-       memcpy(mac_address,
-              MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE), ETH_ALEN);
+       ether_addr_copy(mac_address,
+                       MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE));
        return 0;
 }
 
@@ -172,8 +172,8 @@ static int efx_ef10_probe(struct efx_nic *efx)
        struct efx_ef10_nic_data *nic_data;
        int i, rc;
 
-       /* We can have one VI for each 8K region.  However we need
-        * multiple TX queues per channel.
+       /* We can have one VI for each 8K region.  However, until we
+        * use TX option descriptors we need two TX queues per channel.
         */
        efx->max_channels =
                min_t(unsigned int,
@@ -1955,6 +1955,9 @@ static int efx_ef10_ev_process(struct efx_channel *channel, int quota)
        int tx_descs = 0;
        int spent = 0;
 
+       if (quota <= 0)
+               return spent;
+
        read_ptr = channel->eventq_read_ptr;
 
        for (;;) {
@@ -3145,12 +3148,10 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
                table->dev_uc_count = -1;
        } else {
                table->dev_uc_count = 1 + netdev_uc_count(net_dev);
-               memcpy(table->dev_uc_list[0].addr, net_dev->dev_addr,
-                      ETH_ALEN);
+               ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr);
                i = 1;
                netdev_for_each_uc_addr(uc, net_dev) {
-                       memcpy(table->dev_uc_list[i].addr,
-                              uc->addr, ETH_ALEN);
+                       ether_addr_copy(table->dev_uc_list[i].addr, uc->addr);
                        i++;
                }
        }
@@ -3162,8 +3163,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx)
                eth_broadcast_addr(table->dev_mc_list[0].addr);
                i = 1;
                netdev_for_each_mc_addr(mc, net_dev) {
-                       memcpy(table->dev_mc_list[i].addr,
-                              mc->addr, ETH_ALEN);
+                       ether_addr_copy(table->dev_mc_list[i].addr, mc->addr);
                        i++;
                }
        }
index 207ac9a1e3de989d0f5e4d588c27b6035eec31ec..62a55dde61d570ff78604962808cb2eff21ea273 100644 (file)
 #define        ESF_DZ_RX_KER_BUF_ADDR_LBN 0
 #define        ESF_DZ_RX_KER_BUF_ADDR_WIDTH 48
 
-/* RX_USER_DESC */
-#define        ESF_DZ_RX_USR_RESERVED_LBN 62
-#define        ESF_DZ_RX_USR_RESERVED_WIDTH 2
-#define        ESF_DZ_RX_USR_BYTE_CNT_LBN 48
-#define        ESF_DZ_RX_USR_BYTE_CNT_WIDTH 14
-#define        ESF_DZ_RX_USR_BUF_PAGE_SIZE_LBN 44
-#define        ESF_DZ_RX_USR_BUF_PAGE_SIZE_WIDTH 4
-#define        ESE_DZ_USR_BUF_PAGE_SZ_4MB 10
-#define        ESE_DZ_USR_BUF_PAGE_SZ_1MB 8
-#define        ESE_DZ_USR_BUF_PAGE_SZ_64KB 4
-#define        ESE_DZ_USR_BUF_PAGE_SZ_4KB 0
-#define        ESF_DZ_RX_USR_BUF_ID_OFFSET_LBN 0
-#define        ESF_DZ_RX_USR_BUF_ID_OFFSET_WIDTH 44
-#define        ESF_DZ_RX_USR_4KBPS_BUF_ID_LBN 12
-#define        ESF_DZ_RX_USR_4KBPS_BUF_ID_WIDTH 32
-#define        ESF_DZ_RX_USR_64KBPS_BUF_ID_LBN 16
-#define        ESF_DZ_RX_USR_64KBPS_BUF_ID_WIDTH 28
-#define        ESF_DZ_RX_USR_1MBPS_BUF_ID_LBN 20
-#define        ESF_DZ_RX_USR_1MBPS_BUF_ID_WIDTH 24
-#define        ESF_DZ_RX_USR_4MBPS_BUF_ID_LBN 22
-#define        ESF_DZ_RX_USR_4MBPS_BUF_ID_WIDTH 22
-#define        ESF_DZ_RX_USR_4MBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_RX_USR_4MBPS_BYTE_OFFSET_WIDTH 22
-#define        ESF_DZ_RX_USR_1MBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_RX_USR_1MBPS_BYTE_OFFSET_WIDTH 20
-#define        ESF_DZ_RX_USR_64KBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_RX_USR_64KBPS_BYTE_OFFSET_WIDTH 16
-#define        ESF_DZ_RX_USR_4KBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_RX_USR_4KBPS_BYTE_OFFSET_WIDTH 12
-
 /* TX_CSUM_TSTAMP_DESC */
 #define        ESF_DZ_TX_DESC_IS_OPT_LBN 63
 #define        ESF_DZ_TX_DESC_IS_OPT_WIDTH 1
 #define        ESF_DZ_TX_TSO_TCP_SEQNO_LBN 0
 #define        ESF_DZ_TX_TSO_TCP_SEQNO_WIDTH 32
 
-/* TX_USER_DESC */
-#define        ESF_DZ_TX_USR_TYPE_LBN 63
-#define        ESF_DZ_TX_USR_TYPE_WIDTH 1
-#define        ESF_DZ_TX_USR_CONT_LBN 62
-#define        ESF_DZ_TX_USR_CONT_WIDTH 1
-#define        ESF_DZ_TX_USR_BYTE_CNT_LBN 48
-#define        ESF_DZ_TX_USR_BYTE_CNT_WIDTH 14
-#define        ESF_DZ_TX_USR_BUF_PAGE_SIZE_LBN 44
-#define        ESF_DZ_TX_USR_BUF_PAGE_SIZE_WIDTH 4
-#define        ESE_DZ_USR_BUF_PAGE_SZ_4MB 10
-#define        ESE_DZ_USR_BUF_PAGE_SZ_1MB 8
-#define        ESE_DZ_USR_BUF_PAGE_SZ_64KB 4
-#define        ESE_DZ_USR_BUF_PAGE_SZ_4KB 0
-#define        ESF_DZ_TX_USR_BUF_ID_OFFSET_LBN 0
-#define        ESF_DZ_TX_USR_BUF_ID_OFFSET_WIDTH 44
-#define        ESF_DZ_TX_USR_4KBPS_BUF_ID_LBN 12
-#define        ESF_DZ_TX_USR_4KBPS_BUF_ID_WIDTH 32
-#define        ESF_DZ_TX_USR_64KBPS_BUF_ID_LBN 16
-#define        ESF_DZ_TX_USR_64KBPS_BUF_ID_WIDTH 28
-#define        ESF_DZ_TX_USR_1MBPS_BUF_ID_LBN 20
-#define        ESF_DZ_TX_USR_1MBPS_BUF_ID_WIDTH 24
-#define        ESF_DZ_TX_USR_4MBPS_BUF_ID_LBN 22
-#define        ESF_DZ_TX_USR_4MBPS_BUF_ID_WIDTH 22
-#define        ESF_DZ_TX_USR_4MBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_TX_USR_4MBPS_BYTE_OFFSET_WIDTH 22
-#define        ESF_DZ_TX_USR_1MBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_TX_USR_1MBPS_BYTE_OFFSET_WIDTH 20
-#define        ESF_DZ_TX_USR_64KBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_TX_USR_64KBPS_BYTE_OFFSET_WIDTH 16
-#define        ESF_DZ_TX_USR_4KBPS_BYTE_OFFSET_LBN 0
-#define        ESF_DZ_TX_USR_4KBPS_BYTE_OFFSET_WIDTH 12
 /*************************************************************************/
 
 /* TX_DESC_UPD_REG: Transmit descriptor update register.
index 83d4643470213b7f2380b2fcaadb8404f6d08dc4..52589f6a8beb8d787185a708a050b9d1e28460c0 100644 (file)
@@ -503,8 +503,6 @@ static int efx_probe_channel(struct efx_channel *channel)
                        goto fail;
        }
 
-       channel->n_rx_frm_trunc = 0;
-
        return 0;
 
 fail:
@@ -1014,7 +1012,7 @@ static int efx_probe_port(struct efx_nic *efx)
                return rc;
 
        /* Initialise MAC address to permanent address */
-       memcpy(efx->net_dev->dev_addr, efx->net_dev->perm_addr, ETH_ALEN);
+       ether_addr_copy(efx->net_dev->dev_addr, efx->net_dev->perm_addr);
 
        return 0;
 }
@@ -1346,20 +1344,23 @@ static int efx_probe_interrupts(struct efx_nic *efx)
 
                for (i = 0; i < n_channels; i++)
                        xentries[i].entry = i;
-               rc = pci_enable_msix(efx->pci_dev, xentries, n_channels);
-               if (rc > 0) {
+               rc = pci_enable_msix_range(efx->pci_dev,
+                                          xentries, 1, n_channels);
+               if (rc < 0) {
+                       /* Fall back to single channel MSI */
+                       efx->interrupt_mode = EFX_INT_MODE_MSI;
+                       netif_err(efx, drv, efx->net_dev,
+                                 "could not enable MSI-X\n");
+               } else if (rc < n_channels) {
                        netif_err(efx, drv, efx->net_dev,
                                  "WARNING: Insufficient MSI-X vectors"
                                  " available (%d < %u).\n", rc, n_channels);
                        netif_err(efx, drv, efx->net_dev,
                                  "WARNING: Performance may be reduced.\n");
-                       EFX_BUG_ON_PARANOID(rc >= n_channels);
                        n_channels = rc;
-                       rc = pci_enable_msix(efx->pci_dev, xentries,
-                                            n_channels);
                }
 
-               if (rc == 0) {
+               if (rc > 0) {
                        efx->n_channels = n_channels;
                        if (n_channels > extra_channels)
                                n_channels -= extra_channels;
@@ -1375,11 +1376,6 @@ static int efx_probe_interrupts(struct efx_nic *efx)
                        for (i = 0; i < efx->n_channels; i++)
                                efx_get_channel(efx, i)->irq =
                                        xentries[i].vector;
-               } else {
-                       /* Fall back to single channel MSI */
-                       efx->interrupt_mode = EFX_INT_MODE_MSI;
-                       netif_err(efx, drv, efx->net_dev,
-                                 "could not enable MSI-X\n");
                }
        }
 
@@ -2115,7 +2111,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct sockaddr *addr = data;
-       char *new_addr = addr->sa_data;
+       u8 *new_addr = addr->sa_data;
 
        if (!is_valid_ether_addr(new_addr)) {
                netif_err(efx, drv, efx->net_dev,
@@ -2124,7 +2120,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
                return -EADDRNOTAVAIL;
        }
 
-       memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
+       ether_addr_copy(net_dev->dev_addr, new_addr);
        efx_sriov_mac_address_changed(efx);
 
        /* Reconfigure the MAC */
@@ -3273,6 +3269,6 @@ module_exit(efx_exit_module);
 
 MODULE_AUTHOR("Solarflare Communications and "
              "Michael Brown <mbrown@fensystems.co.uk>");
-MODULE_DESCRIPTION("Solarflare Communications network driver");
+MODULE_DESCRIPTION("Solarflare network driver");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, efx_pci_table);
index dbd7b78fe01c597d088d47ee62f566aadd544a41..99032581336f8297e735bfd21a6bb83c57d9ba4e 100644 (file)
@@ -14,7 +14,7 @@
 #include "net_driver.h"
 #include "filter.h"
 
-/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
+/* All controllers use BAR 0 for I/O space and BAR 2(&3) for memory */
 #define EFX_MEM_BAR 2
 
 /* TX */
index 229428915aa8d01dd40968629087ece21498605d..0de8b07c24c2bf39cd62a06021a42c217a3cba4c 100644 (file)
@@ -251,6 +251,9 @@ static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data,
  * @test_index:                Starting index of the test
  * @strings:           Ethtool strings, or %NULL
  * @data:              Ethtool test results, or %NULL
+ *
+ * Fill in a block of loopback self-test entries.  Return new test
+ * index.
  */
 static int efx_fill_loopback_test(struct efx_nic *efx,
                                  struct efx_loopback_self_tests *lb_tests,
@@ -290,6 +293,12 @@ static int efx_fill_loopback_test(struct efx_nic *efx,
  * @tests:             Efx self-test results structure, or %NULL
  * @strings:           Ethtool strings, or %NULL
  * @data:              Ethtool test results, or %NULL
+ *
+ * Get self-test number of strings, strings, and/or test results.
+ * Return number of strings (== number of test results).
+ *
+ * The reason for merging these three functions is to make sure that
+ * they can never be inconsistent.
  */
 static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
                                       struct efx_self_tests *tests,
@@ -444,7 +453,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_self_tests *efx_tests;
-       int already_up;
+       bool already_up;
        int rc = -ENOMEM;
 
        efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL);
@@ -452,8 +461,8 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                goto fail;
 
        if (efx->state != STATE_READY) {
-               rc = -EIO;
-               goto fail1;
+               rc = -EBUSY;
+               goto out;
        }
 
        netif_info(efx, drv, efx->net_dev, "starting %sline testing\n",
@@ -466,7 +475,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                if (rc) {
                        netif_err(efx, drv, efx->net_dev,
                                  "failed opening device.\n");
-                       goto fail1;
+                       goto out;
                }
        }
 
@@ -479,8 +488,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev,
                   rc == 0 ? "passed" : "failed",
                   (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on");
 
-fail1:
-       /* Fill ethtool results structures */
+out:
        efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data);
        kfree(efx_tests);
 fail:
@@ -691,7 +699,6 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
        pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO);
 }
 
-
 static void efx_ethtool_get_wol(struct net_device *net_dev,
                                struct ethtool_wolinfo *wol)
 {
@@ -720,7 +727,7 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
 }
 
 /* MAC address mask including only I/G bit */
-static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
+static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0};
 
 #define IP4_ADDR_FULL_MASK     ((__force __be32)~0)
 #define PORT_FULL_MASK         ((__force __be16)~0)
@@ -780,16 +787,16 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
                rule->flow_type = ETHER_FLOW;
                if (spec.match_flags &
                    (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) {
-                       memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN);
+                       ether_addr_copy(mac_entry->h_dest, spec.loc_mac);
                        if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC)
-                               memset(mac_mask->h_dest, ~0, ETH_ALEN);
+                               eth_broadcast_addr(mac_mask->h_dest);
                        else
-                               memcpy(mac_mask->h_dest, mac_addr_ig_mask,
-                                      ETH_ALEN);
+                               ether_addr_copy(mac_mask->h_dest,
+                                               mac_addr_ig_mask);
                }
                if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) {
-                       memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN);
-                       memset(mac_mask->h_source, ~0, ETH_ALEN);
+                       ether_addr_copy(mac_entry->h_source, spec.rem_mac);
+                       eth_broadcast_addr(mac_mask->h_source);
                }
                if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) {
                        mac_entry->h_proto = spec.ether_type;
@@ -961,13 +968,13 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
                                spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC;
                        else
                                return -EINVAL;
-                       memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN);
+                       ether_addr_copy(spec.loc_mac, mac_entry->h_dest);
                }
                if (!is_zero_ether_addr(mac_mask->h_source)) {
                        if (!is_broadcast_ether_addr(mac_mask->h_source))
                                return -EINVAL;
                        spec.match_flags |= EFX_FILTER_MATCH_REM_MAC;
-                       memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN);
+                       ether_addr_copy(spec.rem_mac, mac_entry->h_source);
                }
                if (mac_mask->h_proto) {
                        if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK)
index 18d6f761f4d06b18cd060e66d8625a4aa06aa6c2..8ec20b713cc610422781facd45c3c1a03c664164 100644 (file)
@@ -422,7 +422,6 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx)
        efx_readd(efx, &reg, FR_AA_WORK_AROUND_BROKEN_PCI_READS);
 }
 
-
 static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
 {
        struct efx_nic *efx = dev_id;
@@ -467,6 +466,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
                efx_schedule_channel_irq(efx_get_channel(efx, 1));
        return IRQ_HANDLED;
 }
+
 /**************************************************************************
  *
  * RSS
@@ -1358,6 +1358,7 @@ static void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
        case 100:   link_speed = 1; break;
        default:    link_speed = 0; break;
        }
+
        /* MAC_LINK_STATUS controls MAC backpressure but doesn't work
         * as advertised.  Disable to ensure packets are not
         * indefinitely held and TX queue can be flushed at any point
@@ -2182,7 +2183,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
        }
 
        /* Read the MAC addresses */
-       memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN);
+       ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]);
 
        netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n",
                  efx->phy_type, efx->mdio.prtad);
@@ -2868,4 +2869,3 @@ const struct efx_nic_type falcon_b0_nic_type = {
        .mcdi_max_ver = -1,
        .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS,
 };
-
index f72489a105cadcf23a7e4d253c3e9a9e2a81d56f..a08761360cdf526caf33051142149c2962a17f6c 100644 (file)
@@ -311,7 +311,6 @@ static inline void efx_farch_push_tx_desc(struct efx_tx_queue *tx_queue,
  */
 void efx_farch_tx_write(struct efx_tx_queue *tx_queue)
 {
-
        struct efx_tx_buffer *buffer;
        efx_qword_t *txd;
        unsigned write_ptr;
@@ -1249,6 +1248,9 @@ int efx_farch_ev_process(struct efx_channel *channel, int budget)
        int tx_packets = 0;
        int spent = 0;
 
+       if (budget <= 0)
+               return spent;
+
        read_ptr = channel->eventq_read_ptr;
 
        for (;;) {
@@ -1609,7 +1611,6 @@ irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-
 /* Setup RSS indirection table.
  * This maps from the hash value of the packet to RXQ
  */
index 3ef298d3c47e3b32078550231fccc46094cbef68..d0ed7f71ea7e25145bb4cf12395154efc587c3a0 100644 (file)
@@ -243,7 +243,7 @@ static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec,
        }
        if (addr != NULL) {
                spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC;
-               memcpy(spec->loc_mac, addr, ETH_ALEN);
+               ether_addr_copy(spec->loc_mac, addr);
        }
        return 0;
 }
index eb59abb57e8506b4fc9605cad9fcb460be0625a3..7bd4b14bf3b32f627457eb1c48f6231922838670 100644 (file)
@@ -1187,6 +1187,9 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
        int rc;
 
        BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0);
+       /* we need __aligned(2) for ether_addr_copy */
+       BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST & 1);
+       BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST & 1);
 
        rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0,
                          outbuf, sizeof(outbuf), &outlen);
@@ -1199,11 +1202,10 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address,
        }
 
        if (mac_address)
-               memcpy(mac_address,
-                      port_num ?
-                      MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
-                      MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0),
-                      ETH_ALEN);
+               ether_addr_copy(mac_address,
+                               port_num ?
+                               MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) :
+                               MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0));
        if (fw_subtype_list) {
                for (i = 0;
                     i < MCDI_VAR_ARRAY_LEN(outlen,
@@ -1532,7 +1534,7 @@ static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type,
        MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type);
        MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE,
                       MC_CMD_FILTER_MODE_SIMPLE);
-       memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN);
+       ether_addr_copy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac);
 
        rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf),
                          outbuf, sizeof(outbuf), &outlen);
index 91d23252f8fae96d4ff4884d60b04a0cd5486750..e5fc4e1574b53f977e8509652aeb67e7404ca757 100644 (file)
@@ -854,8 +854,8 @@ int efx_mcdi_set_mac(struct efx_nic *efx)
 
        BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0);
 
-       memcpy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
-              efx->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR),
+                       efx->net_dev->dev_addr);
 
        MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU,
                        EFX_MAX_FRAME_LEN(efx->net_dev->mtu));
index af2b8c59a903e7cea3011a3a2be29658542d4d4e..8a400a0595eb8c30ec051aa1e06b3f13e6478eea 100644 (file)
@@ -1323,7 +1323,6 @@ static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
        return &rx_queue->buffer[index];
 }
 
-
 /**
  * EFX_MAX_FRAME_LEN - calculate maximum frame length
  *
index 79226b19e3c40d072bf929046bd8b0b219a9ab1a..32d969e857f7befc79bf4a6f18cb153c350b374b 100644 (file)
@@ -530,4 +530,3 @@ void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *rx_nodesc_drops)
        efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP);
        *rx_nodesc_drops -= efx->rx_nodesc_drops_while_down;
 }
-
index eb75fbd11a0115c73195f7d820ed051e3f720d71..6b861e3de4b0d0655879e5bb5740855d6b9c251d 100644 (file)
@@ -223,7 +223,6 @@ struct efx_ptp_timeset {
  * @evt_list: List of MC receive events awaiting packets
  * @evt_free_list: List of free events
  * @evt_lock: Lock for manipulating evt_list and evt_free_list
- * @evt_overflow: Boolean indicating that event list has overflowed
  * @rx_evts: Instantiated events (on evt_list and evt_free_list)
  * @workwq: Work queue for processing pending PTP operations
  * @work: Work task
@@ -275,7 +274,6 @@ struct efx_ptp_data {
        struct list_head evt_list;
        struct list_head evt_free_list;
        spinlock_t evt_lock;
-       bool evt_overflow;
        struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS];
        struct workqueue_struct *workwq;
        struct work_struct work;
@@ -768,37 +766,36 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
                return -EAGAIN;
        }
 
-       /* Convert the NIC time into kernel time. No correction is required-
-        * this time is the output of a firmware process.
-        */
-       mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major,
-                                         ptp->timeset[last_good].minor, 0);
-
-       /* Calculate delay from actual PPS to last_time */
-       delta = ktime_to_timespec(mc_time);
-       delta.tv_nsec +=
-               last_time->ts_real.tv_nsec -
-               (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK);
-
-       /* It is possible that the seconds rolled over between taking
+       /* Calculate delay from last good sync (host time) to last_time.
+        * It is possible that the seconds rolled over between taking
         * the start reading and the last value written by the host.  The
         * timescales are such that a gap of more than one second is never
-        * expected.
+        * expected.  delta is *not* normalised.
         */
        start_sec = ptp->timeset[last_good].host_start >> MC_NANOSECOND_BITS;
        last_sec = last_time->ts_real.tv_sec & MC_SECOND_MASK;
-       if (start_sec != last_sec) {
-               if (((start_sec + 1) & MC_SECOND_MASK) != last_sec) {
-                       netif_warn(efx, hw, efx->net_dev,
-                                  "PTP bad synchronisation seconds\n");
-                       return -EAGAIN;
-               } else {
-                       delta.tv_sec = 1;
-               }
-       } else {
-               delta.tv_sec = 0;
+       if (start_sec != last_sec &&
+           ((start_sec + 1) & MC_SECOND_MASK) != last_sec) {
+               netif_warn(efx, hw, efx->net_dev,
+                          "PTP bad synchronisation seconds\n");
+               return -EAGAIN;
        }
+       delta.tv_sec = (last_sec - start_sec) & 1;
+       delta.tv_nsec =
+               last_time->ts_real.tv_nsec -
+               (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK);
+
+       /* Convert the NIC time at last good sync into kernel time.
+        * No correction is required - this time is the output of a
+        * firmware process.
+        */
+       mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major,
+                                         ptp->timeset[last_good].minor, 0);
+
+       /* Calculate delay from NIC top of second to last_time */
+       delta.tv_nsec += ktime_to_timespec(mc_time).tv_nsec;
 
+       /* Set PPS timestamp to match NIC top of second */
        ptp->host_time_pps = *last_time;
        pps_sub_ts(&ptp->host_time_pps, delta);
 
@@ -941,11 +938,6 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx)
                        }
                }
        }
-       /* If the event overflow flag is set and the event list is now empty
-        * clear the flag to re-enable the overflow warning message.
-        */
-       if (ptp->evt_overflow && list_empty(&ptp->evt_list))
-               ptp->evt_overflow = false;
        spin_unlock_bh(&ptp->evt_lock);
 }
 
@@ -989,11 +981,6 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx,
                        break;
                }
        }
-       /* If the event overflow flag is set and the event list is now empty
-        * clear the flag to re-enable the overflow warning message.
-        */
-       if (ptp->evt_overflow && list_empty(&ptp->evt_list))
-               ptp->evt_overflow = false;
        spin_unlock_bh(&ptp->evt_lock);
 
        return rc;
@@ -1147,7 +1134,6 @@ static int efx_ptp_stop(struct efx_nic *efx)
        list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) {
                list_move(cursor, &efx->ptp_data->evt_free_list);
        }
-       ptp->evt_overflow = false;
        spin_unlock_bh(&efx->ptp_data->evt_lock);
 
        return rc;
@@ -1208,6 +1194,7 @@ static const struct ptp_clock_info efx_phc_clock_info = {
        .n_alarm        = 0,
        .n_ext_ts       = 0,
        .n_per_out      = 0,
+       .n_pins         = 0,
        .pps            = 1,
        .adjfreq        = efx_phc_adjfreq,
        .adjtime        = efx_phc_adjtime,
@@ -1253,7 +1240,6 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
        spin_lock_init(&ptp->evt_lock);
        for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++)
                list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list);
-       ptp->evt_overflow = false;
 
        /* Get the NIC PTP attributes and set up time conversions */
        rc = efx_ptp_get_attributes(efx);
@@ -1380,6 +1366,7 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
        struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb;
        u8 *match_data_012, *match_data_345;
        unsigned int version;
+       u8 *data;
 
        match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS);
 
@@ -1388,7 +1375,8 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
                if (!pskb_may_pull(skb, PTP_V1_MIN_LENGTH)) {
                        return false;
                }
-               version = ntohs(*(__be16 *)&skb->data[PTP_V1_VERSION_OFFSET]);
+               data = skb->data;
+               version = ntohs(*(__be16 *)&data[PTP_V1_VERSION_OFFSET]);
                if (version != PTP_VERSION_V1) {
                        return false;
                }
@@ -1396,13 +1384,14 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
                /* PTP V1 uses all six bytes of the UUID to match the packet
                 * to the timestamp
                 */
-               match_data_012 = skb->data + PTP_V1_UUID_OFFSET;
-               match_data_345 = skb->data + PTP_V1_UUID_OFFSET + 3;
+               match_data_012 = data + PTP_V1_UUID_OFFSET;
+               match_data_345 = data + PTP_V1_UUID_OFFSET + 3;
        } else {
                if (!pskb_may_pull(skb, PTP_V2_MIN_LENGTH)) {
                        return false;
                }
-               version = skb->data[PTP_V2_VERSION_OFFSET];
+               data = skb->data;
+               version = data[PTP_V2_VERSION_OFFSET];
                if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) {
                        return false;
                }
@@ -1414,17 +1403,17 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
                 * enhanced mode fixes this issue and uses bytes 0-2
                 * and byte 5-7 of the UUID.
                 */
-               match_data_345 = skb->data + PTP_V2_UUID_OFFSET + 5;
+               match_data_345 = data + PTP_V2_UUID_OFFSET + 5;
                if (ptp->mode == MC_CMD_PTP_MODE_V2) {
-                       match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 2;
+                       match_data_012 = data + PTP_V2_UUID_OFFSET + 2;
                } else {
-                       match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 0;
+                       match_data_012 = data + PTP_V2_UUID_OFFSET + 0;
                        BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2_ENHANCED);
                }
        }
 
        /* Does this packet require timestamping? */
-       if (ntohs(*(__be16 *)&skb->data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) {
+       if (ntohs(*(__be16 *)&data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) {
                match->state = PTP_PACKET_STATE_UNMATCHED;
 
                /* We expect the sequence number to be in the same position in
@@ -1440,8 +1429,8 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb)
                                   (match_data_345[0] << 24));
                match->words[1] = (match_data_345[1]         |
                                   (match_data_345[2] << 8)  |
-                                  (skb->data[PTP_V1_SEQUENCE_OFFSET +
-                                             PTP_V1_SEQUENCE_LENGTH - 1] <<
+                                  (data[PTP_V1_SEQUENCE_OFFSET +
+                                        PTP_V1_SEQUENCE_LENGTH - 1] <<
                                    16));
        } else {
                match->state = PTP_PACKET_STATE_MATCH_UNWANTED;
@@ -1635,13 +1624,9 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp)
                list_add_tail(&evt->link, &ptp->evt_list);
 
                queue_work(ptp->workwq, &ptp->work);
-       } else if (!ptp->evt_overflow) {
-               /* Log a warning message and set the event overflow flag.
-                * The message won't be logged again until the event queue
-                * becomes empty.
-                */
+       } else if (net_ratelimit()) {
+               /* Log a rate-limited warning message. */
                netif_err(efx, rx_err, efx->net_dev, "PTP event queue overflow\n");
-               ptp->evt_overflow = true;
        }
        spin_unlock_bh(&ptp->evt_lock);
 }
@@ -1668,6 +1653,13 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev)
        struct efx_ptp_data *ptp = efx->ptp_data;
        int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE);
 
+       if (!ptp) {
+               if (net_ratelimit())
+                       netif_warn(efx, drv, efx->net_dev,
+                                  "Received PTP event but PTP not set up\n");
+               return;
+       }
+
        if (!ptp->enabled)
                return;
 
index 26641817a9c73ab6634057faaa93cba9f91ece0d..0fc5baef45b17377faeef424dab5217bb41a87a0 100644 (file)
@@ -50,7 +50,7 @@ struct efx_loopback_payload {
 } __packed;
 
 /* Loopback test source MAC address */
-static const unsigned char payload_source[ETH_ALEN] = {
+static const u8 payload_source[ETH_ALEN] __aligned(2) = {
        0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
 };
 
@@ -366,8 +366,8 @@ static void efx_iterate_state(struct efx_nic *efx)
        struct efx_loopback_payload *payload = &state->payload;
 
        /* Initialise the layerII header */
-       memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN);
-       memcpy(&payload->header.h_source, &payload_source, ETH_ALEN);
+       ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr);
+       ether_addr_copy((u8 *)&payload->header.h_source, payload_source);
        payload->header.h_proto = htons(ETH_P_IP);
 
        /* saddr set later and used as incrementing count */
index 0c38f926871ebbc99593cf71d263ae54cf83636c..9a9205e778964186d09094128a933179926f8006 100644 (file)
@@ -1095,7 +1095,7 @@ static void efx_sriov_peer_work(struct work_struct *data)
 
        /* Fill the remaining addresses */
        list_for_each_entry(local_addr, &efx->local_addr_list, link) {
-               memcpy(peer->mac_addr, local_addr->addr, ETH_ALEN);
+               ether_addr_copy(peer->mac_addr, local_addr->addr);
                peer->tci = 0;
                ++peer;
                ++peer_count;
@@ -1303,8 +1303,7 @@ int efx_sriov_init(struct efx_nic *efx)
                goto fail_vfs;
 
        rtnl_lock();
-       memcpy(vfdi_status->peers[0].mac_addr,
-              net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(vfdi_status->peers[0].mac_addr, net_dev->dev_addr);
        efx->vf_init_count = efx->vf_count;
        rtnl_unlock();
 
@@ -1452,8 +1451,8 @@ void efx_sriov_mac_address_changed(struct efx_nic *efx)
 
        if (!efx->vf_init_count)
                return;
-       memcpy(vfdi_status->peers[0].mac_addr,
-              efx->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(vfdi_status->peers[0].mac_addr,
+                       efx->net_dev->dev_addr);
        queue_work(vfdi_workqueue, &efx->peer_work);
 }
 
@@ -1570,7 +1569,7 @@ int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
        vf = efx->vf + vf_i;
 
        mutex_lock(&vf->status_lock);
-       memcpy(vf->addr.mac_addr, mac, ETH_ALEN);
+       ether_addr_copy(vf->addr.mac_addr, mac);
        __efx_sriov_update_vf_addr(vf);
        mutex_unlock(&vf->status_lock);
 
@@ -1633,7 +1632,7 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
        vf = efx->vf + vf_i;
 
        ivi->vf = vf_i;
-       memcpy(ivi->mac, vf->addr.mac_addr, ETH_ALEN);
+       ether_addr_copy(ivi->mac, vf->addr.mac_addr);
        ivi->tx_rate = 0;
        tci = ntohs(vf->addr.tci);
        ivi->vlan = tci & VLAN_VID_MASK;
index c49d1fb169652199ebccc42db45b0b73323d6f28..fa9475300411507e447fd51e21dfbd4c5f600aa3 100644 (file)
@@ -429,7 +429,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
        }
 
        /* Transfer ownership of the skb to the final buffer */
+#ifdef EFX_USE_PIO
 finish_packet:
+#endif
        buffer->skb = skb;
        buffer->flags = EFX_TX_BUF_SKB | dma_flags;
 
@@ -785,15 +787,6 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
  * Requires TX checksum offload support.
  */
 
-/* Number of bytes inserted at the start of a TSO header buffer,
- * similar to NET_IP_ALIGN.
- */
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
-#define TSOH_OFFSET    0
-#else
-#define TSOH_OFFSET    NET_IP_ALIGN
-#endif
-
 #define PTR_DIFF(p1, p2)  ((u8 *)(p1) - (u8 *)(p2))
 
 /**
@@ -880,13 +873,13 @@ static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue,
        EFX_BUG_ON_PARANOID(buffer->flags);
        EFX_BUG_ON_PARANOID(buffer->unmap_len);
 
-       if (likely(len <= TSOH_STD_SIZE - TSOH_OFFSET)) {
+       if (likely(len <= TSOH_STD_SIZE - NET_IP_ALIGN)) {
                unsigned index =
                        (tx_queue->insert_count & tx_queue->ptr_mask) / 2;
                struct efx_buffer *page_buf =
                        &tx_queue->tsoh_page[index / TSOH_PER_PAGE];
                unsigned offset =
-                       TSOH_STD_SIZE * (index % TSOH_PER_PAGE) + TSOH_OFFSET;
+                       TSOH_STD_SIZE * (index % TSOH_PER_PAGE) + NET_IP_ALIGN;
 
                if (unlikely(!page_buf->addr) &&
                    efx_nic_alloc_buffer(tx_queue->efx, page_buf, PAGE_SIZE,
@@ -899,10 +892,10 @@ static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue,
        } else {
                tx_queue->tso_long_headers++;
 
-               buffer->heap_buf = kmalloc(TSOH_OFFSET + len, GFP_ATOMIC);
+               buffer->heap_buf = kmalloc(NET_IP_ALIGN + len, GFP_ATOMIC);
                if (unlikely(!buffer->heap_buf))
                        return NULL;
-               result = (u8 *)buffer->heap_buf + TSOH_OFFSET;
+               result = (u8 *)buffer->heap_buf + NET_IP_ALIGN;
                buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_HEAP;
        }
 
@@ -1009,7 +1002,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
 static int tso_start(struct tso_state *st, struct efx_nic *efx,
                     const struct sk_buff *skb)
 {
-       bool use_options = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
+       bool use_opt_desc = efx_nic_rev(efx) >= EFX_REV_HUNT_A0;
        struct device *dma_dev = &efx->pci_dev->dev;
        unsigned int header_len, in_len;
        dma_addr_t dma_addr;
@@ -1035,7 +1028,7 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx,
 
        st->out_len = skb->len - header_len;
 
-       if (!use_options) {
+       if (!use_opt_desc) {
                st->header_unmap_len = 0;
 
                if (likely(in_len == 0)) {
index 5eb933c97bbacf26123d1857949515e6b04adbee..7daa7d433099d0d739bf28db8e6238efa2bd4c31 100644 (file)
@@ -987,7 +987,7 @@ out_unlock:
        spin_unlock(&priv->lock);
 
 out:
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        return NETDEV_TX_OK;
 }
index ff57a46388eefed67c81b70dc67e8ddd6a698826..6072f093e6b46618c0724f6a7ed1436d7f3c50f8 100644 (file)
@@ -1614,7 +1614,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
                skb->data, skb->len, PCI_DMA_TODEVICE);
        if (unlikely(pci_dma_mapping_error(sis_priv->pci_dev,
                sis_priv->tx_ring[entry].bufptr))) {
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        sis_priv->tx_skbuff[entry] = NULL;
                        net_dev->stats.tx_dropped++;
                        spin_unlock_irqrestore(&sis_priv->lock, flags);
index c50fb08c990522d04a4cb819bdfa46cd1205b7fa..66b05e62f70a8bf8b7652b296bce1ef57d5b8699 100644 (file)
@@ -551,7 +551,7 @@ static int smc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dev->stats.tx_errors++;
                dev->stats.tx_dropped++;
                spin_unlock_irqrestore(&lp->lock, flags);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index 839c0e6cca01a9ac24c7c52ed535b489a0551ea7..d1b4dca53a9d10be97f05e2e09dd08418598bf05 100644 (file)
@@ -621,7 +621,7 @@ static void smc_hardware_send_pkt(unsigned long data)
 done:  if (!THROTTLE_TX_PKTS)
                netif_wake_queue(dev);
 
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 }
 
 /*
@@ -657,7 +657,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netdev_warn(dev, "Far too big packet error.\n");
                dev->stats.tx_errors++;
                dev->stats.tx_dropped++;
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index 6382b7c416f4a4e2e6a7769e2846f19c84565251..a0fc151da40db13c20681e04c07d5e923566a14b 100644 (file)
@@ -439,7 +439,8 @@ static int smsc911x_request_resources(struct platform_device *pdev)
        /* Request clock */
        pdata->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(pdata->clk))
-               netdev_warn(ndev, "couldn't get clock %li\n", PTR_ERR(pdata->clk));
+               dev_dbg(&pdev->dev, "couldn't get clock %li\n",
+                       PTR_ERR(pdata->clk));
 
        return ret;
 }
@@ -1672,7 +1673,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
        freespace -= (skb->len + 32);
        skb_tx_timestamp(skb);
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
 
        if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30))
                smsc911x_tx_update_txcounters(dev);
@@ -2379,8 +2380,6 @@ static int smsc911x_drv_probe(struct platform_device *pdev)
        int res_size, irq_flags;
        int retval;
 
-       pr_info("Driver version %s\n", SMSC_DRV_VERSION);
-
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                           "smsc911x-memory");
        if (!res)
index e2f202e3932f518c78bc2c2febbe7efd32a39278..2d09c116cbc8c57b9ded844082dc2693d27a2402 100644 (file)
@@ -26,6 +26,16 @@ config STMMAC_PLATFORM
 
          If unsure, say N.
 
+config DWMAC_SOCFPGA
+       bool "SOCFPGA dwmac support"
+       depends on STMMAC_PLATFORM && MFD_SYSCON && (ARCH_SOCFPGA || COMPILE_TEST)
+       help
+         Support for ethernet controller on Altera SOCFPGA
+
+         This selects the Altera SOCFPGA SoC glue layer support
+         for the stmmac device driver. This driver is used for
+         arria5 and cyclone5 FPGA SoCs.
+
 config DWMAC_SUNXI
        bool "Allwinner GMAC support"
        depends on STMMAC_PLATFORM && ARCH_SUNXI
@@ -37,6 +47,17 @@ config DWMAC_SUNXI
          stmmac device driver. This driver is used for A20/A31
          GMAC    ethernet controller.
 
+config DWMAC_STI
+       bool "STi GMAC support"
+       depends on STMMAC_PLATFORM && ARCH_STI
+       default y
+       ---help---
+         Support for ethernet controller on STi SOCs.
+
+         This selects STi SoC glue layer support for the stmmac
+         device driver. This driver is used on for the STi series
+         SOCs GMAC ethernet controller.
+
 config STMMAC_PCI
        bool "STMMAC PCI bus support"
        depends on STMMAC_ETH && PCI
index ecadecea79b220c6c3e5d86f031d42c34df54e4d..18695ebef7e43cb636e60640fbd52e4835e36ede 100644 (file)
@@ -2,6 +2,8 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o
 stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
 stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
 stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
+stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o
+stmmac-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
 stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
              chain_mode.o dwmac_lib.o dwmac1000_core.o  dwmac1000_dma.o \
              dwmac100_core.o dwmac100_dma.o enh_desc.o  norm_desc.o \
index 72d282bf33a51e8e2cb0036cac6fd03fe19acdf0..c553f6b5a9131f0af16230f59ccd0557fe1116a5 100644 (file)
@@ -151,7 +151,7 @@ static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
                                          sizeof(struct dma_desc)));
 }
 
-const struct stmmac_chain_mode_ops chain_mode_ops = {
+const struct stmmac_mode_ops chain_mode_ops = {
        .init = stmmac_init_dma_chain,
        .is_jumbo_frm = stmmac_is_jumbo_frm,
        .jumbo_frm = stmmac_jumbo_frm,
index 7834a39939464a844fd4fd8bf8ecbc2f9f8847c0..74610f3aca9e5bc8670c49f4a25901c4b4575136 100644 (file)
@@ -419,20 +419,13 @@ struct mii_regs {
        unsigned int data;      /* MII Data */
 };
 
-struct stmmac_ring_mode_ops {
-       unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
-       unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
-       void (*refill_desc3) (void *priv, struct dma_desc *p);
-       void (*init_desc3) (struct dma_desc *p);
-       void (*clean_desc3) (void *priv, struct dma_desc *p);
-       int (*set_16kib_bfsize) (int mtu);
-};
-
-struct stmmac_chain_mode_ops {
+struct stmmac_mode_ops {
        void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
                      unsigned int extend_desc);
        unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
        unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
+       int (*set_16kib_bfsize)(int mtu);
+       void (*init_desc3)(struct dma_desc *p);
        void (*refill_desc3) (void *priv, struct dma_desc *p);
        void (*clean_desc3) (void *priv, struct dma_desc *p);
 };
@@ -441,8 +434,7 @@ struct mac_device_info {
        const struct stmmac_ops *mac;
        const struct stmmac_desc_ops *desc;
        const struct stmmac_dma_ops *dma;
-       const struct stmmac_ring_mode_ops *ring;
-       const struct stmmac_chain_mode_ops *chain;
+       const struct stmmac_mode_ops *mode;
        const struct stmmac_hwtimestamp *ptp;
        struct mii_regs mii;    /* MII register Addresses */
        struct mac_link link;
@@ -460,7 +452,7 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
 void stmmac_set_mac(void __iomem *ioaddr, bool enable);
 
 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
-extern const struct stmmac_ring_mode_ops ring_mode_ops;
-extern const struct stmmac_chain_mode_ops chain_mode_ops;
+extern const struct stmmac_mode_ops ring_mode_ops;
+extern const struct stmmac_mode_ops chain_mode_ops;
 
 #endif /* __COMMON_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
new file mode 100644 (file)
index 0000000..fd8a217
--- /dev/null
@@ -0,0 +1,130 @@
+/* Copyright Altera Corporation (C) 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Adopted from dwmac-sti.c
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+#include <linux/stmmac.h>
+
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII 0x2
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
+#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
+
+struct socfpga_dwmac {
+       int     interface;
+       u32     reg_offset;
+       u32     reg_shift;
+       struct  device *dev;
+       struct regmap *sys_mgr_base_addr;
+};
+
+static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct regmap *sys_mgr_base_addr;
+       u32 reg_offset, reg_shift;
+       int ret;
+
+       dwmac->interface = of_get_phy_mode(np);
+
+       sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
+       if (IS_ERR(sys_mgr_base_addr)) {
+               dev_info(dev, "No sysmgr-syscon node found\n");
+               return PTR_ERR(sys_mgr_base_addr);
+       }
+
+       ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 1, &reg_offset);
+       if (ret) {
+               dev_info(dev, "Could not read reg_offset from sysmgr-syscon!\n");
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32_index(np, "altr,sysmgr-syscon", 2, &reg_shift);
+       if (ret) {
+               dev_info(dev, "Could not read reg_shift from sysmgr-syscon!\n");
+               return -EINVAL;
+       }
+
+       dwmac->reg_offset = reg_offset;
+       dwmac->reg_shift = reg_shift;
+       dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
+       dwmac->dev = dev;
+
+       return 0;
+}
+
+static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
+{
+       struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr;
+       int phymode = dwmac->interface;
+       u32 reg_offset = dwmac->reg_offset;
+       u32 reg_shift = dwmac->reg_shift;
+       u32 ctrl, val;
+
+       switch (phymode) {
+       case PHY_INTERFACE_MODE_RGMII:
+               val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
+               break;
+       case PHY_INTERFACE_MODE_MII:
+       case PHY_INTERFACE_MODE_GMII:
+               val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+               break;
+       default:
+               dev_err(dwmac->dev, "bad phy mode %d\n", phymode);
+               return -EINVAL;
+       }
+
+       regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
+       ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
+       ctrl |= val << reg_shift;
+
+       regmap_write(sys_mgr_base_addr, reg_offset, ctrl);
+       return 0;
+}
+
+static void *socfpga_dwmac_probe(struct platform_device *pdev)
+{
+       struct device           *dev = &pdev->dev;
+       int                     ret;
+       struct socfpga_dwmac    *dwmac;
+
+       dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
+       if (!dwmac)
+               return ERR_PTR(-ENOMEM);
+
+       ret = socfpga_dwmac_parse_data(dwmac, dev);
+       if (ret) {
+               dev_err(dev, "Unable to parse OF data\n");
+               return ERR_PTR(ret);
+       }
+
+       ret = socfpga_dwmac_setup(dwmac);
+       if (ret) {
+               dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
+               return ERR_PTR(ret);
+       }
+
+       return dwmac;
+}
+
+const struct stmmac_of_data socfpga_gmac_data = {
+       .setup = socfpga_dwmac_probe,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
new file mode 100644 (file)
index 0000000..552bbc1
--- /dev/null
@@ -0,0 +1,330 @@
+/**
+ * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
+ *
+ * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
+ * Author: Srinivas Kandagatla <srinivas.kandagatla@st.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/slab.h>
+#include <linux/platform_device.h>
+#include <linux/stmmac.h>
+#include <linux/phy.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+
+/**
+ *                     STi GMAC glue logic.
+ *                     --------------------
+ *
+ *              _
+ *             |  \
+ *     --------|0  \ ETH_SEL_INTERNAL_NOTEXT_PHYCLK
+ * phyclk      |    |___________________________________________
+ *             |    |  |                       (phyclk-in)
+ *     --------|1  /   |
+ * int-clk     |_ /    |
+ *                     |        _
+ *                     |       |  \
+ *                     |_______|1  \ ETH_SEL_TX_RETIME_CLK
+ *                             |    |___________________________
+ *                             |    |          (tx-retime-clk)
+ *                      _______|0  /
+ *                     |       |_ /
+ *              _      |
+ *             |  \    |
+ *     --------|0  \   |
+ * clk_125     |    |__|
+ *             |    |  ETH_SEL_TXCLK_NOT_CLK125
+ *     --------|1  /
+ * txclk       |_ /
+ *
+ *
+ * ETH_SEL_INTERNAL_NOTEXT_PHYCLK is valid only for RMII where PHY can
+ * generate 50MHz clock or MAC can generate it.
+ * This bit is configured by "st,ext-phyclk" property.
+ *
+ * ETH_SEL_TXCLK_NOT_CLK125 is only valid for gigabit modes, where the 125Mhz
+ * clock either comes from clk-125 pin or txclk pin. This configuration is
+ * totally driven by the board wiring. This bit is configured by
+ * "st,tx-retime-src" property.
+ *
+ * TXCLK configuration is different for different phy interface modes
+ * and changes according to link speed in modes like RGMII.
+ *
+ * Below table summarizes the clock requirement and clock sources for
+ * supported phy interface modes with link speeds.
+ * ________________________________________________
+ *|  PHY_MODE  | 1000 Mbit Link | 100 Mbit Link   |
+ * ------------------------------------------------
+ *|    MII     |       n/a      |      25Mhz      |
+ *|            |                |      txclk      |
+ * ------------------------------------------------
+ *|    GMII    |     125Mhz     |      25Mhz      |
+ *|            |  clk-125/txclk |      txclk      |
+ * ------------------------------------------------
+ *|    RGMII   |     125Mhz     |      25Mhz      |
+ *|            |  clk-125/txclk |      clkgen     |
+ * ------------------------------------------------
+ *|    RMII    |       n/a      |      25Mhz      |
+ *|            |                |clkgen/phyclk-in |
+ * ------------------------------------------------
+ *
+ * TX lines are always retimed with a clk, which can vary depending
+ * on the board configuration. Below is the table of these bits
+ * in eth configuration register depending on source of retime clk.
+ *
+ *---------------------------------------------------------------
+ * src  | tx_rt_clk    | int_not_ext_phyclk    | txclk_n_clk125|
+ *---------------------------------------------------------------
+ * txclk |     0       |       n/a             |       1       |
+ *---------------------------------------------------------------
+ * ck_125|     0       |       n/a             |       0       |
+ *---------------------------------------------------------------
+ * phyclk|     1       |       0               |       n/a     |
+ *---------------------------------------------------------------
+ * clkgen|     1       |       1               |       n/a     |
+ *---------------------------------------------------------------
+ */
+
+ /* Register definition */
+
+ /* 3 bits [8:6]
+  *  [6:6]      ETH_SEL_TXCLK_NOT_CLK125
+  *  [7:7]      ETH_SEL_INTERNAL_NOTEXT_PHYCLK
+  *  [8:8]      ETH_SEL_TX_RETIME_CLK
+  *
+  */
+
+#define TX_RETIME_SRC_MASK             GENMASK(8, 6)
+#define ETH_SEL_TX_RETIME_CLK          BIT(8)
+#define ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7)
+#define ETH_SEL_TXCLK_NOT_CLK125       BIT(6)
+
+#define ENMII_MASK                     GENMASK(5, 5)
+#define ENMII                          BIT(5)
+
+/**
+ * 3 bits [4:2]
+ *     000-GMII/MII
+ *     001-RGMII
+ *     010-SGMII
+ *     100-RMII
+*/
+#define MII_PHY_SEL_MASK               GENMASK(4, 2)
+#define ETH_PHY_SEL_RMII               BIT(4)
+#define ETH_PHY_SEL_SGMII              BIT(3)
+#define ETH_PHY_SEL_RGMII              BIT(2)
+#define ETH_PHY_SEL_GMII               0x0
+#define ETH_PHY_SEL_MII                        0x0
+
+#define IS_PHY_IF_MODE_RGMII(iface)    (iface == PHY_INTERFACE_MODE_RGMII || \
+                       iface == PHY_INTERFACE_MODE_RGMII_ID || \
+                       iface == PHY_INTERFACE_MODE_RGMII_RXID || \
+                       iface == PHY_INTERFACE_MODE_RGMII_TXID)
+
+#define IS_PHY_IF_MODE_GBIT(iface)     (IS_PHY_IF_MODE_RGMII(iface) || \
+                       iface == PHY_INTERFACE_MODE_GMII)
+
+struct sti_dwmac {
+       int interface;
+       bool ext_phyclk;
+       bool is_tx_retime_src_clk_125;
+       struct clk *clk;
+       int reg;
+       struct device *dev;
+       struct regmap *regmap;
+};
+
+static u32 phy_intf_sels[] = {
+       [PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII,
+       [PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII,
+       [PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII,
+       [PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII,
+       [PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII,
+       [PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII,
+};
+
+enum {
+       TX_RETIME_SRC_NA = 0,
+       TX_RETIME_SRC_TXCLK = 1,
+       TX_RETIME_SRC_CLK_125,
+       TX_RETIME_SRC_PHYCLK,
+       TX_RETIME_SRC_CLKGEN,
+};
+
+static const char *const tx_retime_srcs[] = {
+       [TX_RETIME_SRC_NA] = "",
+       [TX_RETIME_SRC_TXCLK] = "txclk",
+       [TX_RETIME_SRC_CLK_125] = "clk_125",
+       [TX_RETIME_SRC_PHYCLK] = "phyclk",
+       [TX_RETIME_SRC_CLKGEN] = "clkgen",
+};
+
+static u32 tx_retime_val[] = {
+       [TX_RETIME_SRC_TXCLK] = ETH_SEL_TXCLK_NOT_CLK125,
+       [TX_RETIME_SRC_CLK_125] = 0x0,
+       [TX_RETIME_SRC_PHYCLK] = ETH_SEL_TX_RETIME_CLK,
+       [TX_RETIME_SRC_CLKGEN] = ETH_SEL_TX_RETIME_CLK |
+           ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
+};
+
+static void setup_retime_src(struct sti_dwmac *dwmac, u32 spd)
+{
+       u32 src = 0, freq = 0;
+
+       if (spd == SPEED_100) {
+               if (dwmac->interface == PHY_INTERFACE_MODE_MII ||
+                   dwmac->interface == PHY_INTERFACE_MODE_GMII) {
+                       src = TX_RETIME_SRC_TXCLK;
+               } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
+                       if (dwmac->ext_phyclk) {
+                               src = TX_RETIME_SRC_PHYCLK;
+                       } else {
+                               src = TX_RETIME_SRC_CLKGEN;
+                               freq = 50000000;
+                       }
+
+               } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) {
+                       src = TX_RETIME_SRC_CLKGEN;
+                       freq = 25000000;
+               }
+
+               if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk)
+                       clk_set_rate(dwmac->clk, freq);
+
+       } else if (spd == SPEED_1000) {
+               if (dwmac->is_tx_retime_src_clk_125)
+                       src = TX_RETIME_SRC_CLK_125;
+               else
+                       src = TX_RETIME_SRC_TXCLK;
+       }
+
+       regmap_update_bits(dwmac->regmap, dwmac->reg,
+                          TX_RETIME_SRC_MASK, tx_retime_val[src]);
+}
+
+static void sti_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+       struct sti_dwmac *dwmac = priv;
+
+       if (dwmac->clk)
+               clk_disable_unprepare(dwmac->clk);
+}
+
+static void sti_fix_mac_speed(void *priv, unsigned int spd)
+{
+       struct sti_dwmac *dwmac = priv;
+
+       setup_retime_src(dwmac, spd);
+
+       return;
+}
+
+static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
+                               struct platform_device *pdev)
+{
+       struct resource *res;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct regmap *regmap;
+       int err;
+
+       if (!np)
+               return -EINVAL;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf");
+       if (!res)
+               return -ENODATA;
+
+       regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon");
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       dwmac->dev = dev;
+       dwmac->interface = of_get_phy_mode(np);
+       dwmac->regmap = regmap;
+       dwmac->reg = res->start;
+       dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk");
+       dwmac->is_tx_retime_src_clk_125 = false;
+
+       if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
+               const char *rs;
+
+               err = of_property_read_string(np, "st,tx-retime-src", &rs);
+               if (err < 0) {
+                       dev_err(dev, "st,tx-retime-src not specified\n");
+                       return err;
+               }
+
+               if (!strcasecmp(rs, "clk_125"))
+                       dwmac->is_tx_retime_src_clk_125 = true;
+       }
+
+       dwmac->clk = devm_clk_get(dev, "sti-ethclk");
+
+       if (IS_ERR(dwmac->clk))
+               dwmac->clk = NULL;
+
+       return 0;
+}
+
+static int sti_dwmac_init(struct platform_device *pdev, void *priv)
+{
+       struct sti_dwmac *dwmac = priv;
+       struct regmap *regmap = dwmac->regmap;
+       int iface = dwmac->interface;
+       u32 reg = dwmac->reg;
+       u32 val, spd;
+
+       if (dwmac->clk)
+               clk_prepare_enable(dwmac->clk);
+
+       regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]);
+
+       val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
+       regmap_update_bits(regmap, reg, ENMII_MASK, val);
+
+       if (IS_PHY_IF_MODE_GBIT(iface))
+               spd = SPEED_1000;
+       else
+               spd = SPEED_100;
+
+       setup_retime_src(dwmac, spd);
+
+       return 0;
+}
+
+static void *sti_dwmac_setup(struct platform_device *pdev)
+{
+       struct sti_dwmac *dwmac;
+       int ret;
+
+       dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
+       if (!dwmac)
+               return ERR_PTR(-ENOMEM);
+
+       ret = sti_dwmac_parse_data(dwmac, pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to parse OF data\n");
+               return ERR_PTR(ret);
+       }
+
+       return dwmac;
+}
+
+const struct stmmac_of_data sti_gmac_data = {
+       .fix_mac_speed = sti_fix_mac_speed,
+       .setup = sti_dwmac_setup,
+       .init = sti_dwmac_init,
+       .exit = sti_dwmac_exit,
+};
index a96c7c2f5f3f220b32df9c0ebad2b197e7ecd45a..650a4be6bce5243e046fcd226719e669f66444e8 100644 (file)
@@ -100,10 +100,9 @@ static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
 {
        struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
 
-       if (unlikely(priv->plat->has_gmac))
-               /* Fill DES3 in case of RING mode */
-               if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
-                       p->des3 = p->des2 + BUF_SIZE_8KiB;
+       /* Fill DES3 in case of RING mode */
+       if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
+               p->des3 = p->des2 + BUF_SIZE_8KiB;
 }
 
 /* In ring mode we need to fill the desc3 because it is used as buffer */
@@ -126,7 +125,7 @@ static int stmmac_set_16kib_bfsize(int mtu)
        return ret;
 }
 
-const struct stmmac_ring_mode_ops ring_mode_ops = {
+const struct stmmac_mode_ops ring_mode_ops = {
        .is_jumbo_frm = stmmac_is_jumbo_frm,
        .jumbo_frm = stmmac_jumbo_frm,
        .refill_desc3 = stmmac_refill_desc3,
index d9af26ed58ee7d3c231c64b110924420c41b765e..ca01035634a76fbc88414f6550849cfa1c772403 100644 (file)
@@ -133,6 +133,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv);
 #ifdef CONFIG_DWMAC_SUNXI
 extern const struct stmmac_of_data sun7i_gmac_data;
 #endif
+#ifdef CONFIG_DWMAC_STI
+extern const struct stmmac_of_data sti_gmac_data;
+#endif
+#ifdef CONFIG_DWMAC_SOCFPGA
+extern const struct stmmac_of_data socfpga_gmac_data;
+#endif
 extern struct platform_driver stmmac_pltfr_driver;
 static inline int stmmac_register_platform(void)
 {
index a2e7d2c96e3678c309377d3e4dbb416feb5fbc38..d940034acdd4aa465153f80ae0d5881cb648d6a8 100644 (file)
@@ -92,8 +92,8 @@ static int tc = TC_DEFAULT;
 module_param(tc, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(tc, "DMA threshold control value");
 
-#define DMA_BUFFER_SIZE        BUF_SIZE_4KiB
-static int buf_sz = DMA_BUFFER_SIZE;
+#define        DEFAULT_BUFSIZE 1536
+static int buf_sz = DEFAULT_BUFSIZE;
 module_param(buf_sz, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(buf_sz, "DMA buffer size");
 
@@ -136,8 +136,8 @@ static void stmmac_verify_args(void)
                dma_rxsize = DMA_RX_SIZE;
        if (unlikely(dma_txsize < 0))
                dma_txsize = DMA_TX_SIZE;
-       if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
-               buf_sz = DMA_BUFFER_SIZE;
+       if (unlikely((buf_sz < DEFAULT_BUFSIZE) || (buf_sz > BUF_SIZE_16KiB)))
+               buf_sz = DEFAULT_BUFSIZE;
        if (unlikely(flow_ctrl > 1))
                flow_ctrl = FLOW_AUTO;
        else if (likely(flow_ctrl < 0))
@@ -286,10 +286,25 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
        /* MAC core supports the EEE feature. */
        if (priv->dma_cap.eee) {
+               int tx_lpi_timer = priv->tx_lpi_timer;
+
                /* Check if the PHY supports EEE */
-               if (phy_init_eee(priv->phydev, 1))
+               if (phy_init_eee(priv->phydev, 1)) {
+                       /* To manage at run-time if the EEE cannot be supported
+                        * anymore (for example because the lp caps have been
+                        * changed).
+                        * In that case the driver disable own timers.
+                        */
+                       if (priv->eee_active) {
+                               pr_debug("stmmac: disable EEE\n");
+                               del_timer_sync(&priv->eee_ctrl_timer);
+                               priv->hw->mac->set_eee_timer(priv->ioaddr, 0,
+                                                            tx_lpi_timer);
+                       }
+                       priv->eee_active = 0;
                        goto out;
-
+               }
+               /* Activate the EEE and start timers */
                if (!priv->eee_active) {
                        priv->eee_active = 1;
                        init_timer(&priv->eee_ctrl_timer);
@@ -300,13 +315,13 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 
                        priv->hw->mac->set_eee_timer(priv->ioaddr,
                                                     STMMAC_DEFAULT_LIT_LS,
-                                                    priv->tx_lpi_timer);
+                                                    tx_lpi_timer);
                } else
                        /* Set HW EEE according to the speed */
                        priv->hw->mac->set_eee_pls(priv->ioaddr,
                                                   priv->phydev->link);
 
-               pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
+               pr_debug("stmmac: Energy-Efficient Ethernet initialized\n");
 
                ret = true;
        }
@@ -886,10 +901,10 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
                ret = BUF_SIZE_8KiB;
        else if (mtu >= BUF_SIZE_2KiB)
                ret = BUF_SIZE_4KiB;
-       else if (mtu >= DMA_BUFFER_SIZE)
+       else if (mtu > DEFAULT_BUFSIZE)
                ret = BUF_SIZE_2KiB;
        else
-               ret = DMA_BUFFER_SIZE;
+               ret = DEFAULT_BUFSIZE;
 
        return ret;
 }
@@ -951,9 +966,9 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
 
        p->des2 = priv->rx_skbuff_dma[i];
 
-       if ((priv->mode == STMMAC_RING_MODE) &&
+       if ((priv->hw->mode->init_desc3) &&
            (priv->dma_buf_sz == BUF_SIZE_16KiB))
-               priv->hw->ring->init_desc3(p);
+               priv->hw->mode->init_desc3(p);
 
        return 0;
 }
@@ -984,11 +999,8 @@ static int init_dma_desc_rings(struct net_device *dev)
        unsigned int bfsize = 0;
        int ret = -ENOMEM;
 
-       /* Set the max buffer size according to the DESC mode
-        * and the MTU. Note that RING mode allows 16KiB bsize.
-        */
-       if (priv->mode == STMMAC_RING_MODE)
-               bfsize = priv->hw->ring->set_16kib_bfsize(dev->mtu);
+       if (priv->hw->mode->set_16kib_bfsize)
+               bfsize = priv->hw->mode->set_16kib_bfsize(dev->mtu);
 
        if (bfsize < BUF_SIZE_16KiB)
                bfsize = stmmac_set_bfsize(dev->mtu, priv->dma_buf_sz);
@@ -1029,15 +1041,15 @@ static int init_dma_desc_rings(struct net_device *dev)
        /* Setup the chained descriptor addresses */
        if (priv->mode == STMMAC_CHAIN_MODE) {
                if (priv->extend_desc) {
-                       priv->hw->chain->init(priv->dma_erx, priv->dma_rx_phy,
-                                             rxsize, 1);
-                       priv->hw->chain->init(priv->dma_etx, priv->dma_tx_phy,
-                                             txsize, 1);
+                       priv->hw->mode->init(priv->dma_erx, priv->dma_rx_phy,
+                                            rxsize, 1);
+                       priv->hw->mode->init(priv->dma_etx, priv->dma_tx_phy,
+                                            txsize, 1);
                } else {
-                       priv->hw->chain->init(priv->dma_rx, priv->dma_rx_phy,
-                                             rxsize, 0);
-                       priv->hw->chain->init(priv->dma_tx, priv->dma_tx_phy,
-                                             txsize, 0);
+                       priv->hw->mode->init(priv->dma_rx, priv->dma_rx_phy,
+                                            rxsize, 0);
+                       priv->hw->mode->init(priv->dma_tx, priv->dma_tx_phy,
+                                            txsize, 0);
                }
        }
 
@@ -1288,10 +1300,10 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
                                         DMA_TO_DEVICE);
                        priv->tx_skbuff_dma[entry] = 0;
                }
-               priv->hw->ring->clean_desc3(priv, p);
+               priv->hw->mode->clean_desc3(priv, p);
 
                if (likely(skb != NULL)) {
-                       dev_kfree_skb(skb);
+                       dev_consume_skb_any(skb);
                        priv->tx_skbuff[entry] = NULL;
                }
 
@@ -1705,7 +1717,7 @@ static int stmmac_open(struct net_device *dev)
        priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
        priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
 
-       alloc_dma_desc_resources(priv);
+       ret = alloc_dma_desc_resources(priv);
        if (ret < 0) {
                pr_err("%s: DMA descriptors allocation failed\n", __func__);
                goto dma_desc_error;
@@ -1844,6 +1856,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        int nfrags = skb_shinfo(skb)->nr_frags;
        struct dma_desc *desc, *first;
        unsigned int nopaged_len = skb_headlen(skb);
+       unsigned int enh_desc = priv->plat->enh_desc;
 
        if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
                if (!netif_queue_stopped(dev)) {
@@ -1871,27 +1884,19 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        first = desc;
 
        /* To program the descriptors according to the size of the frame */
-       if (priv->mode == STMMAC_RING_MODE) {
-               is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
-                                                       priv->plat->enh_desc);
-               if (unlikely(is_jumbo))
-                       entry = priv->hw->ring->jumbo_frm(priv, skb,
-                                                         csum_insertion);
-       } else {
-               is_jumbo = priv->hw->chain->is_jumbo_frm(skb->len,
-                                                        priv->plat->enh_desc);
-               if (unlikely(is_jumbo))
-                       entry = priv->hw->chain->jumbo_frm(priv, skb,
-                                                          csum_insertion);
-       }
+       if (enh_desc)
+               is_jumbo = priv->hw->mode->is_jumbo_frm(skb->len, enh_desc);
+
        if (likely(!is_jumbo)) {
                desc->des2 = dma_map_single(priv->device, skb->data,
                                            nopaged_len, DMA_TO_DEVICE);
                priv->tx_skbuff_dma[entry] = desc->des2;
                priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len,
                                                csum_insertion, priv->mode);
-       } else
+       } else {
                desc = first;
+               entry = priv->hw->mode->jumbo_frm(priv, skb, csum_insertion);
+       }
 
        for (i = 0; i < nfrags; i++) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -2029,7 +2034,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv)
 
                        p->des2 = priv->rx_skbuff_dma[entry];
 
-                       priv->hw->ring->refill_desc3(priv, p);
+                       priv->hw->mode->refill_desc3(priv, p);
 
                        if (netif_msg_rx_status(priv))
                                pr_debug("\trefill entry #%d\n", entry);
@@ -2633,11 +2638,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
 
        /* To use the chained or ring mode */
        if (chain_mode) {
-               priv->hw->chain = &chain_mode_ops;
+               priv->hw->mode = &chain_mode_ops;
                pr_info(" Chain mode enabled\n");
                priv->mode = STMMAC_CHAIN_MODE;
        } else {
-               priv->hw->ring = &ring_mode_ops;
+               priv->hw->mode = &ring_mode_ops;
                pr_info(" Ring mode enabled\n");
                priv->mode = STMMAC_RING_MODE;
        }
index 5884a7d2063b9bf650a7940485f9e96ea2cb0022..46aef5108bea47c7d6e49b891937d05ac2610c85 100644 (file)
 static const struct of_device_id stmmac_dt_ids[] = {
 #ifdef CONFIG_DWMAC_SUNXI
        { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
+#endif
+#ifdef CONFIG_DWMAC_STI
+       { .compatible = "st,stih415-dwmac", .data = &sti_gmac_data},
+       { .compatible = "st,stih416-dwmac", .data = &sti_gmac_data},
+       { .compatible = "st,stid127-dwmac", .data = &sti_gmac_data},
+#endif
+#ifdef CONFIG_DWMAC_SOCFPGA
+       { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
 #endif
        /* SoC specific glue layers should come before generic bindings */
        { .compatible = "st,spear600-gmac"},
index 7680581ebe12fe58a60de42b419467e3f2f065f7..b7ad3565566cc8a09b7964fcb59aca3921e8e57c 100644 (file)
@@ -164,6 +164,7 @@ static struct ptp_clock_info stmmac_ptp_clock_ops = {
        .n_alarm = 0,
        .n_ext_ts = 0,
        .n_per_out = 0,
+       .n_pins = 0,
        .pps = 0,
        .adjfreq = stmmac_adjust_freq,
        .adjtime = stmmac_adjust_time,
index 8e2266e1f26070614559c12d5d5de50281aad813..79606f47a08e0989396203e5ba54485dba33a04f 100644 (file)
@@ -9041,7 +9041,7 @@ static void niu_try_msix(struct niu *np, u8 *ldg_num_map)
        struct msix_entry msi_vec[NIU_NUM_LDG];
        struct niu_parent *parent = np->parent;
        struct pci_dev *pdev = np->pdev;
-       int i, num_irqs, err;
+       int i, num_irqs;
        u8 first_ldg;
 
        first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port;
@@ -9053,21 +9053,16 @@ static void niu_try_msix(struct niu *np, u8 *ldg_num_map)
                    (np->port == 0 ? 3 : 1));
        BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports));
 
-retry:
        for (i = 0; i < num_irqs; i++) {
                msi_vec[i].vector = 0;
                msi_vec[i].entry = i;
        }
 
-       err = pci_enable_msix(pdev, msi_vec, num_irqs);
-       if (err < 0) {
+       num_irqs = pci_enable_msix_range(pdev, msi_vec, 1, num_irqs);
+       if (num_irqs < 0) {
                np->flags &= ~NIU_FLAGS_MSIX;
                return;
        }
-       if (err > 0) {
-               num_irqs = err;
-               goto retry;
-       }
 
        np->flags |= NIU_FLAGS_MSIX;
        for (i = 0; i < num_irqs; i++)
index c2799dc46325e48bad961c4a3138e80e28eabdb9..102a66fc54a216718fbe753f764ed62ee08cc987 100644 (file)
@@ -688,7 +688,7 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st
                }
 
                dev->stats.tx_packets++;
-               dev_kfree_skb(skb);
+               dev_consume_skb_any(skb);
        }
        gp->tx_old = entry;
 
index bde63e3af96f6a0e005cd2cc9da93b83a53dc0db..5d5fec6c4eb04bbdacf851635394893055a27866 100644 (file)
@@ -378,7 +378,6 @@ struct cpsw_priv {
        u32                             version;
        u32                             coal_intvl;
        u32                             bus_freq_mhz;
-       struct net_device_stats         stats;
        int                             rx_packet_max;
        int                             host_port;
        struct clk                      *clk;
@@ -554,7 +553,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
                 * common for both the interface as the interface shares
                 * the same hardware resource.
                 */
-               for (i = 0; i <= priv->data.slaves; i++)
+               for (i = 0; i < priv->data.slaves; i++)
                        if (priv->slaves[i].ndev->flags & IFF_PROMISC)
                                flag = true;
 
@@ -578,7 +577,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
                        unsigned long timeout = jiffies + HZ;
 
                        /* Disable Learn for all ports */
-                       for (i = 0; i <= priv->data.slaves; i++) {
+                       for (i = 0; i < priv->data.slaves; i++) {
                                cpsw_ale_control_set(ale, i,
                                                     ALE_PORT_NOLEARN, 1);
                                cpsw_ale_control_set(ale, i,
@@ -606,7 +605,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
                        cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0);
 
                        /* Enable Learn for all ports */
-                       for (i = 0; i <= priv->data.slaves; i++) {
+                       for (i = 0; i < priv->data.slaves; i++) {
                                cpsw_ale_control_set(ale, i,
                                                     ALE_PORT_NOLEARN, 0);
                                cpsw_ale_control_set(ale, i,
@@ -673,8 +672,8 @@ static void cpsw_tx_handler(void *token, int len, int status)
        if (unlikely(netif_queue_stopped(ndev)))
                netif_wake_queue(ndev);
        cpts_tx_timestamp(priv->cpts, skb);
-       priv->stats.tx_packets++;
-       priv->stats.tx_bytes += len;
+       ndev->stats.tx_packets++;
+       ndev->stats.tx_bytes += len;
        dev_kfree_skb_any(skb);
 }
 
@@ -700,10 +699,10 @@ static void cpsw_rx_handler(void *token, int len, int status)
                cpts_rx_timestamp(priv->cpts, skb);
                skb->protocol = eth_type_trans(skb, ndev);
                netif_receive_skb(skb);
-               priv->stats.rx_bytes += len;
-               priv->stats.rx_packets++;
+               ndev->stats.rx_bytes += len;
+               ndev->stats.rx_packets++;
        } else {
-               priv->stats.rx_dropped++;
+               ndev->stats.rx_dropped++;
                new_skb = skb;
        }
 
@@ -1164,11 +1163,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
 
 static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
 {
+       u32 slave_port;
+
+       slave_port = cpsw_get_slave_port(priv, slave->slave_num);
+
        if (!slave->phy)
                return;
        phy_stop(slave->phy);
        phy_disconnect(slave->phy);
        slave->phy = NULL;
+       cpsw_ale_control_set(priv->ale, slave_port,
+                            ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
 }
 
 static int cpsw_ndo_open(struct net_device *ndev)
@@ -1307,7 +1312,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 
        if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) {
                cpsw_err(priv, tx_err, "packet pad failed\n");
-               priv->stats.tx_dropped++;
+               ndev->stats.tx_dropped++;
                return NETDEV_TX_OK;
        }
 
@@ -1331,7 +1336,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb,
 
        return NETDEV_TX_OK;
 fail:
-       priv->stats.tx_dropped++;
+       ndev->stats.tx_dropped++;
        netif_stop_queue(ndev);
        return NETDEV_TX_BUSY;
 }
@@ -1471,7 +1476,6 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
 static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
        struct cpsw_priv *priv = netdev_priv(dev);
-       struct mii_ioctl_data *data = if_mii(req);
        int slave_no = cpsw_slave_index(priv);
 
        if (!netif_running(dev))
@@ -1484,14 +1488,11 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
        case SIOCGHWTSTAMP:
                return cpsw_hwtstamp_get(dev, req);
 #endif
-       case SIOCGMIIPHY:
-               data->phy_id = priv->slaves[slave_no].phy->addr;
-               break;
-       default:
-               return -ENOTSUPP;
        }
 
-       return 0;
+       if (!priv->slaves[slave_no].phy)
+               return -EOPNOTSUPP;
+       return phy_mii_ioctl(priv->slaves[slave_no].phy, req, cmd);
 }
 
 static void cpsw_ndo_tx_timeout(struct net_device *ndev)
@@ -1499,7 +1500,7 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
        struct cpsw_priv *priv = netdev_priv(ndev);
 
        cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n");
-       priv->stats.tx_errors++;
+       ndev->stats.tx_errors++;
        cpsw_intr_disable(priv);
        cpdma_ctlr_int_ctrl(priv->dma, false);
        cpdma_chan_stop(priv->txch);
@@ -1538,12 +1539,6 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
        return 0;
 }
 
-static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev)
-{
-       struct cpsw_priv *priv = netdev_priv(ndev);
-       return &priv->stats;
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void cpsw_ndo_poll_controller(struct net_device *ndev)
 {
@@ -1636,7 +1631,6 @@ static const struct net_device_ops cpsw_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = eth_change_mtu,
        .ndo_tx_timeout         = cpsw_ndo_tx_timeout,
-       .ndo_get_stats          = cpsw_ndo_get_stats,
        .ndo_set_rx_mode        = cpsw_ndo_set_rx_mode,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = cpsw_ndo_poll_controller,
@@ -1878,14 +1872,29 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
                phyid = be32_to_cpup(parp+1);
                mdio = of_find_device_by_node(mdio_node);
-               snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
-                        PHY_ID_FMT, mdio->name, phyid);
+
+               if (strncmp(mdio->name, "gpio", 4) == 0) {
+                       /* GPIO bitbang MDIO driver attached */
+                       struct mii_bus *bus = dev_get_drvdata(&mdio->dev);
+
+                       snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                                PHY_ID_FMT, bus->id, phyid);
+               } else {
+                       /* davinci MDIO driver attached */
+                       snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+                                PHY_ID_FMT, mdio->name, phyid);
+               }
 
                mac_addr = of_get_mac_address(slave_node);
                if (mac_addr)
                        memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
 
                slave_data->phy_if = of_get_phy_mode(slave_node);
+               if (slave_data->phy_if < 0) {
+                       pr_err("Missing or malformed slave[%d] phy-mode property\n",
+                              i);
+                       return slave_data->phy_if;
+               }
 
                if (data->dual_emac) {
                        if (of_property_read_u32(slave_node, "dual_emac_res_vlan",
@@ -2208,10 +2217,6 @@ static int cpsw_probe(struct platform_device *pdev)
                goto clean_ale_ret;
        }
 
-       if (cpts_register(&pdev->dev, priv->cpts,
-                         data->cpts_clock_mult, data->cpts_clock_shift))
-               dev_err(priv->dev, "error registering cpts device\n");
-
        cpsw_notice(priv, probe, "initialized device (regs %pa, irq %d)\n",
                    &ss_res->start, ndev->irq);
 
index 8c351f100acac5335aedeba235b395bd4330a109..a3bbf59eaafdf2e31b400336129e3731e0d88364 100644 (file)
 
 #ifdef CONFIG_TI_CPTS
 
-static struct sock_filter ptp_filter[] = {
-       PTP_FILTER
-};
-
 #define cpts_read32(c, r)      __raw_readl(&c->reg->r)
 #define cpts_write32(c, v, r)  __raw_writel(v, &c->reg->r)
 
@@ -217,6 +213,7 @@ static struct ptp_clock_info cpts_info = {
        .name           = "CTPS timer",
        .max_adj        = 1000000,
        .n_ext_ts       = 0,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = cpts_ptp_adjfreq,
        .adjtime        = cpts_ptp_adjtime,
@@ -300,7 +297,7 @@ static u64 cpts_find_ts(struct cpts *cpts, struct sk_buff *skb, int ev_type)
        u64 ns = 0;
        struct cpts_event *event;
        struct list_head *this, *next;
-       unsigned int class = sk_run_filter(skb, ptp_filter);
+       unsigned int class = ptp_classify_raw(skb);
        unsigned long flags;
        u16 seqid;
        u8 mtype;
@@ -371,10 +368,6 @@ int cpts_register(struct device *dev, struct cpts *cpts,
        int err, i;
        unsigned long flags;
 
-       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
-               pr_err("cpts: bad ptp filter\n");
-               return -EINVAL;
-       }
        cpts->info = cpts_info;
        cpts->clock = ptp_clock_register(&cpts->info, dev);
        if (IS_ERR(cpts->clock)) {
index 364d0c7952c023d0cc60de6cc8d73460b000fbd1..88ef27067bf24a8b2569f533b63ac223d52280fe 100644 (file)
@@ -355,7 +355,7 @@ int cpdma_ctlr_stop(struct cpdma_ctlr *ctlr)
        int i;
 
        spin_lock_irqsave(&ctlr->lock, flags);
-       if (ctlr->state != CPDMA_STATE_ACTIVE) {
+       if (ctlr->state == CPDMA_STATE_TEARDOWN) {
                spin_unlock_irqrestore(&ctlr->lock, flags);
                return -EINVAL;
        }
@@ -891,7 +891,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan)
        unsigned                timeout;
 
        spin_lock_irqsave(&chan->lock, flags);
-       if (chan->state != CPDMA_STATE_ACTIVE) {
+       if (chan->state == CPDMA_STATE_TEARDOWN) {
                spin_unlock_irqrestore(&chan->lock, flags);
                return -EINVAL;
        }
index cd9b164a0434acb3a51066b5d0e17262a4bdc0dd..8f0e69ce07ca3e03cfbf4cf1b22c92c9af27beeb 100644 (file)
@@ -1532,9 +1532,9 @@ static int emac_dev_open(struct net_device *ndev)
        struct device *emac_dev = &ndev->dev;
        u32 cnt;
        struct resource *res;
-       int ret;
+       int q, m, ret;
+       int res_num = 0, irq_num = 0;
        int i = 0;
-       int k = 0;
        struct emac_priv *priv = netdev_priv(ndev);
 
        pm_runtime_get(&priv->pdev->dev);
@@ -1564,15 +1564,24 @@ static int emac_dev_open(struct net_device *ndev)
        }
 
        /* Request IRQ */
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ,
+                                           res_num))) {
+               for (irq_num = res->start; irq_num <= res->end; irq_num++) {
+                       dev_err(emac_dev, "Request IRQ %d\n", irq_num);
+                       if (request_irq(irq_num, emac_irq, 0, ndev->name,
+                                       ndev)) {
+                               dev_err(emac_dev,
+                                       "DaVinci EMAC: request_irq() failed\n");
+                               ret = -EBUSY;
 
-       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
-               for (i = res->start; i <= res->end; i++) {
-                       if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
-                                            0, ndev->name, ndev))
                                goto rollback;
+                       }
                }
-               k++;
+               res_num++;
        }
+       /* prepare counters for rollback in case of an error */
+       res_num--;
+       irq_num--;
 
        /* Start/Enable EMAC hardware */
        emac_hw_enable(priv);
@@ -1639,11 +1648,23 @@ static int emac_dev_open(struct net_device *ndev)
 
        return 0;
 
-rollback:
-
-       dev_err(emac_dev, "DaVinci EMAC: devm_request_irq() failed");
-       ret = -EBUSY;
 err:
+       emac_int_disable(priv);
+       napi_disable(&priv->napi);
+
+rollback:
+       for (q = res_num; q >= 0; q--) {
+               res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, q);
+               /* at the first iteration, irq_num is already set to the
+                * right value
+                */
+               if (q != res_num)
+                       irq_num = res->end;
+
+               for (m = irq_num; m >= res->start; m--)
+                       free_irq(m, ndev);
+       }
+       cpdma_ctlr_stop(priv->dma);
        pm_runtime_put(&priv->pdev->dev);
        return ret;
 }
@@ -1659,6 +1680,9 @@ err:
  */
 static int emac_dev_stop(struct net_device *ndev)
 {
+       struct resource *res;
+       int i = 0;
+       int irq_num;
        struct emac_priv *priv = netdev_priv(ndev);
        struct device *emac_dev = &ndev->dev;
 
@@ -1674,6 +1698,13 @@ static int emac_dev_stop(struct net_device *ndev)
        if (priv->phydev)
                phy_disconnect(priv->phydev);
 
+       /* Free IRQ */
+       while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, i))) {
+               for (irq_num = res->start; irq_num <= res->end; irq_num++)
+                       free_irq(irq_num, priv->ndev);
+               i++;
+       }
+
        if (netif_msg_drv(priv))
                dev_notice(emac_dev, "DaVinci EMAC: %s stopped\n", ndev->name);
 
index 023237a657207995e367ec365269d155043377c0..7e1c91d41a87ff2a4e065718d4caaf84c7db8020 100644 (file)
@@ -659,6 +659,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
        struct info_mpipe *info_mpipe =
                container_of(napi, struct info_mpipe, napi);
 
+       if (budget <= 0)
+               goto done;
+
        instance = info_mpipe->instance;
        while ((n = gxio_mpipe_iqueue_try_peek(
                        &info_mpipe->iqueue,
@@ -870,6 +873,7 @@ static struct ptp_clock_info ptp_mpipe_caps = {
        .name           = "mPIPE clock",
        .max_adj        = 999999999,
        .n_ext_ts       = 0,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = ptp_mpipe_adjfreq,
        .adjtime        = ptp_mpipe_adjtime,
@@ -2071,7 +2075,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
 
 /* Return subqueue id on this core (one per core). */
 static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb,
-                                void *accel_priv)
+                                void *accel_priv, select_queue_fallback_t fallback)
 {
        return smp_processor_id();
 }
index edb2e12a0fe214894e9a9a0445ccc7e869dbe7d6..e5a5c5d4ce0c8c8967c7963bf8bff36ee58f113f 100644 (file)
@@ -831,6 +831,9 @@ static int tile_net_poll(struct napi_struct *napi, int budget)
 
        unsigned int work = 0;
 
+       if (budget <= 0)
+               goto done;
+
        while (priv->active) {
                int index = qup->__packet_receive_read;
                if (index == qsp->__packet_receive_queue.__packet_write)
@@ -1821,7 +1824,7 @@ busy:
 
        /* Handle completions. */
        for (i = 0; i < nolds; i++)
-               kfree_skb(olds[i]);
+               dev_consume_skb_any(olds[i]);
 
        /* Update stats. */
        u64_stats_update_begin(&stats->syncp);
@@ -2005,7 +2008,7 @@ busy:
 
        /* Handle completions. */
        for (i = 0; i < nolds; i++)
-               kfree_skb(olds[i]);
+               dev_consume_skb_any(olds[i]);
 
        /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
        u64_stats_update_begin(&stats->syncp);
@@ -2068,14 +2071,14 @@ static struct rtnl_link_stats64 *tile_net_get_stats64(struct net_device *dev,
                cpu_stats = &priv->cpu[i]->stats;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&cpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
                        trx_packets = cpu_stats->rx_packets;
                        ttx_packets = cpu_stats->tx_packets;
                        trx_bytes   = cpu_stats->rx_bytes;
                        ttx_bytes   = cpu_stats->tx_bytes;
                        trx_errors  = cpu_stats->rx_errors;
                        trx_dropped = cpu_stats->rx_dropped;
-               } while (u64_stats_fetch_retry_bh(&cpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
 
                rx_packets += trx_packets;
                tx_packets += ttx_packets;
index 3f4a32e39d276f6fcf9c9d9d16c4aec440b9daf6..0282d01618595aa2e4b690dea15e1b82d625b705 100644 (file)
@@ -860,7 +860,7 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
                if (skb) {
                        pci_unmap_single(card->pdev, buf_addr, skb->len,
                                        PCI_DMA_TODEVICE);
-                       dev_kfree_skb(skb);
+                       dev_consume_skb_any(skb);
                }
        }
        return 0;
index 88e9c73cebc015b9a31b169b973911f92ef8a9d8..fef5573dbfcac0f6db7c44be4124fd04c1fe6587 100644 (file)
@@ -1645,6 +1645,9 @@ static int tc35815_poll(struct napi_struct *napi, int budget)
        int received = 0, handled;
        u32 status;
 
+       if (budget <= 0)
+               return received;
+
        spin_lock(&lp->rx_lock);
        status = tc_readl(&tr->Int_Src);
        do {
index ef312bc6b8658deabae28d179c39237564b8ede4..f61dc2b72bb2f43780ace58a503bd2e3b89f61a9 100644 (file)
@@ -923,7 +923,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc) {
                dev_err(&pdev->dev,
                        "32-bit PCI DMA addresses not supported by the card!?\n");
-               goto err_out;
+               goto err_out_pci_disable;
        }
 
        /* sanity check */
@@ -931,7 +931,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
            (pci_resource_len(pdev, 1) < io_size)) {
                rc = -EIO;
                dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
-               goto err_out;
+               goto err_out_pci_disable;
        }
 
        pioaddr = pci_resource_start(pdev, 0);
@@ -942,7 +942,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev = alloc_etherdev(sizeof(struct rhine_private));
        if (!dev) {
                rc = -ENOMEM;
-               goto err_out;
+               goto err_out_pci_disable;
        }
        SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -1022,7 +1022,7 @@ static int rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* The chip-specific entries in the device structure. */
        dev->netdev_ops = &rhine_netdev_ops;
-       dev->ethtool_ops = &netdev_ethtool_ops,
+       dev->ethtool_ops = &netdev_ethtool_ops;
        dev->watchdog_timeo = TX_TIMEOUT;
 
        netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
@@ -1084,6 +1084,8 @@ err_out_free_res:
        pci_release_regions(pdev);
 err_out_free_netdev:
        free_netdev(dev);
+err_out_pci_disable:
+       pci_disable_device(pdev);
 err_out:
        return rc;
 }
@@ -1676,7 +1678,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                /* Must use alignment buffer. */
                if (skb->len > PKT_BUF_SZ) {
                        /* packet too long, drop it */
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        rp->tx_skbuff[entry] = NULL;
                        dev->stats.tx_dropped++;
                        return NETDEV_TX_OK;
@@ -1696,7 +1698,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
                        pci_map_single(rp->pdev, skb->data, skb->len,
                                       PCI_DMA_TODEVICE);
                if (dma_mapping_error(&rp->pdev->dev, rp->tx_skbuff_dma[entry])) {
-                       dev_kfree_skb(skb);
+                       dev_kfree_skb_any(skb);
                        rp->tx_skbuff_dma[entry] = 0;
                        dev->stats.tx_dropped++;
                        return NETDEV_TX_OK;
@@ -1834,7 +1836,7 @@ static void rhine_tx(struct net_device *dev)
                                         rp->tx_skbuff[entry]->len,
                                         PCI_DMA_TODEVICE);
                }
-               dev_kfree_skb(rp->tx_skbuff[entry]);
+               dev_consume_skb_any(rp->tx_skbuff[entry]);
                rp->tx_skbuff[entry] = NULL;
                entry = (++rp->dirty_tx) % TX_RING_SIZE;
        }
@@ -2070,16 +2072,16 @@ rhine_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        netdev_stats_to_stats64(stats, &dev->stats);
 
        do {
-               start = u64_stats_fetch_begin_bh(&rp->rx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&rp->rx_stats.syncp);
                stats->rx_packets = rp->rx_stats.packets;
                stats->rx_bytes = rp->rx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&rp->rx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rp->rx_stats.syncp, start));
 
        do {
-               start = u64_stats_fetch_begin_bh(&rp->tx_stats.syncp);
+               start = u64_stats_fetch_begin_irq(&rp->tx_stats.syncp);
                stats->tx_packets = rp->tx_stats.packets;
                stats->tx_bytes = rp->tx_stats.bytes;
-       } while (u64_stats_fetch_retry_bh(&rp->tx_stats.syncp, start));
+       } while (u64_stats_fetch_retry_irq(&rp->tx_stats.syncp, start));
 
        return stats;
 }
index ad61d26a44f31d26fc3b6d96f8430a5264e28e6f..de08e86db209fdd21aee55bea8b2827b2af48fe7 100644 (file)
@@ -2565,7 +2565,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
        /* The hardware can handle at most 7 memory segments, so merge
         * the skb if there are more */
        if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index 0df36c6ec7f4618c753db429d8c6c793455e0594..104d46f37969f990c920d4ee42c61e7258579f8a 100644 (file)
@@ -641,11 +641,10 @@ static int w5100_hw_probe(struct platform_device *pdev)
        if (!mem)
                return -ENXIO;
        mem_size = resource_size(mem);
-       if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name))
-               return -EBUSY;
-       priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size);
-       if (!priv->base)
-               return -EBUSY;
+
+       priv->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
 
        spin_lock_init(&priv->reg_lock);
        priv->indirect = mem_size < W5100_BUS_DIRECT_SIZE;
index 71c27b3292f1318a30a26dcd25d277dfcc5bd119..1f33c4c86c207f6a4fecf52bca8645c5e114be9e 100644 (file)
@@ -561,11 +561,10 @@ static int w5300_hw_probe(struct platform_device *pdev)
        if (!mem)
                return -ENXIO;
        mem_size = resource_size(mem);
-       if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name))
-               return -EBUSY;
-       priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size);
-       if (!priv->base)
-               return -EBUSY;
+
+       priv->base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
 
        spin_lock_init(&priv->reg_lock);
        priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE;
index a4347508031ce4cff516c8d5dce32a4ba9e2efa8..fa193c4688da78719257ac982af8be1f81b270c1 100644 (file)
@@ -771,8 +771,8 @@ static void ll_temac_recv(struct net_device *ndev)
 
                /* if we're doing rx csum offload, set it up */
                if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) &&
-                       (skb->protocol == __constant_htons(ETH_P_IP)) &&
-                       (skb->len > 64)) {
+                   (skb->protocol == htons(ETH_P_IP)) &&
+                   (skb->len > 64)) {
 
                        skb->csum = cur_p->app3 & 0xFFFF;
                        skb->ip_summed = CHECKSUM_COMPLETE;
index 1ec65feebb9e29cb1b9bfe7ffe2343fdfad9c537..7b0a735562645cf042cfb312ace5018180d94559 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/netdevice.h>
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
+#include <linux/of_irq.h>
 #include <linux/of_address.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
@@ -600,7 +601,8 @@ static void axienet_start_xmit_done(struct net_device *ndev)
                size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK;
                packets++;
 
-               lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM;
+               ++lp->tx_bd_ci;
+               lp->tx_bd_ci %= TX_BD_NUM;
                cur_p = &lp->tx_bd_v[lp->tx_bd_ci];
                status = cur_p->status;
        }
@@ -686,7 +688,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                     skb_headlen(skb), DMA_TO_DEVICE);
 
        for (ii = 0; ii < num_frag; ii++) {
-               lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
+               ++lp->tx_bd_tail;
+               lp->tx_bd_tail %= TX_BD_NUM;
                cur_p = &lp->tx_bd_v[lp->tx_bd_tail];
                frag = &skb_shinfo(skb)->frags[ii];
                cur_p->phys = dma_map_single(ndev->dev.parent,
@@ -702,7 +705,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail;
        /* Start the transfer */
        axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p);
-       lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM;
+       ++lp->tx_bd_tail;
+       lp->tx_bd_tail %= TX_BD_NUM;
 
        return NETDEV_TX_OK;
 }
@@ -752,7 +756,7 @@ static void axienet_recv(struct net_device *ndev)
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
                        }
                } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 &&
-                          skb->protocol == __constant_htons(ETH_P_IP) &&
+                          skb->protocol == htons(ETH_P_IP) &&
                           skb->len > 64) {
                        skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF);
                        skb->ip_summed = CHECKSUM_COMPLETE;
@@ -774,7 +778,8 @@ static void axienet_recv(struct net_device *ndev)
                cur_p->status = 0;
                cur_p->sw_id_offset = (u32) new_skb;
 
-               lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM;
+               ++lp->rx_bd_ci;
+               lp->rx_bd_ci %= RX_BD_NUM;
                cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
        }
 
index 36052b98b3fcb20c8955a575c66d38fb8e6fc2ad..0d87c67a5ff7208e807a980c406a934214c9d4a6 100644 (file)
@@ -794,18 +794,6 @@ static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg,
        return 0;
 }
 
-/**
- * xemaclite_mdio_reset - Reset the mdio bus.
- * @bus:       Pointer to the MII bus
- *
- * This function is required(?) as per Documentation/networking/phy.txt.
- * There is no reset in this device; this function always returns 0.
- */
-static int xemaclite_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 /**
  * xemaclite_mdio_setup - Register mii_bus for the Emaclite device
  * @lp:                Pointer to the Emaclite device private data
@@ -861,7 +849,6 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev)
        bus->name = "Xilinx Emaclite MDIO";
        bus->read = xemaclite_mdio_read;
        bus->write = xemaclite_mdio_write;
-       bus->reset = xemaclite_mdio_reset;
        bus->parent = dev;
        bus->irq = lp->mdio_irqs; /* preallocated IRQ table */
 
@@ -1037,7 +1024,7 @@ static int xemaclite_send(struct sk_buff *orig_skb, struct net_device *dev)
        skb_tx_timestamp(new_skb);
 
        dev->stats.tx_bytes += len;
-       dev_kfree_skb(new_skb);
+       dev_consume_skb_any(new_skb);
 
        return 0;
 }
index 25283f17d82f34e093e8b41fe195f82ebb66db26..f7e0f0f7c2e27dd19b2cbc674644cd4678074c2c 100644 (file)
@@ -256,10 +256,6 @@ static int ports_open;
 static struct port *npe_port_tab[MAX_NPES];
 static struct dma_pool *dma_pool;
 
-static struct sock_filter ptp_filter[] = {
-       PTP_FILTER
-};
-
 static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
 {
        u8 *data = skb->data;
@@ -267,7 +263,7 @@ static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
        u16 *hi, *id;
        u32 lo;
 
-       if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
+       if (ptp_classify_raw(skb) != PTP_CLASS_V1_IPV4)
                return 0;
 
        offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
@@ -1413,11 +1409,6 @@ static int eth_init_one(struct platform_device *pdev)
        char phy_id[MII_BUS_ID_SIZE + 3];
        int err;
 
-       if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
-               pr_err("ixp4xx_eth: bad ptp filter\n");
-               return -EINVAL;
-       }
-
        if (!(dev = alloc_etherdev(sizeof(struct port))))
                return -ENOMEM;
 
index 61dd2447e1bb4eedb5d8e6b72abcf21e9f273afb..81901659cc9ea1126e22f02e427dab1b9a729039 100644 (file)
@@ -1184,7 +1184,7 @@ static void __exit yam_cleanup_driver(void)
        struct yam_mcs *p;
        int i;
 
-       del_timer(&yam_timer);
+       del_timer_sync(&yam_timer);
        for (i = 0; i < NR_PORTS; i++) {
                struct net_device *dev = yam_devs[i];
                if (dev) {
index 7b594ce3f21db2102139e8802d4d9e69bb61a3e8..13010b4dae5b7ddea9b3a48cf28dc8425c5b3e6c 100644 (file)
@@ -30,6 +30,7 @@
 
 /* Fwd declaration */
 struct hv_netvsc_packet;
+struct ndis_tcp_ip_checksum_info;
 
 /* Represent the xfer page packet which contains 1 or more netvsc packet */
 struct xferpage_packet {
@@ -73,7 +74,7 @@ struct hv_netvsc_packet {
        } completion;
 
        /* This points to the memory after page_buf */
-       void *extension;
+       struct rndis_message *rndis_msg;
 
        u32 total_data_buflen;
        /* Points to the send/receive buffer where the ethernet frame is */
@@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device,
 void netvsc_linkstatus_callback(struct hv_device *device_obj,
                                unsigned int status);
 int netvsc_recv_callback(struct hv_device *device_obj,
-                       struct hv_netvsc_packet *packet);
+                       struct hv_netvsc_packet *packet,
+                       struct ndis_tcp_ip_checksum_info *csum_info);
 int rndis_filter_open(struct hv_device *dev);
 int rndis_filter_close(struct hv_device *dev);
 int rndis_filter_device_add(struct hv_device *dev,
@@ -126,11 +128,6 @@ void rndis_filter_device_remove(struct hv_device *dev);
 int rndis_filter_receive(struct hv_device *dev,
                        struct hv_netvsc_packet *pkt);
 
-
-
-int rndis_filter_send(struct hv_device *dev,
-                       struct hv_netvsc_packet *pkt);
-
 int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
 int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
 
@@ -139,6 +136,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
 
 #define NVSP_PROTOCOL_VERSION_1                2
 #define NVSP_PROTOCOL_VERSION_2                0x30002
+#define NVSP_PROTOCOL_VERSION_4                0x40000
+#define NVSP_PROTOCOL_VERSION_5                0x50000
 
 enum {
        NVSP_MSG_TYPE_NONE = 0,
@@ -193,6 +192,23 @@ enum {
 
        NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE,
        NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
+
+       NVSP_MSG2_MAX = NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP,
+
+       /* Version 4 messages */
+       NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION,
+       NVSP_MSG4_TYPE_SWITCH_DATA_PATH,
+       NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED,
+
+       NVSP_MSG4_MAX = NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED,
+
+       /* Version 5 messages */
+       NVSP_MSG5_TYPE_OID_QUERY_EX,
+       NVSP_MSG5_TYPE_OID_QUERY_EX_COMP,
+       NVSP_MSG5_TYPE_SUBCHANNEL,
+       NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE,
+
+       NVSP_MSG5_MAX = NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE,
 };
 
 enum {
@@ -447,10 +463,44 @@ union nvsp_2_message_uber {
        struct nvsp_2_free_rxbuf free_rxbuf;
 } __packed;
 
+enum nvsp_subchannel_operation {
+       NVSP_SUBCHANNEL_NONE = 0,
+       NVSP_SUBCHANNEL_ALLOCATE,
+       NVSP_SUBCHANNEL_MAX
+};
+
+struct nvsp_5_subchannel_request {
+       u32 op;
+       u32 num_subchannels;
+} __packed;
+
+struct nvsp_5_subchannel_complete {
+       u32 status;
+       u32 num_subchannels; /* Actual number of subchannels allocated */
+} __packed;
+
+struct nvsp_5_send_indirect_table {
+       /* The number of entries in the send indirection table */
+       u32 count;
+
+       /* The offset of the send indireciton table from top of this struct.
+        * The send indirection table tells which channel to put the send
+        * traffic on. Each entry is a channel number.
+        */
+       u32 offset;
+} __packed;
+
+union nvsp_5_message_uber {
+       struct nvsp_5_subchannel_request subchn_req;
+       struct nvsp_5_subchannel_complete subchn_comp;
+       struct nvsp_5_send_indirect_table send_table;
+} __packed;
+
 union nvsp_all_messages {
        union nvsp_message_init_uber init_msg;
        union nvsp_1_message_uber v1_msg;
        union nvsp_2_message_uber v2_msg;
+       union nvsp_5_message_uber v5_msg;
 } __packed;
 
 /* ALL Messages */
@@ -463,6 +513,7 @@ struct nvsp_message {
 #define NETVSC_MTU 65536
 
 #define NETVSC_RECEIVE_BUFFER_SIZE             (1024*1024*16)  /* 16MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY      (1024*1024*15)  /* 15MB */
 
 #define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
@@ -506,6 +557,8 @@ struct netvsc_device {
 
        /* Holds rndis device info */
        void *extension;
+       /* The recive buffer for this device */
+       unsigned char cb_buffer[NETVSC_PACKET_SIZE];
 };
 
 /* NdisInitialize message */
@@ -671,9 +724,133 @@ struct ndis_pkt_8021q_info {
        };
 };
 
+struct ndis_oject_header {
+       u8 type;
+       u8 revision;
+       u16 size;
+};
+
+#define NDIS_OBJECT_TYPE_DEFAULT       0x80
+#define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3
+#define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED  2
+#define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED  2
+#define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1
+#define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2
+#define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3
+#define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4
+
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE    1
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4       0
+#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6       1
+
+/*
+ * New offload OIDs for NDIS 6
+ */
+#define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */
+#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C          /* set only */
+#define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */
+#define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */
+#define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */
+
+struct ndis_offload_params {
+       struct ndis_oject_header header;
+       u8 ip_v4_csum;
+       u8 tcp_ip_v4_csum;
+       u8 udp_ip_v4_csum;
+       u8 tcp_ip_v6_csum;
+       u8 udp_ip_v6_csum;
+       u8 lso_v1;
+       u8 ip_sec_v1;
+       u8 lso_v2_ipv4;
+       u8 lso_v2_ipv6;
+       u8 tcp_connection_ip_v4;
+       u8 tcp_connection_ip_v6;
+       u32 flags;
+       u8 ip_sec_v2;
+       u8 ip_sec_v2_ip_v4;
+       struct {
+               u8 rsc_ip_v4;
+               u8 rsc_ip_v6;
+       };
+       struct {
+               u8 encapsulated_packet_task_offload;
+               u8 encapsulation_types;
+       };
+};
+
+struct ndis_tcp_ip_checksum_info {
+       union {
+               struct {
+                       u32 is_ipv4:1;
+                       u32 is_ipv6:1;
+                       u32 tcp_checksum:1;
+                       u32 udp_checksum:1;
+                       u32 ip_header_checksum:1;
+                       u32 reserved:11;
+                       u32 tcp_header_offset:10;
+               } transmit;
+               struct {
+                       u32 tcp_checksum_failed:1;
+                       u32 udp_checksum_failed:1;
+                       u32 ip_checksum_failed:1;
+                       u32 tcp_checksum_succeeded:1;
+                       u32 udp_checksum_succeeded:1;
+                       u32 ip_checksum_succeeded:1;
+                       u32 loopback:1;
+                       u32 tcp_checksum_value_invalid:1;
+                       u32 ip_checksum_value_invalid:1;
+               } receive;
+               u32  value;
+       };
+};
+
+struct ndis_tcp_lso_info {
+       union {
+               struct {
+                       u32 unused:30;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } transmit;
+               struct {
+                       u32 mss:20;
+                       u32 tcp_header_offset:10;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } lso_v1_transmit;
+               struct {
+                       u32 tcp_payload:30;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } lso_v1_transmit_complete;
+               struct {
+                       u32 mss:20;
+                       u32 tcp_header_offset:10;
+                       u32 type:1;
+                       u32 ip_version:1;
+               } lso_v2_transmit;
+               struct {
+                       u32 reserved:30;
+                       u32 type:1;
+                       u32 reserved2:1;
+               } lso_v2_transmit_complete;
+               u32  value;
+       };
+};
+
 #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
                sizeof(struct ndis_pkt_8021q_info))
 
+#define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+               sizeof(struct ndis_tcp_ip_checksum_info))
+
+#define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \
+               sizeof(struct ndis_tcp_lso_info))
+
 /* Format of Information buffer passed in a SetRequest for the OID */
 /* OID_GEN_RNDIS_CONFIG_PARAMETER. */
 struct rndis_config_parameter_info {
@@ -846,12 +1023,6 @@ struct rndis_message {
 };
 
 
-struct rndis_filter_packet {
-       void *completion_ctx;
-       void (*completion)(void *context);
-       struct rndis_message msg;
-};
-
 /* Handy macros */
 
 /* get the size of an RNDIS message. Pass in the message type, */
@@ -905,6 +1076,16 @@ struct rndis_filter_packet {
 #define NDIS_PACKET_TYPE_FUNCTIONAL    0x00000400
 #define NDIS_PACKET_TYPE_MAC_FRAME     0x00000800
 
+#define INFO_IPV4       2
+#define INFO_IPV6       4
+#define INFO_TCP        2
+#define INFO_UDP        4
+
+#define TRANSPORT_INFO_NOT_IP   0
+#define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP)
+#define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP)
+#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP)
+#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP)
 
 
 #endif /* _HYPERV_NET_H */
index 03a2c6e171584ff5f639d686458fbb75b7dcfb47..daddea2654ce4ec6ee3e3db66d45c9edb9ceb35f 100644 (file)
@@ -290,7 +290,7 @@ static int negotiate_nvsp_ver(struct hv_device *device,
            NVSP_STAT_SUCCESS)
                return -EINVAL;
 
-       if (nvsp_ver != NVSP_PROTOCOL_VERSION_2)
+       if (nvsp_ver == NVSP_PROTOCOL_VERSION_1)
                return 0;
 
        /* NVSPv2 only: Send NDIS config */
@@ -314,6 +314,9 @@ static int netvsc_connect_vsp(struct hv_device *device)
        struct nvsp_message *init_packet;
        int ndis_version;
        struct net_device *ndev;
+       u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
+               NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
+       int i, num_ver = 4; /* number of different NVSP versions */
 
        net_device = get_outbound_net_device(device);
        if (!net_device)
@@ -323,13 +326,14 @@ static int netvsc_connect_vsp(struct hv_device *device)
        init_packet = &net_device->channel_init_pkt;
 
        /* Negotiate the latest NVSP protocol supported */
-       if (negotiate_nvsp_ver(device, net_device, init_packet,
-                              NVSP_PROTOCOL_VERSION_2) == 0) {
-               net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2;
-       } else if (negotiate_nvsp_ver(device, net_device, init_packet,
-                                   NVSP_PROTOCOL_VERSION_1) == 0) {
-               net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1;
-       } else {
+       for (i = num_ver - 1; i >= 0; i--)
+               if (negotiate_nvsp_ver(device, net_device, init_packet,
+                                      ver_list[i])  == 0) {
+                       net_device->nvsp_version = ver_list[i];
+                       break;
+               }
+
+       if (i < 0) {
                ret = -EPROTO;
                goto cleanup;
        }
@@ -339,7 +343,10 @@ static int netvsc_connect_vsp(struct hv_device *device)
        /* Send the ndis version */
        memset(init_packet, 0, sizeof(struct nvsp_message));
 
-       ndis_version = 0x00050001;
+       if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_4)
+               ndis_version = 0x00050001;
+       else
+               ndis_version = 0x0006001e;
 
        init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER;
        init_packet->msg.v1_msg.
@@ -358,6 +365,11 @@ static int netvsc_connect_vsp(struct hv_device *device)
                goto cleanup;
 
        /* Post the big receive buffer to NetVSP */
+       if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2)
+               net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
+       else
+               net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
+
        ret = netvsc_init_recv_buf(device);
 
 cleanup:
@@ -432,17 +444,14 @@ static inline u32 hv_ringbuf_avail_percent(
        return avail_write * 100 / ring_info->ring_datasize;
 }
 
-static void netvsc_send_completion(struct hv_device *device,
+static void netvsc_send_completion(struct netvsc_device *net_device,
+                                  struct hv_device *device,
                                   struct vmpacket_descriptor *packet)
 {
-       struct netvsc_device *net_device;
        struct nvsp_message *nvsp_packet;
        struct hv_netvsc_packet *nvsc_packet;
        struct net_device *ndev;
 
-       net_device = get_inbound_net_device(device);
-       if (!net_device)
-               return;
        ndev = net_device->ndev;
 
        nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
@@ -561,13 +570,13 @@ int netvsc_send(struct hv_device *device,
 }
 
 static void netvsc_send_recv_completion(struct hv_device *device,
+                                       struct netvsc_device *net_device,
                                        u64 transaction_id, u32 status)
 {
        struct nvsp_message recvcompMessage;
        int retries = 0;
        int ret;
        struct net_device *ndev;
-       struct netvsc_device *net_device = hv_get_drvdata(device);
 
        ndev = net_device->ndev;
 
@@ -653,14 +662,15 @@ static void netvsc_receive_completion(void *context)
 
        /* Send a receive completion for the xfer page packet */
        if (fsend_receive_comp)
-               netvsc_send_recv_completion(device, transaction_id, status);
+               netvsc_send_recv_completion(device, net_device, transaction_id,
+                                       status);
 
 }
 
-static void netvsc_receive(struct hv_device *device,
-                           struct vmpacket_descriptor *packet)
+static void netvsc_receive(struct netvsc_device *net_device,
+                       struct hv_device *device,
+                       struct vmpacket_descriptor *packet)
 {
-       struct netvsc_device *net_device;
        struct vmtransfer_page_packet_header *vmxferpage_packet;
        struct nvsp_message *nvsp_packet;
        struct hv_netvsc_packet *netvsc_packet = NULL;
@@ -673,9 +683,6 @@ static void netvsc_receive(struct hv_device *device,
 
        LIST_HEAD(listHead);
 
-       net_device = get_inbound_net_device(device);
-       if (!net_device)
-               return;
        ndev = net_device->ndev;
 
        /*
@@ -741,7 +748,7 @@ static void netvsc_receive(struct hv_device *device,
                spin_unlock_irqrestore(&net_device->recv_pkt_list_lock,
                                       flags);
 
-               netvsc_send_recv_completion(device,
+               netvsc_send_recv_completion(device, net_device,
                                            vmxferpage_packet->d.trans_id,
                                            NVSP_STAT_FAIL);
 
@@ -800,22 +807,16 @@ static void netvsc_channel_cb(void *context)
        struct netvsc_device *net_device;
        u32 bytes_recvd;
        u64 request_id;
-       unsigned char *packet;
        struct vmpacket_descriptor *desc;
        unsigned char *buffer;
        int bufferlen = NETVSC_PACKET_SIZE;
        struct net_device *ndev;
 
-       packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char),
-                        GFP_ATOMIC);
-       if (!packet)
-               return;
-       buffer = packet;
-
        net_device = get_inbound_net_device(device);
        if (!net_device)
-               goto out;
+               return;
        ndev = net_device->ndev;
+       buffer = net_device->cb_buffer;
 
        do {
                ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen,
@@ -825,11 +826,13 @@ static void netvsc_channel_cb(void *context)
                                desc = (struct vmpacket_descriptor *)buffer;
                                switch (desc->type) {
                                case VM_PKT_COMP:
-                                       netvsc_send_completion(device, desc);
+                                       netvsc_send_completion(net_device,
+                                                               device, desc);
                                        break;
 
                                case VM_PKT_DATA_USING_XFER_PAGES:
-                                       netvsc_receive(device, desc);
+                                       netvsc_receive(net_device,
+                                                       device, desc);
                                        break;
 
                                default:
@@ -841,23 +844,16 @@ static void netvsc_channel_cb(void *context)
                                        break;
                                }
 
-                               /* reset */
-                               if (bufferlen > NETVSC_PACKET_SIZE) {
-                                       kfree(buffer);
-                                       buffer = packet;
-                                       bufferlen = NETVSC_PACKET_SIZE;
-                               }
                        } else {
-                               /* reset */
-                               if (bufferlen > NETVSC_PACKET_SIZE) {
-                                       kfree(buffer);
-                                       buffer = packet;
-                                       bufferlen = NETVSC_PACKET_SIZE;
-                               }
-
+                               /*
+                                * We are done for this pass.
+                                */
                                break;
                        }
+
                } else if (ret == -ENOBUFS) {
+                       if (bufferlen > NETVSC_PACKET_SIZE)
+                               kfree(buffer);
                        /* Handle large packet */
                        buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
                        if (buffer == NULL) {
@@ -872,8 +868,8 @@ static void netvsc_channel_cb(void *context)
                }
        } while (1);
 
-out:
-       kfree(buffer);
+       if (bufferlen > NETVSC_PACKET_SIZE)
+               kfree(buffer);
        return;
 }
 
@@ -907,7 +903,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
        ndev = net_device->ndev;
 
        /* Initialize the NetVSC channel extension */
-       net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE;
        spin_lock_init(&net_device->recv_pkt_list_lock);
 
        INIT_LIST_HEAD(&net_device->recv_pkt_list);
index 7756118c2f0aee4c3671f45bc0bd13e15143d607..4e4cf9e0c8d7a6c6472f2dee357b8b31a814c2b8 100644 (file)
@@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net)
 {
        struct net_device_context *net_device_ctx = netdev_priv(net);
        struct hv_device *device_obj = net_device_ctx->device_ctx;
+       struct netvsc_device *nvdev;
+       struct rndis_device *rdev;
        int ret = 0;
 
+       netif_carrier_off(net);
+
        /* Open up the device */
        ret = rndis_filter_open(device_obj);
        if (ret != 0) {
@@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net)
 
        netif_start_queue(net);
 
+       nvdev = hv_get_drvdata(device_obj);
+       rdev = nvdev->extension;
+       if (!rdev->link_state)
+               netif_carrier_on(net);
+
        return ret;
 }
 
@@ -119,6 +128,27 @@ static int netvsc_close(struct net_device *net)
        return ret;
 }
 
+static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size,
+                               int pkt_type)
+{
+       struct rndis_packet *rndis_pkt;
+       struct rndis_per_packet_info *ppi;
+
+       rndis_pkt = &msg->msg.pkt;
+       rndis_pkt->data_offset += ppi_size;
+
+       ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt +
+               rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len);
+
+       ppi->size = ppi_size;
+       ppi->type = pkt_type;
+       ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
+
+       rndis_pkt->per_pkt_info_len += ppi_size;
+
+       return ppi;
+}
+
 static void netvsc_xmit_completion(void *context)
 {
        struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
@@ -131,22 +161,164 @@ static void netvsc_xmit_completion(void *context)
                dev_kfree_skb_any(skb);
 }
 
+static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
+                       struct hv_page_buffer *pb)
+{
+       int j = 0;
+
+       /* Deal with compund pages by ignoring unused part
+        * of the page.
+        */
+       page += (offset >> PAGE_SHIFT);
+       offset &= ~PAGE_MASK;
+
+       while (len > 0) {
+               unsigned long bytes;
+
+               bytes = PAGE_SIZE - offset;
+               if (bytes > len)
+                       bytes = len;
+               pb[j].pfn = page_to_pfn(page);
+               pb[j].offset = offset;
+               pb[j].len = bytes;
+
+               offset += bytes;
+               len -= bytes;
+
+               if (offset == PAGE_SIZE && len) {
+                       page++;
+                       offset = 0;
+                       j++;
+               }
+       }
+
+       return j + 1;
+}
+
+static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
+                          struct hv_page_buffer *pb)
+{
+       u32 slots_used = 0;
+       char *data = skb->data;
+       int frags = skb_shinfo(skb)->nr_frags;
+       int i;
+
+       /* The packet is laid out thus:
+        * 1. hdr
+        * 2. skb linear data
+        * 3. skb fragment data
+        */
+       if (hdr != NULL)
+               slots_used += fill_pg_buf(virt_to_page(hdr),
+                                       offset_in_page(hdr),
+                                       len, &pb[slots_used]);
+
+       slots_used += fill_pg_buf(virt_to_page(data),
+                               offset_in_page(data),
+                               skb_headlen(skb), &pb[slots_used]);
+
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+               slots_used += fill_pg_buf(skb_frag_page(frag),
+                                       frag->page_offset,
+                                       skb_frag_size(frag), &pb[slots_used]);
+       }
+       return slots_used;
+}
+
+static int count_skb_frag_slots(struct sk_buff *skb)
+{
+       int i, frags = skb_shinfo(skb)->nr_frags;
+       int pages = 0;
+
+       for (i = 0; i < frags; i++) {
+               skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+               unsigned long size = skb_frag_size(frag);
+               unsigned long offset = frag->page_offset;
+
+               /* Skip unused frames from start of page */
+               offset &= ~PAGE_MASK;
+               pages += PFN_UP(offset + size);
+       }
+       return pages;
+}
+
+static int netvsc_get_slots(struct sk_buff *skb)
+{
+       char *data = skb->data;
+       unsigned int offset = offset_in_page(data);
+       unsigned int len = skb_headlen(skb);
+       int slots;
+       int frag_slots;
+
+       slots = DIV_ROUND_UP(offset + len, PAGE_SIZE);
+       frag_slots = count_skb_frag_slots(skb);
+       return slots + frag_slots;
+}
+
+static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off)
+{
+       u32 ret_val = TRANSPORT_INFO_NOT_IP;
+
+       if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) &&
+               (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) {
+               goto not_ip;
+       }
+
+       *trans_off = skb_transport_offset(skb);
+
+       if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) {
+               struct iphdr *iphdr = ip_hdr(skb);
+
+               if (iphdr->protocol == IPPROTO_TCP)
+                       ret_val = TRANSPORT_INFO_IPV4_TCP;
+               else if (iphdr->protocol == IPPROTO_UDP)
+                       ret_val = TRANSPORT_INFO_IPV4_UDP;
+       } else {
+               if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
+                       ret_val = TRANSPORT_INFO_IPV6_TCP;
+               else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP)
+                       ret_val = TRANSPORT_INFO_IPV6_UDP;
+       }
+
+not_ip:
+       return ret_val;
+}
+
 static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
        struct net_device_context *net_device_ctx = netdev_priv(net);
        struct hv_netvsc_packet *packet;
        int ret;
-       unsigned int i, num_pages, npg_data;
-
-       /* Add multipages for skb->data and additional 2 for RNDIS */
-       npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1)
-               >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1;
-       num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2;
+       unsigned int num_data_pgs;
+       struct rndis_message *rndis_msg;
+       struct rndis_packet *rndis_pkt;
+       u32 rndis_msg_size;
+       bool isvlan;
+       struct rndis_per_packet_info *ppi;
+       struct ndis_tcp_ip_checksum_info *csum_info;
+       struct ndis_tcp_lso_info *lso_info;
+       int  hdr_offset;
+       u32 net_trans_info;
+
+
+       /* We will atmost need two pages to describe the rndis
+        * header. We can only transmit MAX_PAGE_BUFFER_COUNT number
+        * of pages in a single packet.
+        */
+       num_data_pgs = netvsc_get_slots(skb) + 2;
+       if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) {
+               netdev_err(net, "Packet too big: %u\n", skb->len);
+               dev_kfree_skb(skb);
+               net->stats.tx_dropped++;
+               return NETDEV_TX_OK;
+       }
 
        /* Allocate a netvsc packet based on # of frags. */
        packet = kzalloc(sizeof(struct hv_netvsc_packet) +
-                        (num_pages * sizeof(struct hv_page_buffer)) +
-                        sizeof(struct rndis_filter_packet) +
+                        (num_data_pgs * sizeof(struct hv_page_buffer)) +
+                        sizeof(struct rndis_message) +
                         NDIS_VLAN_PPI_SIZE, GFP_ATOMIC);
        if (!packet) {
                /* out of memory, drop packet */
@@ -159,53 +331,111 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
 
        packet->vlan_tci = skb->vlan_tci;
 
-       packet->extension = (void *)(unsigned long)packet +
+       packet->is_data_pkt = true;
+       packet->total_data_buflen = skb->len;
+
+       packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
                                sizeof(struct hv_netvsc_packet) +
-                                   (num_pages * sizeof(struct hv_page_buffer));
+                               (num_data_pgs * sizeof(struct hv_page_buffer)));
 
-       /* If the rndis msg goes beyond 1 page, we will add 1 later */
-       packet->page_buf_cnt = num_pages - 1;
+       /* Set the completion routine */
+       packet->completion.send.send_completion = netvsc_xmit_completion;
+       packet->completion.send.send_completion_ctx = packet;
+       packet->completion.send.send_completion_tid = (unsigned long)skb;
 
-       /* Initialize it from the skb */
-       packet->total_data_buflen = skb->len;
+       isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
+
+       /* Add the rndis header */
+       rndis_msg = packet->rndis_msg;
+       rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
+       rndis_msg->msg_len = packet->total_data_buflen;
+       rndis_pkt = &rndis_msg->msg.pkt;
+       rndis_pkt->data_offset = sizeof(struct rndis_packet);
+       rndis_pkt->data_len = packet->total_data_buflen;
+       rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
+
+       rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
+
+       if (isvlan) {
+               struct ndis_pkt_8021q_info *vlan;
+
+               rndis_msg_size += NDIS_VLAN_PPI_SIZE;
+               ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE,
+                                       IEEE_8021Q_INFO);
+               vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
+                                               ppi->ppi_offset);
+               vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
+               vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
+                               VLAN_PRIO_SHIFT;
+       }
+
+       net_trans_info = get_net_transport_info(skb, &hdr_offset);
+       if (net_trans_info == TRANSPORT_INFO_NOT_IP)
+               goto do_send;
+
+       /*
+        * Setup the sendside checksum offload only if this is not a
+        * GSO packet.
+        */
+       if (skb_is_gso(skb))
+               goto do_lso;
 
-       /* Start filling in the page buffers starting after RNDIS buffer. */
-       packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT;
-       packet->page_buf[1].offset
-               = (unsigned long)skb->data & (PAGE_SIZE - 1);
-       if (npg_data == 1)
-               packet->page_buf[1].len = skb_headlen(skb);
+       rndis_msg_size += NDIS_CSUM_PPI_SIZE;
+       ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE,
+                           TCPIP_CHKSUM_PKTINFO);
+
+       csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi +
+                       ppi->ppi_offset);
+
+       if (net_trans_info & (INFO_IPV4 << 16))
+               csum_info->transmit.is_ipv4 = 1;
        else
-               packet->page_buf[1].len = PAGE_SIZE
-                       - packet->page_buf[1].offset;
-
-       for (i = 2; i <= npg_data; i++) {
-               packet->page_buf[i].pfn = virt_to_phys(skb->data
-                       + PAGE_SIZE * (i-1)) >> PAGE_SHIFT;
-               packet->page_buf[i].offset = 0;
-               packet->page_buf[i].len = PAGE_SIZE;
+               csum_info->transmit.is_ipv6 = 1;
+
+       if (net_trans_info & INFO_TCP) {
+               csum_info->transmit.tcp_checksum = 1;
+               csum_info->transmit.tcp_header_offset = hdr_offset;
+       } else if (net_trans_info & INFO_UDP) {
+               csum_info->transmit.udp_checksum = 1;
        }
-       if (npg_data > 1)
-               packet->page_buf[npg_data].len = (((unsigned long)skb->data
-                       + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1;
-
-       /* Additional fragments are after SKB data */
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
-
-               packet->page_buf[i+npg_data+1].pfn =
-                       page_to_pfn(skb_frag_page(f));
-               packet->page_buf[i+npg_data+1].offset = f->page_offset;
-               packet->page_buf[i+npg_data+1].len = skb_frag_size(f);
+       goto do_send;
+
+do_lso:
+       rndis_msg_size += NDIS_LSO_PPI_SIZE;
+       ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE,
+                           TCP_LARGESEND_PKTINFO);
+
+       lso_info = (struct ndis_tcp_lso_info *)((void *)ppi +
+                       ppi->ppi_offset);
+
+       lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE;
+       if (net_trans_info & (INFO_IPV4 << 16)) {
+               lso_info->lso_v2_transmit.ip_version =
+                       NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4;
+               ip_hdr(skb)->tot_len = 0;
+               ip_hdr(skb)->check = 0;
+               tcp_hdr(skb)->check =
+               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                  ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
+       } else {
+               lso_info->lso_v2_transmit.ip_version =
+                       NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6;
+               ipv6_hdr(skb)->payload_len = 0;
+               tcp_hdr(skb)->check =
+               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                               &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
        }
+       lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset;
+       lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size;
 
-       /* Set the completion routine */
-       packet->completion.send.send_completion = netvsc_xmit_completion;
-       packet->completion.send.send_completion_ctx = packet;
-       packet->completion.send.send_completion_tid = (unsigned long)skb;
+do_send:
+       /* Start filling in the page buffers with the rndis hdr */
+       rndis_msg->msg_len += rndis_msg_size;
+       packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
+                                       skb, &packet->page_buf[0]);
+
+       ret = netvsc_send(net_device_ctx->device_ctx, packet);
 
-       ret = rndis_filter_send(net_device_ctx->device_ctx,
-                                 packet);
        if (ret == 0) {
                net->stats.tx_bytes += skb->len;
                net->stats.tx_packets++;
@@ -229,23 +459,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
        struct net_device *net;
        struct net_device_context *ndev_ctx;
        struct netvsc_device *net_device;
+       struct rndis_device *rdev;
 
        net_device = hv_get_drvdata(device_obj);
+       rdev = net_device->extension;
+
+       rdev->link_state = status != 1;
+
        net = net_device->ndev;
 
-       if (!net) {
-               netdev_err(net, "got link status but net device "
-                               "not initialized yet\n");
+       if (!net || net->reg_state != NETREG_REGISTERED)
                return;
-       }
 
+       ndev_ctx = netdev_priv(net);
        if (status == 1) {
-               netif_carrier_on(net);
-               ndev_ctx = netdev_priv(net);
                schedule_delayed_work(&ndev_ctx->dwork, 0);
                schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20));
        } else {
-               netif_carrier_off(net);
+               schedule_delayed_work(&ndev_ctx->dwork, 0);
        }
 }
 
@@ -254,7 +485,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
  * "wire" on the specified device.
  */
 int netvsc_recv_callback(struct hv_device *device_obj,
-                               struct hv_netvsc_packet *packet)
+                               struct hv_netvsc_packet *packet,
+                               struct ndis_tcp_ip_checksum_info *csum_info)
 {
        struct net_device *net;
        struct sk_buff *skb;
@@ -281,7 +513,17 @@ int netvsc_recv_callback(struct hv_device *device_obj,
                packet->total_data_buflen);
 
        skb->protocol = eth_type_trans(skb, net);
-       skb->ip_summed = CHECKSUM_NONE;
+       if (csum_info) {
+               /* We only look at the IP checksum here.
+                * Should we be dropping the packet if checksum
+                * failed? How do we deal with other checksums - TCP/UDP?
+                */
+               if (csum_info->receive.ip_checksum_succeeded)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               else
+                       skb->ip_summed = CHECKSUM_NONE;
+       }
+
        if (packet->vlan_tci & VLAN_TAG_PRESENT)
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
                                       packet->vlan_tci);
@@ -317,7 +559,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        if (nvdev == NULL || nvdev->destroy)
                return -ENODEV;
 
-       if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2)
+       if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2)
                limit = NETVSC_MTU;
 
        if (mtu < 68 || mtu > limit)
@@ -388,17 +630,35 @@ static const struct net_device_ops device_ops = {
  * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add
  * another netif_notify_peers() into a delayed work, otherwise GARP packet
  * will not be sent after quick migration, and cause network disconnection.
+ * Also, we update the carrier status here.
  */
-static void netvsc_send_garp(struct work_struct *w)
+static void netvsc_link_change(struct work_struct *w)
 {
        struct net_device_context *ndev_ctx;
        struct net_device *net;
        struct netvsc_device *net_device;
+       struct rndis_device *rdev;
+       bool notify;
+
+       rtnl_lock();
 
        ndev_ctx = container_of(w, struct net_device_context, dwork.work);
        net_device = hv_get_drvdata(ndev_ctx->device_ctx);
+       rdev = net_device->extension;
        net = net_device->ndev;
-       netdev_notify_peers(net);
+
+       if (rdev->link_state) {
+               netif_carrier_off(net);
+               notify = false;
+       } else {
+               netif_carrier_on(net);
+               notify = true;
+       }
+
+       rtnl_unlock();
+
+       if (notify)
+               netdev_notify_peers(net);
 }
 
 
@@ -414,20 +674,20 @@ static int netvsc_probe(struct hv_device *dev,
        if (!net)
                return -ENOMEM;
 
-       /* Set initial state */
        netif_carrier_off(net);
 
        net_device_ctx = netdev_priv(net);
        net_device_ctx->device_ctx = dev;
        hv_set_drvdata(dev, net);
-       INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp);
+       INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change);
        INIT_WORK(&net_device_ctx->work, do_set_multicast);
 
        net->netdev_ops = &device_ops;
 
-       /* TODO: Add GSO and Checksum offload */
-       net->hw_features = 0;
-       net->features = NETIF_F_HW_VLAN_CTAG_TX;
+       net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM |
+                               NETIF_F_TSO;
+       net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM |
+                       NETIF_F_IP_CSUM | NETIF_F_TSO;
 
        SET_ETHTOOL_OPS(net, &ethtool_ops);
        SET_NETDEV_DEV(net, &dev->device);
@@ -443,13 +703,13 @@ static int netvsc_probe(struct hv_device *dev,
        }
        memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN);
 
-       netif_carrier_on(net);
-
        ret = register_netdev(net);
        if (ret != 0) {
                pr_err("Unable to register netdev.\n");
                rndis_filter_device_remove(dev);
                free_netdev(net);
+       } else {
+               schedule_delayed_work(&net_device_ctx->dwork, 0);
        }
 
        return ret;
index 1084e5de3ceb4c805d2ef9e98b90c6d68a9a9991..4a37e3db9e32f06c1c820c66cb08d79920bf02c0 100644 (file)
@@ -58,9 +58,6 @@ struct rndis_request {
        u8 request_ext[RNDIS_EXT_LEN];
 };
 
-static void rndis_filter_send_completion(void *ctx);
-
-
 static struct rndis_device *get_rndis_device(void)
 {
        struct rndis_device *device;
@@ -243,6 +240,22 @@ static int rndis_filter_send_request(struct rndis_device *dev,
        return ret;
 }
 
+static void rndis_set_link_state(struct rndis_device *rdev,
+                                struct rndis_request *request)
+{
+       u32 link_status;
+       struct rndis_query_complete *query_complete;
+
+       query_complete = &request->response_msg.msg.query_complete;
+
+       if (query_complete->status == RNDIS_STATUS_SUCCESS &&
+           query_complete->info_buflen == sizeof(u32)) {
+               memcpy(&link_status, (void *)((unsigned long)query_complete +
+                      query_complete->info_buf_offset), sizeof(u32));
+               rdev->link_state = link_status != 0;
+       }
+}
+
 static void rndis_filter_receive_response(struct rndis_device *dev,
                                       struct rndis_message *resp)
 {
@@ -272,12 +285,16 @@ static void rndis_filter_receive_response(struct rndis_device *dev,
                    sizeof(struct rndis_message) + RNDIS_EXT_LEN) {
                        memcpy(&request->response_msg, resp,
                               resp->msg_len);
+                       if (request->request_msg.ndis_msg_type ==
+                           RNDIS_MSG_QUERY && request->request_msg.msg.
+                           query_req.oid == RNDIS_OID_GEN_MEDIA_CONNECT_STATUS)
+                               rndis_set_link_state(dev, request);
                } else {
                        netdev_err(ndev,
                                "rndis response buffer overflow "
                                "detected (size %u max %zu)\n",
                                resp->msg_len,
-                               sizeof(struct rndis_filter_packet));
+                               sizeof(struct rndis_message));
 
                        if (resp->ndis_msg_type ==
                            RNDIS_MSG_RESET_C) {
@@ -353,6 +370,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
        struct rndis_packet *rndis_pkt;
        u32 data_offset;
        struct ndis_pkt_8021q_info *vlan;
+       struct ndis_tcp_ip_checksum_info *csum_info;
 
        rndis_pkt = &msg->msg.pkt;
 
@@ -391,7 +409,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
                pkt->vlan_tci = 0;
        }
 
-       netvsc_recv_callback(dev->net_dev->dev, pkt);
+       csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
+       netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
 }
 
 int rndis_filter_receive(struct hv_device *dev,
@@ -610,6 +629,61 @@ cleanup:
        return ret;
 }
 
+int rndis_filter_set_offload_params(struct hv_device *hdev,
+                               struct ndis_offload_params *req_offloads)
+{
+       struct netvsc_device *nvdev = hv_get_drvdata(hdev);
+       struct rndis_device *rdev = nvdev->extension;
+       struct net_device *ndev = nvdev->ndev;
+       struct rndis_request *request;
+       struct rndis_set_request *set;
+       struct ndis_offload_params *offload_params;
+       struct rndis_set_complete *set_complete;
+       u32 extlen = sizeof(struct ndis_offload_params);
+       int ret, t;
+
+       request = get_rndis_request(rdev, RNDIS_MSG_SET,
+               RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
+       if (!request)
+               return -ENOMEM;
+
+       set = &request->request_msg.msg.set_req;
+       set->oid = OID_TCP_OFFLOAD_PARAMETERS;
+       set->info_buflen = extlen;
+       set->info_buf_offset = sizeof(struct rndis_set_request);
+       set->dev_vc_handle = 0;
+
+       offload_params = (struct ndis_offload_params *)((ulong)set +
+                               set->info_buf_offset);
+       *offload_params = *req_offloads;
+       offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT;
+       offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3;
+       offload_params->header.size = extlen;
+
+       ret = rndis_filter_send_request(rdev, request);
+       if (ret != 0)
+               goto cleanup;
+
+       t = wait_for_completion_timeout(&request->wait_event, 5*HZ);
+       if (t == 0) {
+               netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n");
+               /* can't put_rndis_request, since we may still receive a
+                * send-completion.
+                */
+               return -EBUSY;
+       } else {
+               set_complete = &request->response_msg.msg.set_complete;
+               if (set_complete->status != RNDIS_STATUS_SUCCESS) {
+                       netdev_err(ndev, "Fail to set MAC on host side:0x%x\n",
+                                  set_complete->status);
+                       ret = -EINVAL;
+               }
+       }
+
+cleanup:
+       put_rndis_request(rdev, request);
+       return ret;
+}
 
 static int rndis_filter_query_device_link_status(struct rndis_device *dev)
 {
@@ -620,7 +694,6 @@ static int rndis_filter_query_device_link_status(struct rndis_device *dev)
        ret = rndis_filter_query_device(dev,
                                      RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
                                      &link_status, &size);
-       dev->link_state = (link_status != 0) ? true : false;
 
        return ret;
 }
@@ -810,6 +883,7 @@ int rndis_filter_device_add(struct hv_device *dev,
        struct netvsc_device *net_device;
        struct rndis_device *rndis_device;
        struct netvsc_device_info *device_info = additional_info;
+       struct ndis_offload_params offloads;
 
        rndis_device = get_rndis_device();
        if (!rndis_device)
@@ -849,6 +923,26 @@ int rndis_filter_device_add(struct hv_device *dev,
 
        memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN);
 
+       /* Turn on the offloads; the host supports all of the relevant
+        * offloads.
+        */
+       memset(&offloads, 0, sizeof(struct ndis_offload_params));
+       /* A value of zero means "no change"; now turn on what we
+        * want.
+        */
+       offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
+       offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
+
+
+       ret = rndis_filter_set_offload_params(dev, &offloads);
+       if (ret)
+               goto err_dev_remv;
+
+
        rndis_filter_query_device_link_status(rndis_device);
 
        device_info->link_state = rndis_device->link_state;
@@ -858,6 +952,10 @@ int rndis_filter_device_add(struct hv_device *dev,
                 device_info->link_state ? "down" : "up");
 
        return ret;
+
+err_dev_remv:
+       rndis_filter_device_remove(dev);
+       return ret;
 }
 
 void rndis_filter_device_remove(struct hv_device *dev)
@@ -894,101 +992,3 @@ int rndis_filter_close(struct hv_device *dev)
 
        return rndis_filter_close_device(nvdev->extension);
 }
-
-int rndis_filter_send(struct hv_device *dev,
-                            struct hv_netvsc_packet *pkt)
-{
-       int ret;
-       struct rndis_filter_packet *filter_pkt;
-       struct rndis_message *rndis_msg;
-       struct rndis_packet *rndis_pkt;
-       u32 rndis_msg_size;
-       bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT;
-
-       /* Add the rndis header */
-       filter_pkt = (struct rndis_filter_packet *)pkt->extension;
-
-       rndis_msg = &filter_pkt->msg;
-       rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet);
-       if (isvlan)
-               rndis_msg_size += NDIS_VLAN_PPI_SIZE;
-
-       rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
-       rndis_msg->msg_len = pkt->total_data_buflen +
-                                     rndis_msg_size;
-
-       rndis_pkt = &rndis_msg->msg.pkt;
-       rndis_pkt->data_offset = sizeof(struct rndis_packet);
-       if (isvlan)
-               rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE;
-       rndis_pkt->data_len = pkt->total_data_buflen;
-
-       if (isvlan) {
-               struct rndis_per_packet_info *ppi;
-               struct ndis_pkt_8021q_info *vlan;
-
-               rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet);
-               rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE;
-
-               ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt +
-                       rndis_pkt->per_pkt_info_offset);
-               ppi->size = NDIS_VLAN_PPI_SIZE;
-               ppi->type = IEEE_8021Q_INFO;
-               ppi->ppi_offset = sizeof(struct rndis_per_packet_info);
-
-               vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi +
-                       ppi->ppi_offset);
-               vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK;
-               vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
-       }
-
-       pkt->is_data_pkt = true;
-       pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT;
-       pkt->page_buf[0].offset =
-                       (unsigned long)rndis_msg & (PAGE_SIZE-1);
-       pkt->page_buf[0].len = rndis_msg_size;
-
-       /* Add one page_buf if the rndis msg goes beyond page boundary */
-       if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) {
-               int i;
-               for (i = pkt->page_buf_cnt; i > 1; i--)
-                       pkt->page_buf[i] = pkt->page_buf[i-1];
-               pkt->page_buf_cnt++;
-               pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset;
-               pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong)
-                       rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT;
-               pkt->page_buf[1].offset = 0;
-               pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len;
-       }
-
-       /* Save the packet send completion and context */
-       filter_pkt->completion = pkt->completion.send.send_completion;
-       filter_pkt->completion_ctx =
-                               pkt->completion.send.send_completion_ctx;
-
-       /* Use ours */
-       pkt->completion.send.send_completion = rndis_filter_send_completion;
-       pkt->completion.send.send_completion_ctx = filter_pkt;
-
-       ret = netvsc_send(dev, pkt);
-       if (ret != 0) {
-               /*
-                * Reset the completion to originals to allow retries from
-                * above
-                */
-               pkt->completion.send.send_completion =
-                               filter_pkt->completion;
-               pkt->completion.send.send_completion_ctx =
-                               filter_pkt->completion_ctx;
-       }
-
-       return ret;
-}
-
-static void rndis_filter_send_completion(void *ctx)
-{
-       struct rndis_filter_packet *filter_pkt = ctx;
-
-       /* Pass it back to the original handler */
-       filter_pkt->completion(filter_pkt->completion_ctx);
-}
index 08ae4655423a6b8f7deeee92d588fa38f0ec5cf4..3e89beab64fdc87559a2b1b9e27a7e6c6ba2b04c 100644 (file)
@@ -15,9 +15,9 @@ config IEEE802154_FAKEHARD
        depends on  IEEE802154_DRIVERS
        ---help---
          Say Y here to enable the fake driver that serves as an example
-          of HardMAC device driver.
+         of HardMAC device driver.
 
-          This driver can also be built as a module. To do so say M here.
+         This driver can also be built as a module. To do so say M here.
          The module will be called 'fakehard'.
 
 config IEEE802154_FAKELB
@@ -31,17 +31,23 @@ config IEEE802154_FAKELB
          The module will be called 'fakelb'.
 
 config IEEE802154_AT86RF230
-        depends on IEEE802154_DRIVERS && MAC802154
-        tristate "AT86RF230/231 transceiver driver"
-        depends on SPI
+       depends on IEEE802154_DRIVERS && MAC802154
+       tristate "AT86RF230/231/233/212 transceiver driver"
+       depends on SPI
+       ---help---
+         Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless
+         controller.
+
+         This driver can also be built as a module. To do so, say M here.
+         the module will be called 'at86rf230'.
 
 config IEEE802154_MRF24J40
-       tristate "Microchip MRF24J40 transceiver driver"
-       depends on IEEE802154_DRIVERS && MAC802154
-       depends on SPI
-       ---help---
-         Say Y here to enable the MRF24J20 SPI 802.15.4 wireless
-         controller.
-
-         This driver can also be built as a module. To do so, say M here.
-         the module will be called 'mrf24j40'.
+       tristate "Microchip MRF24J40 transceiver driver"
+       depends on IEEE802154_DRIVERS && MAC802154
+       depends on SPI
+       ---help---
+         Say Y here to enable the MRF24J20 SPI 802.15.4 wireless
+         controller.
+
+         This driver can also be built as a module. To do so, say M here.
+         the module will be called 'mrf24j40'.
index ab31544bc25487ac82b1703beef9df6c069e615e..e8004ef73bc1c6a900f57b741d1780391cad769f 100644 (file)
 #include <linux/spi/spi.h>
 #include <linux/spi/at86rf230.h>
 #include <linux/skbuff.h>
+#include <linux/of_gpio.h>
 
 #include <net/mac802154.h>
 #include <net/wpan-phy.h>
 
 struct at86rf230_local {
        struct spi_device *spi;
-       int rstn, slp_tr, dig2;
 
        u8 part;
        u8 vers;
@@ -53,8 +53,16 @@ struct at86rf230_local {
        spinlock_t lock;
        bool irq_busy;
        bool is_tx;
+       bool tx_aret;
+
+       int rssi_base_val;
 };
 
+static bool is_rf212(struct at86rf230_local *local)
+{
+       return local->part == 7;
+}
+
 #define        RG_TRX_STATUS   (0x01)
 #define        SR_TRX_STATUS           0x01, 0x1f, 0
 #define        SR_RESERVED_01_3        0x01, 0x20, 5
@@ -100,7 +108,10 @@ struct at86rf230_local {
 #define        SR_SFD_VALUE            0x0b, 0xff, 0
 #define        RG_TRX_CTRL_2   (0x0c)
 #define        SR_OQPSK_DATA_RATE      0x0c, 0x03, 0
-#define        SR_RESERVED_0c_2        0x0c, 0x7c, 2
+#define        SR_SUB_MODE             0x0c, 0x04, 2
+#define        SR_BPSK_QPSK            0x0c, 0x08, 3
+#define        SR_OQPSK_SUB1_RC_EN     0x0c, 0x10, 4
+#define        SR_RESERVED_0c_5        0x0c, 0x60, 5
 #define        SR_RX_SAFE_MODE         0x0c, 0x80, 7
 #define        RG_ANT_DIV      (0x0d)
 #define        SR_ANT_CTRL             0x0d, 0x03, 0
@@ -145,7 +156,7 @@ struct at86rf230_local {
 #define        SR_RESERVED_17_5        0x17, 0x08, 3
 #define        SR_AACK_UPLD_RES_FT     0x17, 0x10, 4
 #define        SR_AACK_FLTR_RES_FT     0x17, 0x20, 5
-#define        SR_RESERVED_17_2        0x17, 0x40, 6
+#define        SR_CSMA_LBT_MODE        0x17, 0x40, 6
 #define        SR_RESERVED_17_1        0x17, 0x80, 7
 #define        RG_FTN_CTRL     (0x18)
 #define        SR_RESERVED_18_2        0x18, 0x7f, 0
@@ -234,6 +245,7 @@ struct at86rf230_local {
 #define STATE_TX_ON            0x09
 /* 0x0a - 0x0e */                      /* 0x0a - UNSUPPORTED_ATTRIBUTE */
 #define STATE_SLEEP            0x0F
+#define STATE_PREP_DEEP_SLEEP  0x10
 #define STATE_BUSY_RX_AACK     0x11
 #define STATE_BUSY_TX_ARET     0x12
 #define STATE_RX_AACK_ON       0x16
@@ -243,6 +255,57 @@ struct at86rf230_local {
 #define STATE_BUSY_RX_AACK_NOCLK 0x1E
 #define STATE_TRANSITION_IN_PROGRESS 0x1F
 
+static int
+__at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part,
+               u8 *version)
+{
+       u8 data[4];
+       u8 *buf = kmalloc(2, GFP_KERNEL);
+       int status;
+       struct spi_message msg;
+       struct spi_transfer xfer = {
+               .len    = 2,
+               .tx_buf = buf,
+               .rx_buf = buf,
+       };
+       u8 reg;
+
+       if (!buf)
+               return -ENOMEM;
+
+       for (reg = RG_PART_NUM; reg <= RG_MAN_ID_1; reg++) {
+               buf[0] = (reg & CMD_REG_MASK) | CMD_REG;
+               buf[1] = 0xff;
+               dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]);
+               spi_message_init(&msg);
+               spi_message_add_tail(&xfer, &msg);
+
+               status = spi_sync(spi, &msg);
+               dev_vdbg(&spi->dev, "status = %d\n", status);
+               if (msg.status)
+                       status = msg.status;
+
+               dev_vdbg(&spi->dev, "status = %d\n", status);
+               dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]);
+               dev_vdbg(&spi->dev, "buf[1] = %02x\n", buf[1]);
+
+               if (status == 0)
+                       data[reg - RG_PART_NUM] = buf[1];
+               else
+                       break;
+       }
+
+       if (status == 0) {
+               *part = data[0];
+               *version = data[1];
+               *man_id = (data[3] << 8) | data[2];
+       }
+
+       kfree(buf);
+
+       return status;
+}
+
 static int
 __at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data)
 {
@@ -489,7 +552,9 @@ at86rf230_state(struct ieee802154_dev *dev, int state)
        } while (val == STATE_TRANSITION_IN_PROGRESS);
 
 
-       if (val == desired_status)
+       if (val == desired_status ||
+           (desired_status == STATE_RX_ON && val == STATE_BUSY_RX) ||
+           (desired_status == STATE_RX_AACK_ON && val == STATE_BUSY_RX_AACK))
                return 0;
 
        pr_err("unexpected state change: %d, asked for %d\n", val, state);
@@ -510,7 +575,11 @@ at86rf230_start(struct ieee802154_dev *dev)
        if (rc)
                return rc;
 
-       return at86rf230_state(dev, STATE_RX_ON);
+       rc = at86rf230_state(dev, STATE_TX_ON);
+       if (rc)
+               return rc;
+
+       return at86rf230_state(dev, STATE_RX_AACK_ON);
 }
 
 static void
@@ -519,6 +588,39 @@ at86rf230_stop(struct ieee802154_dev *dev)
        at86rf230_state(dev, STATE_FORCE_TRX_OFF);
 }
 
+static int
+at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel)
+{
+       lp->rssi_base_val = -91;
+
+       return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+}
+
+static int
+at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel)
+{
+       int rc;
+
+       if (channel == 0)
+               rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0);
+       else
+               rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1);
+       if (rc < 0)
+               return rc;
+
+       if (page == 0) {
+               rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0);
+               lp->rssi_base_val = -100;
+       } else {
+               rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1);
+               lp->rssi_base_val = -98;
+       }
+       if (rc < 0)
+               return rc;
+
+       return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+}
+
 static int
 at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
 {
@@ -527,14 +629,22 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel)
 
        might_sleep();
 
-       if (page != 0 || channel < 11 || channel > 26) {
+       if (page < 0 || page > 31 ||
+           !(lp->dev->phy->channels_supported[page] & BIT(channel))) {
                WARN_ON(1);
                return -EINVAL;
        }
 
-       rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel);
+       if (is_rf212(lp))
+               rc = at86rf212_set_channel(lp, page, channel);
+       else
+               rc = at86rf230_set_channel(lp, page, channel);
+       if (rc < 0)
+               return rc;
+
        msleep(1); /* Wait for PLL */
        dev->phy->current_channel = channel;
+       dev->phy->current_page = page;
 
        return 0;
 }
@@ -546,12 +656,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        int rc;
        unsigned long flags;
 
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        if  (lp->irq_busy) {
-               spin_unlock(&lp->lock);
+               spin_unlock_irqrestore(&lp->lock, flags);
                return -EBUSY;
        }
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        might_sleep();
 
@@ -568,6 +678,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb)
        if (rc)
                goto err_rx;
 
+       if (lp->tx_aret) {
+               rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ARET_ON);
+               if (rc)
+                       goto err_rx;
+       }
+
        rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX);
        if (rc)
                goto err_rx;
@@ -630,30 +746,31 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
        struct at86rf230_local *lp = dev->priv;
 
        if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
+               u16 addr = le16_to_cpu(filt->short_addr);
+
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for saddr\n");
-               __at86rf230_write(lp, RG_SHORT_ADDR_0, filt->short_addr);
-               __at86rf230_write(lp, RG_SHORT_ADDR_1, filt->short_addr >> 8);
+               __at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
+               __at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
        }
 
        if (changed & IEEE802515_AFILT_PANID_CHANGED) {
+               u16 pan = le16_to_cpu(filt->pan_id);
+
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for pan id\n");
-               __at86rf230_write(lp, RG_PAN_ID_0, filt->pan_id);
-               __at86rf230_write(lp, RG_PAN_ID_1, filt->pan_id >> 8);
+               __at86rf230_write(lp, RG_PAN_ID_0, pan);
+               __at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
        }
 
        if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
+               u8 i, addr[8];
+
+               memcpy(addr, &filt->ieee_addr, 8);
                dev_vdbg(&lp->spi->dev,
                        "at86rf230_set_hw_addr_filt called for IEEE addr\n");
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_0, filt->ieee_addr[7]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_1, filt->ieee_addr[6]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_2, filt->ieee_addr[5]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_3, filt->ieee_addr[4]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_4, filt->ieee_addr[3]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_5, filt->ieee_addr[2]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_6, filt->ieee_addr[1]);
-               at86rf230_write_subreg(lp, SR_IEEE_ADDR_7, filt->ieee_addr[0]);
+               for (i = 0; i < 8; i++)
+                       __at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
        }
 
        if (changed & IEEE802515_AFILT_PANC_CHANGED) {
@@ -668,6 +785,93 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev,
        return 0;
 }
 
+static int
+at86rf212_set_txpower(struct ieee802154_dev *dev, int db)
+{
+       struct at86rf230_local *lp = dev->priv;
+
+       /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five
+        * bits decrease power in 1dB steps. 0x60 represents extra PA gain of
+        * 0dB.
+        * thus, supported values for db range from -26 to 5, for 31dB of
+        * reduction to 0dB of reduction.
+        */
+       if (db > 5 || db < -26)
+               return -EINVAL;
+
+       db = -(db - 5);
+
+       return __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db);
+}
+
+static int
+at86rf212_set_lbt(struct ieee802154_dev *dev, bool on)
+{
+       struct at86rf230_local *lp = dev->priv;
+
+       return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
+}
+
+static int
+at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode)
+{
+       struct at86rf230_local *lp = dev->priv;
+
+       return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
+}
+
+static int
+at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level)
+{
+       struct at86rf230_local *lp = dev->priv;
+       int desens_steps;
+
+       if (level < lp->rssi_base_val || level > 30)
+               return -EINVAL;
+
+       desens_steps = (level - lp->rssi_base_val) * 100 / 207;
+
+       return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps);
+}
+
+static int
+at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
+                         u8 retries)
+{
+       struct at86rf230_local *lp = dev->priv;
+       int rc;
+
+       if (min_be > max_be || max_be > 8 || retries > 5)
+               return -EINVAL;
+
+       rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be);
+       if (rc)
+               return rc;
+
+       rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be);
+       if (rc)
+               return rc;
+
+       return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, max_be);
+}
+
+static int
+at86rf212_set_frame_retries(struct ieee802154_dev *dev, s8 retries)
+{
+       struct at86rf230_local *lp = dev->priv;
+       int rc = 0;
+
+       if (retries < -1 || retries > 15)
+               return -EINVAL;
+
+       lp->tx_aret = retries >= 0;
+
+       if (retries >= 0)
+               rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries);
+
+       return rc;
+}
+
 static struct ieee802154_ops at86rf230_ops = {
        .owner = THIS_MODULE,
        .xmit = at86rf230_xmit,
@@ -678,6 +882,22 @@ static struct ieee802154_ops at86rf230_ops = {
        .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
 };
 
+static struct ieee802154_ops at86rf212_ops = {
+       .owner = THIS_MODULE,
+       .xmit = at86rf230_xmit,
+       .ed = at86rf230_ed,
+       .set_channel = at86rf230_channel,
+       .start = at86rf230_start,
+       .stop = at86rf230_stop,
+       .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
+       .set_txpower = at86rf212_set_txpower,
+       .set_lbt = at86rf212_set_lbt,
+       .set_cca_mode = at86rf212_set_cca_mode,
+       .set_cca_ed_level = at86rf212_set_cca_ed_level,
+       .set_csma_params = at86rf212_set_csma_params,
+       .set_frame_retries = at86rf212_set_frame_retries,
+};
+
 static void at86rf230_irqwork(struct work_struct *work)
 {
        struct at86rf230_local *lp =
@@ -695,8 +915,8 @@ static void at86rf230_irqwork(struct work_struct *work)
        status &= ~IRQ_TRX_UR; /* FIXME: possibly handle ???*/
 
        if (status & IRQ_TRX_END) {
-               spin_lock_irqsave(&lp->lock, flags);
                status &= ~IRQ_TRX_END;
+               spin_lock_irqsave(&lp->lock, flags);
                if (lp->is_tx) {
                        lp->is_tx = 0;
                        spin_unlock_irqrestore(&lp->lock, flags);
@@ -725,10 +945,11 @@ static void at86rf230_irqwork_level(struct work_struct *work)
 static irqreturn_t at86rf230_isr(int irq, void *data)
 {
        struct at86rf230_local *lp = data;
+       unsigned long flags;
 
-       spin_lock(&lp->lock);
+       spin_lock_irqsave(&lp->lock, flags);
        lp->irq_busy = 1;
-       spin_unlock(&lp->lock);
+       spin_unlock_irqrestore(&lp->lock, flags);
 
        schedule_work(&lp->irqwork);
 
@@ -752,22 +973,15 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
        struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data;
        int rc, irq_pol;
        u8 status;
+       u8 csma_seed[2];
 
        rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
        if (rc)
                return rc;
 
-       dev_info(&lp->spi->dev, "Status: %02x\n", status);
-       if (status == STATE_P_ON) {
-               rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF);
-               if (rc)
-                       return rc;
-               msleep(1);
-               rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
-               if (rc)
-                       return rc;
-               dev_info(&lp->spi->dev, "Status: %02x\n", status);
-       }
+       rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF);
+       if (rc)
+               return rc;
 
        /* configure irq polarity, defaults to high active */
        if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW))
@@ -783,6 +997,14 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
        if (rc)
                return rc;
 
+       get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed));
+       rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]);
+       if (rc)
+               return rc;
+       rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]);
+       if (rc)
+               return rc;
+
        /* CLKM changes are applied immediately */
        rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00);
        if (rc)
@@ -795,16 +1017,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
        /* Wait the next SLEEP cycle */
        msleep(100);
 
-       rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON);
-       if (rc)
-               return rc;
-       msleep(1);
-
-       rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status);
-       if (rc)
-               return rc;
-       dev_info(&lp->spi->dev, "Status: %02x\n", status);
-
        rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status);
        if (rc)
                return rc;
@@ -824,14 +1036,38 @@ static int at86rf230_hw_init(struct at86rf230_local *lp)
        return 0;
 }
 
-static void at86rf230_fill_data(struct spi_device *spi)
+static struct at86rf230_platform_data *
+at86rf230_get_pdata(struct spi_device *spi)
 {
-       struct at86rf230_local *lp = spi_get_drvdata(spi);
-       struct at86rf230_platform_data *pdata = spi->dev.platform_data;
+       struct at86rf230_platform_data *pdata;
+       const char *irq_type;
+
+       if (!IS_ENABLED(CONFIG_OF) || !spi->dev.of_node)
+               return spi->dev.platform_data;
+
+       pdata = devm_kzalloc(&spi->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               goto done;
+
+       pdata->rstn = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0);
+       pdata->slp_tr = of_get_named_gpio(spi->dev.of_node, "sleep-gpio", 0);
+
+       pdata->irq_type = IRQF_TRIGGER_RISING;
+       of_property_read_string(spi->dev.of_node, "irq-type", &irq_type);
+       if (!strcmp(irq_type, "level-high"))
+               pdata->irq_type = IRQF_TRIGGER_HIGH;
+       else if (!strcmp(irq_type, "level-low"))
+               pdata->irq_type = IRQF_TRIGGER_LOW;
+       else if (!strcmp(irq_type, "edge-rising"))
+               pdata->irq_type = IRQF_TRIGGER_RISING;
+       else if (!strcmp(irq_type, "edge-falling"))
+               pdata->irq_type = IRQF_TRIGGER_FALLING;
+       else
+               dev_warn(&spi->dev, "wrong irq-type specified using edge-rising\n");
 
-       lp->rstn = pdata->rstn;
-       lp->slp_tr = pdata->slp_tr;
-       lp->dig2 = pdata->dig2;
+       spi->dev.platform_data = pdata;
+done:
+       return pdata;
 }
 
 static int at86rf230_probe(struct spi_device *spi)
@@ -839,133 +1075,146 @@ static int at86rf230_probe(struct spi_device *spi)
        struct at86rf230_platform_data *pdata;
        struct ieee802154_dev *dev;
        struct at86rf230_local *lp;
-       u8 man_id_0, man_id_1, status;
+       u16 man_id = 0;
+       u8 part = 0, version = 0, status;
        irq_handler_t irq_handler;
        work_func_t irq_worker;
-       int rc, supported = 0;
+       int rc;
        const char *chip;
+       struct ieee802154_ops *ops = NULL;
 
        if (!spi->irq) {
                dev_err(&spi->dev, "no IRQ specified\n");
                return -EINVAL;
        }
 
-       pdata = spi->dev.platform_data;
+       pdata = at86rf230_get_pdata(spi);
        if (!pdata) {
                dev_err(&spi->dev, "no platform_data\n");
                return -EINVAL;
        }
 
-       dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops);
-       if (!dev)
-               return -ENOMEM;
-
-       lp = dev->priv;
-       lp->dev = dev;
-
-       lp->spi = spi;
-
-       dev->parent = &spi->dev;
-       dev->extra_tx_headroom = 0;
-       /* We do support only 2.4 Ghz */
-       dev->phy->channels_supported[0] = 0x7FFF800;
-       dev->flags = IEEE802154_HW_OMIT_CKSUM;
-
-       if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-               irq_worker = at86rf230_irqwork;
-               irq_handler = at86rf230_isr;
-       } else {
-               irq_worker = at86rf230_irqwork_level;
-               irq_handler = at86rf230_isr_level;
+       if (gpio_is_valid(pdata->rstn)) {
+               rc = gpio_request(pdata->rstn, "rstn");
+               if (rc)
+                       return rc;
        }
 
-       mutex_init(&lp->bmux);
-       INIT_WORK(&lp->irqwork, irq_worker);
-       spin_lock_init(&lp->lock);
-       init_completion(&lp->tx_complete);
-
-       spi_set_drvdata(spi, lp);
-
-       at86rf230_fill_data(spi);
-
-       rc = gpio_request(lp->rstn, "rstn");
-       if (rc)
-               goto err_rstn;
-
-       if (gpio_is_valid(lp->slp_tr)) {
-               rc = gpio_request(lp->slp_tr, "slp_tr");
+       if (gpio_is_valid(pdata->slp_tr)) {
+               rc = gpio_request(pdata->slp_tr, "slp_tr");
                if (rc)
                        goto err_slp_tr;
        }
 
-       rc = gpio_direction_output(lp->rstn, 1);
-       if (rc)
-               goto err_gpio_dir;
+       if (gpio_is_valid(pdata->rstn)) {
+               rc = gpio_direction_output(pdata->rstn, 1);
+               if (rc)
+                       goto err_gpio_dir;
+       }
 
-       if (gpio_is_valid(lp->slp_tr)) {
-               rc = gpio_direction_output(lp->slp_tr, 0);
+       if (gpio_is_valid(pdata->slp_tr)) {
+               rc = gpio_direction_output(pdata->slp_tr, 0);
                if (rc)
                        goto err_gpio_dir;
        }
 
        /* Reset */
-       msleep(1);
-       gpio_set_value(lp->rstn, 0);
-       msleep(1);
-       gpio_set_value(lp->rstn, 1);
-       msleep(1);
+       if (gpio_is_valid(pdata->rstn)) {
+               udelay(1);
+               gpio_set_value(pdata->rstn, 0);
+               udelay(1);
+               gpio_set_value(pdata->rstn, 1);
+               usleep_range(120, 240);
+       }
 
-       rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0);
-       if (rc)
-               goto err_gpio_dir;
-       rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1);
-       if (rc)
+       rc = __at86rf230_detect_device(spi, &man_id, &part, &version);
+       if (rc < 0)
                goto err_gpio_dir;
 
-       if (man_id_1 != 0x00 || man_id_0 != 0x1f) {
+       if (man_id != 0x001f) {
                dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n",
-                       man_id_1, man_id_0);
+                       man_id >> 8, man_id & 0xFF);
                rc = -EINVAL;
                goto err_gpio_dir;
        }
 
-       rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part);
-       if (rc)
-               goto err_gpio_dir;
-
-       rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers);
-       if (rc)
-               goto err_gpio_dir;
-
-       switch (lp->part) {
+       switch (part) {
        case 2:
                chip = "at86rf230";
-               /* supported = 1;  FIXME: should be easy to support; */
+               /* FIXME: should be easy to support; */
                break;
        case 3:
                chip = "at86rf231";
-               supported = 1;
+               ops = &at86rf230_ops;
+               break;
+       case 7:
+               chip = "at86rf212";
+               if (version == 1)
+                       ops = &at86rf212_ops;
+               break;
+       case 11:
+               chip = "at86rf233";
+               ops = &at86rf230_ops;
                break;
        default:
                chip = "UNKNOWN";
                break;
        }
 
-       dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers);
-       if (!supported) {
+       dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version);
+       if (!ops) {
                rc = -ENOTSUPP;
                goto err_gpio_dir;
        }
 
+       dev = ieee802154_alloc_device(sizeof(*lp), ops);
+       if (!dev) {
+               rc = -ENOMEM;
+               goto err_gpio_dir;
+       }
+
+       lp = dev->priv;
+       lp->dev = dev;
+       lp->part = part;
+       lp->vers = version;
+
+       lp->spi = spi;
+
+       dev->parent = &spi->dev;
+       dev->extra_tx_headroom = 0;
+       dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK;
+
+       if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+               irq_worker = at86rf230_irqwork;
+               irq_handler = at86rf230_isr;
+       } else {
+               irq_worker = at86rf230_irqwork_level;
+               irq_handler = at86rf230_isr_level;
+       }
+
+       mutex_init(&lp->bmux);
+       INIT_WORK(&lp->irqwork, irq_worker);
+       spin_lock_init(&lp->lock);
+       init_completion(&lp->tx_complete);
+
+       spi_set_drvdata(spi, lp);
+
+       if (is_rf212(lp)) {
+               dev->phy->channels_supported[0] = 0x00007FF;
+               dev->phy->channels_supported[2] = 0x00007FF;
+       } else {
+               dev->phy->channels_supported[0] = 0x7FFF800;
+       }
+
        rc = at86rf230_hw_init(lp);
        if (rc)
-               goto err_gpio_dir;
+               goto err_hw_init;
 
        rc = request_irq(spi->irq, irq_handler,
                         IRQF_SHARED | pdata->irq_type,
                         dev_name(&spi->dev), lp);
        if (rc)
-               goto err_gpio_dir;
+               goto err_hw_init;
 
        /* Read irq status register to reset irq line */
        rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status);
@@ -980,30 +1229,35 @@ static int at86rf230_probe(struct spi_device *spi)
 
 err_irq:
        free_irq(spi->irq, lp);
+err_hw_init:
        flush_work(&lp->irqwork);
-err_gpio_dir:
-       if (gpio_is_valid(lp->slp_tr))
-               gpio_free(lp->slp_tr);
-err_slp_tr:
-       gpio_free(lp->rstn);
-err_rstn:
+       spi_set_drvdata(spi, NULL);
        mutex_destroy(&lp->bmux);
        ieee802154_free_device(lp->dev);
+
+err_gpio_dir:
+       if (gpio_is_valid(pdata->slp_tr))
+               gpio_free(pdata->slp_tr);
+err_slp_tr:
+       if (gpio_is_valid(pdata->rstn))
+               gpio_free(pdata->rstn);
        return rc;
 }
 
 static int at86rf230_remove(struct spi_device *spi)
 {
        struct at86rf230_local *lp = spi_get_drvdata(spi);
+       struct at86rf230_platform_data *pdata = spi->dev.platform_data;
 
        ieee802154_unregister_device(lp->dev);
 
        free_irq(spi->irq, lp);
        flush_work(&lp->irqwork);
 
-       if (gpio_is_valid(lp->slp_tr))
-               gpio_free(lp->slp_tr);
-       gpio_free(lp->rstn);
+       if (gpio_is_valid(pdata->slp_tr))
+               gpio_free(pdata->slp_tr);
+       if (gpio_is_valid(pdata->rstn))
+               gpio_free(pdata->rstn);
 
        mutex_destroy(&lp->bmux);
        ieee802154_free_device(lp->dev);
@@ -1012,8 +1266,19 @@ static int at86rf230_remove(struct spi_device *spi)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_OF)
+static struct of_device_id at86rf230_of_match[] = {
+       { .compatible = "atmel,at86rf230", },
+       { .compatible = "atmel,at86rf231", },
+       { .compatible = "atmel,at86rf233", },
+       { .compatible = "atmel,at86rf212", },
+       { },
+};
+#endif
+
 static struct spi_driver at86rf230_driver = {
        .driver = {
+               .of_match_table = of_match_ptr(at86rf230_of_match),
                .name   = "at86rf230",
                .owner  = THIS_MODULE,
        },
index bf0d55e2dd635613c3712b5b73ab528217e5cff7..78f18be3bbf2a76b7c245abef4aabd34faf3c72f 100644 (file)
@@ -63,11 +63,11 @@ static struct wpan_phy *fake_get_phy(const struct net_device *dev)
  *
  * Return the ID of the PAN from the PIB.
  */
-static u16 fake_get_pan_id(const struct net_device *dev)
+static __le16 fake_get_pan_id(const struct net_device *dev)
 {
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return 0xeba1;
+       return cpu_to_le16(0xeba1);
 }
 
 /**
@@ -78,11 +78,11 @@ static u16 fake_get_pan_id(const struct net_device *dev)
  * device. If the device has not yet had a short address assigned
  * then this should return 0xFFFF to indicate a lack of association.
  */
-static u16 fake_get_short_addr(const struct net_device *dev)
+static __le16 fake_get_short_addr(const struct net_device *dev)
 {
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
-       return 0x1;
+       return cpu_to_le16(0x1);
 }
 
 /**
@@ -149,7 +149,7 @@ static int fake_assoc_req(struct net_device *dev,
  *       802.15.4-2006 document.
  */
 static int fake_assoc_resp(struct net_device *dev,
-               struct ieee802154_addr *addr, u16 short_addr, u8 status)
+               struct ieee802154_addr *addr, __le16 short_addr, u8 status)
 {
        return 0;
 }
@@ -191,10 +191,10 @@ static int fake_disassoc_req(struct net_device *dev,
  * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006
  * document, with 7.3.8 describing coordinator realignment.
  */
-static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
-                               u8 channel, u8 page,
-                               u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
-                               u8 coord_realign)
+static int fake_start_req(struct net_device *dev,
+                         struct ieee802154_addr *addr, u8 channel, u8 page,
+                         u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
+                         u8 coord_realign)
 {
        struct wpan_phy *phy = fake_to_phy(dev);
 
@@ -281,8 +281,8 @@ static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr,
        switch (cmd) {
        case SIOCGIFADDR:
                /* FIXME: fixed here, get from device IRL */
-               pan_id = fake_get_pan_id(dev);
-               short_addr = fake_get_short_addr(dev);
+               pan_id = le16_to_cpu(fake_get_pan_id(dev));
+               short_addr = le16_to_cpu(fake_get_short_addr(dev));
                if (pan_id == IEEE802154_PANID_BROADCAST ||
                    short_addr == IEEE802154_ADDR_BROADCAST)
                        return -EADDRNOTAVAIL;
index 246befa4ba0571383f13cbdef2a701156b0326d0..78a6552ed7072d04672b98d7731c0ffd4af6117b 100644 (file)
@@ -465,8 +465,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
        if (changed & IEEE802515_AFILT_SADDR_CHANGED) {
                /* Short Addr */
                u8 addrh, addrl;
-               addrh = filt->short_addr >> 8 & 0xff;
-               addrl = filt->short_addr & 0xff;
+               addrh = le16_to_cpu(filt->short_addr) >> 8 & 0xff;
+               addrl = le16_to_cpu(filt->short_addr) & 0xff;
 
                write_short_reg(devrec, REG_SADRH, addrh);
                write_short_reg(devrec, REG_SADRL, addrl);
@@ -476,15 +476,16 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
 
        if (changed & IEEE802515_AFILT_IEEEADDR_CHANGED) {
                /* Device Address */
-               int i;
+               u8 i, addr[8];
+
+               memcpy(addr, &filt->ieee_addr, 8);
                for (i = 0; i < 8; i++)
-                       write_short_reg(devrec, REG_EADR0+i,
-                                       filt->ieee_addr[7-i]);
+                       write_short_reg(devrec, REG_EADR0 + i, addr[i]);
 
 #ifdef DEBUG
                printk(KERN_DEBUG "Set long addr to: ");
                for (i = 0; i < 8; i++)
-                       printk("%02hhx ", filt->ieee_addr[i]);
+                       printk("%02hhx ", addr[7 - i]);
                printk(KERN_DEBUG "\n");
 #endif
        }
@@ -492,8 +493,8 @@ static int mrf24j40_filter(struct ieee802154_dev *dev,
        if (changed & IEEE802515_AFILT_PANID_CHANGED) {
                /* PAN ID */
                u8 panidl, panidh;
-               panidh = filt->pan_id >> 8 & 0xff;
-               panidl = filt->pan_id & 0xff;
+               panidh = le16_to_cpu(filt->pan_id) >> 8 & 0xff;
+               panidl = le16_to_cpu(filt->pan_id) & 0xff;
                write_short_reg(devrec, REG_PANIDH, panidh);
                write_short_reg(devrec, REG_PANIDL, panidl);
 
index c14d39bf32d06a6f8d1b42a29b36dcd84b25c8f6..46a7790be004a7653d391ce96d51ae48975baa8c 100644 (file)
@@ -136,18 +136,18 @@ static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev,
        unsigned int start;
 
        do {
-               start = u64_stats_fetch_begin_bh(&dp->rsync);
+               start = u64_stats_fetch_begin_irq(&dp->rsync);
                stats->rx_packets = dp->rx_packets;
                stats->rx_bytes = dp->rx_bytes;
-       } while (u64_stats_fetch_retry_bh(&dp->rsync, start));
+       } while (u64_stats_fetch_retry_irq(&dp->rsync, start));
 
        do {
-               start = u64_stats_fetch_begin_bh(&dp->tsync);
+               start = u64_stats_fetch_begin_irq(&dp->tsync);
 
                stats->tx_packets = dp->tx_packets;
                stats->tx_bytes = dp->tx_bytes;
 
-       } while (u64_stats_fetch_retry_bh(&dp->tsync, start));
+       } while (u64_stats_fetch_retry_irq(&dp->tsync, start));
 
        stats->rx_dropped = dev->stats.rx_dropped;
        stats->tx_dropped = dev->stats.tx_dropped;
@@ -180,7 +180,8 @@ static void ifb_setup(struct net_device *dev)
        dev->tx_queue_len = TX_Q_LIMIT;
 
        dev->features |= IFB_FEATURES;
-       dev->vlan_features |= IFB_FEATURES;
+       dev->vlan_features |= IFB_FEATURES & ~(NETIF_F_HW_VLAN_CTAG_TX |
+                                              NETIF_F_HW_VLAN_STAG_TX);
 
        dev->flags |= IFF_NOARP;
        dev->flags &= ~IFF_MULTICAST;
index 2dc82f1d2e700be81f999d8922348dc05288c580..3da44d5d91497801a141b373c60f8cd5890a1bf9 100644 (file)
@@ -210,13 +210,6 @@ config KINGSUN_DONGLE
          To compile it as a module, choose M here: the module will be called
          kingsun-sir.
 
-config EP7211_DONGLE
-       tristate "Cirrus Logic clps711x I/R support"
-       depends on IRTTY_SIR && ARCH_CLPS711X && IRDA
-       help
-         Say Y here if you want to build support for the Cirrus logic
-         EP7211 chipset's infrared module.
-
 config KSDAZZLE_DONGLE
        tristate "KingSun Dazzle IrDA-USB dongle"
        depends on IRDA && USB
index dfc64537f62f939f537fe012382d562978348c6c..be8ab5b9a4a270eecaec815cdfaf3f03dfba9701 100644 (file)
@@ -35,7 +35,6 @@ obj-$(CONFIG_MCP2120_DONGLE)  += mcp2120-sir.o
 obj-$(CONFIG_ACT200L_DONGLE)   += act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)     += ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)  += toim3232-sir.o
-obj-$(CONFIG_EP7211_DONGLE)    += ep7211-sir.o
 obj-$(CONFIG_KINGSUN_DONGLE)   += kingsun-sir.o
 obj-$(CONFIG_KSDAZZLE_DONGLE)  += ksdazzle-sir.o
 obj-$(CONFIG_KS959_DONGLE)     += ks959-sir.o
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
deleted file mode 100644 (file)
index 5fe1f4d..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * IR port driver for the Cirrus Logic CLPS711X processors
- *
- * Copyright 2001, Blue Mug Inc.  All rights reserved.
- * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <mach/hardware.h>
-
-#include "sir-dev.h"
-
-static int clps711x_dongle_open(struct sir_dev *dev)
-{
-       unsigned int syscon;
-
-       /* Turn on the SIR encoder. */
-       syscon = clps_readl(SYSCON1);
-       syscon |= SYSCON1_SIREN;
-       clps_writel(syscon, SYSCON1);
-
-       return 0;
-}
-
-static int clps711x_dongle_close(struct sir_dev *dev)
-{
-       unsigned int syscon;
-
-       /* Turn off the SIR encoder. */
-       syscon = clps_readl(SYSCON1);
-       syscon &= ~SYSCON1_SIREN;
-       clps_writel(syscon, SYSCON1);
-
-       return 0;
-}
-
-static struct dongle_driver clps711x_dongle = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "EP7211 IR driver",
-       .type           = IRDA_EP7211_DONGLE,
-       .open           = clps711x_dongle_open,
-       .close          = clps711x_dongle_close,
-};
-
-static int clps711x_sir_probe(struct platform_device *pdev)
-{
-       return irda_register_dongle(&clps711x_dongle);
-}
-
-static int clps711x_sir_remove(struct platform_device *pdev)
-{
-       return irda_unregister_dongle(&clps711x_dongle);
-}
-
-static struct platform_driver clps711x_sir_driver = {
-       .driver = {
-               .name   = "sir-clps711x",
-               .owner  = THIS_MODULE,
-       },
-       .probe  = clps711x_sir_probe,
-       .remove = clps711x_sir_remove,
-};
-module_platform_driver(clps711x_sir_driver);
-
-MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
-MODULE_DESCRIPTION("EP7211 IR dongle driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
index 177441afeb9680de599905bf75e8c1e10a9c7e0b..24b6dddd7f2f58445af7d0c5af47d399c31ac799 100644 (file)
@@ -522,7 +522,6 @@ static void irtty_close(struct tty_struct *tty)
        sirdev_put_instance(priv->dev);
 
        /* Stop tty */
-       irtty_stop_receiver(tty, TRUE);
        clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
        if (tty->ops->stop)
                tty->ops->stop(tty);
index c5011e078e1b48f4181464009afc0fe7a1ebbd10..bb96409f8c056b85b77255f1c397edb4b28b0511 100644 (file)
@@ -111,10 +111,10 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
 
                lb_stats = per_cpu_ptr(dev->lstats, i);
                do {
-                       start = u64_stats_fetch_begin_bh(&lb_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&lb_stats->syncp);
                        tbytes = lb_stats->bytes;
                        tpackets = lb_stats->packets;
-               } while (u64_stats_fetch_retry_bh(&lb_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start));
                bytes   += tbytes;
                packets += tpackets;
        }
@@ -136,16 +136,9 @@ static const struct ethtool_ops loopback_ethtool_ops = {
 
 static int loopback_dev_init(struct net_device *dev)
 {
-       int i;
-       dev->lstats = alloc_percpu(struct pcpu_lstats);
+       dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
        if (!dev->lstats)
                return -ENOMEM;
-
-       for_each_possible_cpu(i) {
-               struct pcpu_lstats *lb_stats;
-               lb_stats = per_cpu_ptr(dev->lstats, i);
-               u64_stats_init(&lb_stats->syncp);
-       }
        return 0;
 }
 
@@ -160,6 +153,7 @@ static const struct net_device_ops loopback_ops = {
        .ndo_init      = loopback_dev_init,
        .ndo_start_xmit= loopback_xmit,
        .ndo_get_stats64 = loopback_get_stats64,
+       .ndo_set_mac_address = eth_mac_addr,
 };
 
 /*
@@ -174,6 +168,7 @@ static void loopback_setup(struct net_device *dev)
        dev->tx_queue_len       = 0;
        dev->type               = ARPHRD_LOOPBACK;      /* 0x0001*/
        dev->flags              = IFF_LOOPBACK;
+       dev->priv_flags         |= IFF_LIVE_ADDR_CHANGE;
        dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
        dev->hw_features        = NETIF_F_ALL_TSO | NETIF_F_UFO;
        dev->features           = NETIF_F_SG | NETIF_F_FRAGLIST
@@ -181,6 +176,7 @@ static void loopback_setup(struct net_device *dev)
                | NETIF_F_UFO
                | NETIF_F_HW_CSUM
                | NETIF_F_RXCSUM
+               | NETIF_F_SCTP_CSUM
                | NETIF_F_HIGHDMA
                | NETIF_F_LLTX
                | NETIF_F_NETNS_LOCAL
index 8433de4509c75a35cb65e7abdacb4f8968cb4008..753a8c23d15d9af1e138ec6fda410aeda32d288b 100644 (file)
@@ -506,6 +506,9 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
 static struct lock_class_key macvlan_netdev_xmit_lock_key;
 static struct lock_class_key macvlan_netdev_addr_lock_key;
 
+#define ALWAYS_ON_FEATURES \
+       (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX)
+
 #define MACVLAN_FEATURES \
        (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
@@ -534,28 +537,21 @@ static int macvlan_init(struct net_device *dev)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
        const struct net_device *lowerdev = vlan->lowerdev;
-       int i;
 
        dev->state              = (dev->state & ~MACVLAN_STATE_MASK) |
                                  (lowerdev->state & MACVLAN_STATE_MASK);
        dev->features           = lowerdev->features & MACVLAN_FEATURES;
-       dev->features           |= NETIF_F_LLTX;
+       dev->features           |= ALWAYS_ON_FEATURES;
        dev->gso_max_size       = lowerdev->gso_max_size;
        dev->iflink             = lowerdev->ifindex;
        dev->hard_header_len    = lowerdev->hard_header_len;
 
        macvlan_set_lockdep_class(dev);
 
-       vlan->pcpu_stats = alloc_percpu(struct vlan_pcpu_stats);
+       vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
        if (!vlan->pcpu_stats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct vlan_pcpu_stats *mvlstats;
-               mvlstats = per_cpu_ptr(vlan->pcpu_stats, i);
-               u64_stats_init(&mvlstats->syncp);
-       }
-
        return 0;
 }
 
@@ -586,13 +582,13 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
                for_each_possible_cpu(i) {
                        p = per_cpu_ptr(vlan->pcpu_stats, i);
                        do {
-                               start = u64_stats_fetch_begin_bh(&p->syncp);
+                               start = u64_stats_fetch_begin_irq(&p->syncp);
                                rx_packets      = p->rx_packets;
                                rx_bytes        = p->rx_bytes;
                                rx_multicast    = p->rx_multicast;
                                tx_packets      = p->tx_packets;
                                tx_bytes        = p->tx_bytes;
-                       } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                        stats->rx_packets       += rx_packets;
                        stats->rx_bytes         += rx_bytes;
@@ -699,7 +695,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
        features = netdev_increment_features(vlan->lowerdev->features,
                                             features,
                                             mask);
-       features |= NETIF_F_LLTX;
+       features |= ALWAYS_ON_FEATURES;
 
        return features;
 }
@@ -879,14 +875,15 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
        dev->priv_flags |= IFF_MACVLAN;
        err = netdev_upper_dev_link(lowerdev, dev);
        if (err)
-               goto destroy_port;
-
+               goto unregister_netdev;
 
        list_add_tail_rcu(&vlan->list, &port->vlans);
        netif_stacked_transfer_operstate(lowerdev, dev);
 
        return 0;
 
+unregister_netdev:
+       unregister_netdevice(dev);
 destroy_port:
        port->count -= 1;
        if (!port->count)
index d2bb12bfabd5501055dfd52760c19c598b254bc9..34924dfadd0097608dac20dcf0aced6bb1c9805e 100644 (file)
@@ -47,16 +47,7 @@ static int nlmon_change_mtu(struct net_device *dev, int new_mtu)
 
 static int nlmon_dev_init(struct net_device *dev)
 {
-       int i;
-
-       dev->lstats = alloc_percpu(struct pcpu_lstats);
-
-       for_each_possible_cpu(i) {
-               struct pcpu_lstats *nlmstats;
-               nlmstats = per_cpu_ptr(dev->lstats, i);
-               u64_stats_init(&nlmstats->syncp);
-       }
-
+       dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
        return dev->lstats == NULL ? -ENOMEM : 0;
 }
 
@@ -99,10 +90,10 @@ nlmon_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
                nl_stats = per_cpu_ptr(dev->lstats, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&nl_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&nl_stats->syncp);
                        tbytes = nl_stats->bytes;
                        tpackets = nl_stats->packets;
-               } while (u64_stats_fetch_retry_bh(&nl_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&nl_stats->syncp, start));
 
                packets += tpackets;
                bytes += tbytes;
@@ -145,7 +136,8 @@ static void nlmon_setup(struct net_device *dev)
        dev->ethtool_ops = &nlmon_ethtool_ops;
        dev->destructor = free_netdev;
 
-       dev->features = NETIF_F_FRAGLIST | NETIF_F_HIGHDMA;
+       dev->features = NETIF_F_SG | NETIF_F_FRAGLIST |
+                       NETIF_F_HIGHDMA | NETIF_F_LLTX;
        dev->flags = IFF_NOARP;
 
        /* That's rather a softlimit here, which, of course,
index 9b5d46c03eed34d244bf279ea13bf38ffebea009..6a17f92153b31b3b2fe95a5d7e087eeb3373032b 100644 (file)
@@ -71,6 +71,12 @@ config BCM63XX_PHY
        ---help---
          Currently supports the 6348 and 6358 PHYs.
 
+config BCM7XXX_PHY
+       tristate "Drivers for Broadcom 7xxx SOCs internal PHYs"
+       ---help---
+         Currently supports the BCM7366, BCM7439, BCM7445, and
+         40nm and 65nm generation of BCM7xxx Set Top Box SoCs.
+
 config BCM87XX_PHY
        tristate "Driver for Broadcom BCM8706 and BCM8727 PHYs"
        help
index 9013dfa12aa39ac7fe504734e6b3e62d7865b0d7..07d24024863e0805af4127c72e4663174a47babb 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_SMSC_PHY)                += smsc.o
 obj-$(CONFIG_VITESSE_PHY)      += vitesse.o
 obj-$(CONFIG_BROADCOM_PHY)     += broadcom.o
 obj-$(CONFIG_BCM63XX_PHY)      += bcm63xx.o
+obj-$(CONFIG_BCM7XXX_PHY)      += bcm7xxx.o
 obj-$(CONFIG_BCM87XX_PHY)      += bcm87xx.o
 obj-$(CONFIG_ICPLUS_PHY)       += icplus.o
 obj-$(CONFIG_REALTEK_PHY)      += realtek.o
index bc71947b1ec329f2eacd52b915b37ce56a4f16bb..643464d5a727b3b937fbe803072861de15a1414f 100644 (file)
@@ -27,6 +27,9 @@
 #define AT803X_MMD_ACCESS_CONTROL              0x0D
 #define AT803X_MMD_ACCESS_CONTROL_DATA         0x0E
 #define AT803X_FUNC_DATA                       0x4003
+#define AT803X_INER                            0x0012
+#define AT803X_INER_INIT                       0xec00
+#define AT803X_INSR                            0x0013
 #define AT803X_DEBUG_ADDR                      0x1D
 #define AT803X_DEBUG_DATA                      0x1E
 #define AT803X_DEBUG_SYSTEM_MODE_CTRL          0x05
@@ -191,6 +194,31 @@ static int at803x_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int at803x_ack_interrupt(struct phy_device *phydev)
+{
+       int err;
+
+       err = phy_read(phydev, AT803X_INSR);
+
+       return (err < 0) ? err : 0;
+}
+
+static int at803x_config_intr(struct phy_device *phydev)
+{
+       int err;
+       int value;
+
+       value = phy_read(phydev, AT803X_INER);
+
+       if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+               err = phy_write(phydev, AT803X_INER,
+                               value | AT803X_INER_INIT);
+       else
+               err = phy_write(phydev, AT803X_INER, 0);
+
+       return err;
+}
+
 static struct phy_driver at803x_driver[] = {
 {
        /* ATHEROS 8035 */
@@ -240,6 +268,8 @@ static struct phy_driver at803x_driver[] = {
        .flags          = PHY_HAS_INTERRUPT,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
+       .ack_interrupt  = &at803x_ack_interrupt,
+       .config_intr    = &at803x_config_intr,
        .driver         = {
                .owner = THIS_MODULE,
        },
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
new file mode 100644 (file)
index 0000000..526b94c
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Broadcom BCM7xxx internal transceivers support.
+ *
+ * Copyright (C) 2014, Broadcom 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.
+ */
+
+#include <linux/module.h>
+#include <linux/phy.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/brcmphy.h>
+
+/* Broadcom BCM7xxx internal PHY registers */
+#define MII_BCM7XXX_CHANNEL_WIDTH      0x2000
+
+/* 40nm only register definitions */
+#define MII_BCM7XXX_100TX_AUX_CTL      0x10
+#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_CORE_BASE1E                0x1e
+#define MII_BCM7XXX_TEST               0x1f
+#define  MII_BCM7XXX_SHD_MODE_2                BIT(2)
+
+/* 28nm only register definitions */
+#define MISC_ADDR(base, channel)       base, channel
+
+#define DSP_TAP10                      MISC_ADDR(0x0a, 0)
+#define PLL_PLLCTRL_1                  MISC_ADDR(0x32, 1)
+#define PLL_PLLCTRL_2                  MISC_ADDR(0x32, 2)
+#define PLL_PLLCTRL_4                  MISC_ADDR(0x33, 0)
+
+#define AFE_RXCONFIG_0                 MISC_ADDR(0x38, 0)
+#define AFE_RXCONFIG_1                 MISC_ADDR(0x38, 1)
+#define AFE_RX_LP_COUNTER              MISC_ADDR(0x38, 3)
+#define AFE_TX_CONFIG                  MISC_ADDR(0x39, 0)
+#define AFE_HPF_TRIM_OTHERS            MISC_ADDR(0x3a, 0)
+
+#define CORE_EXPB0                     0xb0
+
+static int bcm7445_config_init(struct phy_device *phydev)
+{
+       int ret;
+       const struct bcm7445_regs {
+               int reg;
+               u16 value;
+       } bcm7445_regs_cfg[] = {
+               /* increases ADC latency by 24ns */
+               { MII_BCM54XX_EXP_SEL, 0x0038 },
+               { MII_BCM54XX_EXP_DATA, 0xAB95 },
+               /* increases internal 1V LDO voltage by 5% */
+               { MII_BCM54XX_EXP_SEL, 0x2038 },
+               { MII_BCM54XX_EXP_DATA, 0xBB22 },
+               /* reduce RX low pass filter corner frequency */
+               { MII_BCM54XX_EXP_SEL, 0x6038 },
+               { MII_BCM54XX_EXP_DATA, 0xFFC5 },
+               /* reduce RX high pass filter corner frequency */
+               { MII_BCM54XX_EXP_SEL, 0x003a },
+               { MII_BCM54XX_EXP_DATA, 0x2002 },
+       };
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) {
+               ret = phy_write(phydev,
+                               bcm7445_regs_cfg[i].reg,
+                               bcm7445_regs_cfg[i].value);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static void phy_write_exp(struct phy_device *phydev,
+                                       u16 reg, u16 value)
+{
+       phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
+       phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
+}
+
+static void phy_write_misc(struct phy_device *phydev,
+                                       u16 reg, u16 chl, u16 value)
+{
+       int tmp;
+
+       phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
+
+       tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
+       tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
+       phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
+
+       tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
+       phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
+
+       phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
+}
+
+static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
+{
+       /* Increase VCO range to prevent unlocking problem of PLL at low
+        * temp
+        */
+       phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
+
+       /* Change Ki to 011 */
+       phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
+
+       /* Disable loading of TVCO buffer to bandgap, set bandgap trim
+        * to 111
+        */
+       phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
+
+       /* Adjust bias current trim by -3 */
+       phy_write_misc(phydev, DSP_TAP10, 0x690b);
+
+       /* Switch to CORE_BASE1E */
+       phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
+
+       /* Reset R_CAL/RC_CAL Engine */
+       phy_write_exp(phydev, CORE_EXPB0, 0x0010);
+
+       /* Disable Reset R_CAL/RC_CAL Engine */
+       phy_write_exp(phydev, CORE_EXPB0, 0x0000);
+
+       /* write AFE_RXCONFIG_0 */
+       phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
+
+       /* write AFE_RXCONFIG_1 */
+       phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
+
+       /* write AFE_RX_LP_COUNTER */
+       phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc0);
+
+       /* write AFE_HPF_TRIM_OTHERS */
+       phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
+
+       /* write AFTE_TX_CONFIG */
+       phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
+
+       return 0;
+}
+
+static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = bcm7445_config_init(phydev);
+       if (ret)
+               return ret;
+
+       return bcm7xxx_28nm_afe_config_init(phydev);
+}
+
+static int phy_set_clr_bits(struct phy_device *dev, int location,
+                                       int set_mask, int clr_mask)
+{
+       int v, ret;
+
+       v = phy_read(dev, location);
+       if (v < 0)
+               return v;
+
+       v &= ~clr_mask;
+       v |= set_mask;
+
+       ret = phy_write(dev, location, v);
+       if (ret < 0)
+               return ret;
+
+       return v;
+}
+
+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_read(phydev, MII_BCM7XXX_AUX_MODE);
+
+       /* Workaround only required for 100Mbits/sec */
+       if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR))
+               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);
+       if (ret < 0)
+               return ret;
+
+       /* set iddq_clkbias */
+       phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
+       udelay(10);
+
+       /* reset iddq_clkbias */
+       phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
+
+       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);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/* Workaround for putting the PHY in IDDQ mode, required
+ * for all BCM7XXX PHYs
+ */
+static int bcm7xxx_suspend(struct phy_device *phydev)
+{
+       int ret;
+       const struct bcm7xxx_regs {
+               int reg;
+               u16 value;
+       } bcm7xxx_suspend_cfg[] = {
+               { MII_BCM7XXX_TEST, 0x008b },
+               { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
+               { MII_BCM7XXX_100TX_DISC, 0x7000 },
+               { MII_BCM7XXX_TEST, 0x000f },
+               { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
+               { MII_BCM7XXX_TEST, 0x000b },
+       };
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
+               ret = phy_write(phydev,
+                               bcm7xxx_suspend_cfg[i].reg,
+                               bcm7xxx_suspend_cfg[i].value);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
+{
+       return 0;
+}
+
+static struct phy_driver bcm7xxx_driver[] = {
+{
+       .phy_id         = PHY_ID_BCM7366,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM7366",
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+       .flags          = PHY_IS_INTERNAL,
+       .config_init    = bcm7xxx_28nm_afe_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .suspend        = bcm7xxx_suspend,
+       .resume         = bcm7xxx_28nm_afe_config_init,
+       .driver         = { .owner = THIS_MODULE },
+}, {
+       .phy_id         = PHY_ID_BCM7439,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM7439",
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+       .flags          = PHY_IS_INTERNAL,
+       .config_init    = bcm7xxx_28nm_afe_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .suspend        = bcm7xxx_suspend,
+       .resume         = bcm7xxx_28nm_afe_config_init,
+       .driver         = { .owner = THIS_MODULE },
+}, {
+       .phy_id         = PHY_ID_BCM7445,
+       .phy_id_mask    = 0xfffffff0,
+       .name           = "Broadcom BCM7445",
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+       .flags          = PHY_IS_INTERNAL,
+       .config_init    = bcm7xxx_28nm_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .suspend        = bcm7xxx_suspend,
+       .resume         = bcm7xxx_28nm_config_init,
+       .driver         = { .owner = THIS_MODULE },
+}, {
+       .name           = "Broadcom BCM7XXX 28nm",
+       .phy_id         = PHY_ID_BCM7XXX_28,
+       .phy_id_mask    = PHY_BCM_OUI_MASK,
+       .features       = PHY_GBIT_FEATURES |
+                         SUPPORTED_Pause | SUPPORTED_Asym_Pause,
+       .flags          = PHY_IS_INTERNAL,
+       .config_init    = bcm7xxx_28nm_config_init,
+       .config_aneg    = genphy_config_aneg,
+       .read_status    = genphy_read_status,
+       .suspend        = bcm7xxx_suspend,
+       .resume         = bcm7xxx_28nm_config_init,
+       .driver         = { .owner = THIS_MODULE },
+}, {
+       .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,
+       .driver         = { .owner = THIS_MODULE },
+}, {
+       .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,
+       .driver         = { .owner = THIS_MODULE },
+} };
+
+static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+       { PHY_ID_BCM7366, 0xfffffff0, },
+       { PHY_ID_BCM7439, 0xfffffff0, },
+       { PHY_ID_BCM7445, 0xfffffff0, },
+       { PHY_ID_BCM7XXX_28, 0xfffffc00 },
+       { PHY_BCM_OUI_4, 0xffff0000 },
+       { PHY_BCM_OUI_5, 0xffffff00 },
+       { }
+};
+
+static int __init bcm7xxx_phy_init(void)
+{
+       return phy_drivers_register(bcm7xxx_driver,
+                       ARRAY_SIZE(bcm7xxx_driver));
+}
+
+static void __exit bcm7xxx_phy_exit(void)
+{
+       phy_drivers_unregister(bcm7xxx_driver,
+                       ARRAY_SIZE(bcm7xxx_driver));
+}
+
+module_init(bcm7xxx_phy_init);
+module_exit(bcm7xxx_phy_exit);
+
+MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
+
+MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom Corporation");
index f8c90ea751083456e7e07135aaa16a215e23f43b..34088d60da74613cd007916ddd4844ee5420f90a 100644 (file)
 #define BRCM_PHY_REV(phydev) \
        ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
 
-
-#define MII_BCM54XX_ECR                0x10    /* BCM54xx extended control register */
-#define MII_BCM54XX_ECR_IM     0x1000  /* Interrupt mask */
-#define MII_BCM54XX_ECR_IF     0x0800  /* Interrupt force */
-
-#define MII_BCM54XX_ESR                0x11    /* BCM54xx extended status register */
-#define MII_BCM54XX_ESR_IS     0x1000  /* Interrupt status */
-
-#define MII_BCM54XX_EXP_DATA   0x15    /* Expansion register data */
-#define MII_BCM54XX_EXP_SEL    0x17    /* Expansion register select */
-#define MII_BCM54XX_EXP_SEL_SSD        0x0e00  /* Secondary SerDes select */
-#define MII_BCM54XX_EXP_SEL_ER 0x0f00  /* Expansion register select */
-
-#define MII_BCM54XX_AUX_CTL    0x18    /* Auxiliary control register */
-#define MII_BCM54XX_ISR                0x1a    /* BCM54xx interrupt status register */
-#define MII_BCM54XX_IMR                0x1b    /* BCM54xx interrupt mask register */
-#define MII_BCM54XX_INT_CRCERR 0x0001  /* CRC error */
-#define MII_BCM54XX_INT_LINK   0x0002  /* Link status changed */
-#define MII_BCM54XX_INT_SPEED  0x0004  /* Link speed change */
-#define MII_BCM54XX_INT_DUPLEX 0x0008  /* Duplex mode changed */
-#define MII_BCM54XX_INT_LRS    0x0010  /* Local receiver status changed */
-#define MII_BCM54XX_INT_RRS    0x0020  /* Remote receiver status changed */
-#define MII_BCM54XX_INT_SSERR  0x0040  /* Scrambler synchronization error */
-#define MII_BCM54XX_INT_UHCD   0x0080  /* Unsupported HCD negotiated */
-#define MII_BCM54XX_INT_NHCD   0x0100  /* No HCD */
-#define MII_BCM54XX_INT_NHCDL  0x0200  /* No HCD link */
-#define MII_BCM54XX_INT_ANPR   0x0400  /* Auto-negotiation page received */
-#define MII_BCM54XX_INT_LC     0x0800  /* All counters below 128 */
-#define MII_BCM54XX_INT_HC     0x1000  /* Counter above 32768 */
-#define MII_BCM54XX_INT_MDIX   0x2000  /* MDIX status change */
-#define MII_BCM54XX_INT_PSERR  0x4000  /* Pair swap error */
-
-#define MII_BCM54XX_SHD                0x1c    /* 0x1c shadow registers */
-#define MII_BCM54XX_SHD_WRITE  0x8000
-#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
-#define MII_BCM54XX_SHD_DATA(x)        ((x & 0x3ff) << 0)
-
-/*
- * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
- */
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
-#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB         0x0400
-#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA      0x0800
-
-#define MII_BCM54XX_AUXCTL_MISC_WREN   0x8000
-#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX    0x0200
-#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC     0x7000
-#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC        0x0007
-
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
-
-
 /*
  * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
  * BCM5482, and possibly some others.
index 547725fa8671f5174f0ddbd0160a66ccc4144cac..352c5e45fe9cc4477286970612a15b72a1e9dd81 100644 (file)
@@ -47,6 +47,7 @@
 #define CAL_EVENT      7
 #define CAL_TRIGGER    7
 #define PER_TRIGGER    6
+#define DP83640_N_PINS 12
 
 #define MII_DP83640_MICR 0x11
 #define MII_DP83640_MISR 0x12
@@ -173,6 +174,37 @@ MODULE_PARM_DESC(chosen_phy, \
 MODULE_PARM_DESC(gpio_tab, \
        "Which GPIO line to use for which purpose: cal,perout,extts1,...,extts6");
 
+static void dp83640_gpio_defaults(struct ptp_pin_desc *pd)
+{
+       int i, index;
+
+       for (i = 0; i < DP83640_N_PINS; i++) {
+               snprintf(pd[i].name, sizeof(pd[i].name), "GPIO%d", 1 + i);
+               pd[i].index = i;
+       }
+
+       for (i = 0; i < GPIO_TABLE_SIZE; i++) {
+               if (gpio_tab[i] < 1 || gpio_tab[i] > DP83640_N_PINS) {
+                       pr_err("gpio_tab[%d]=%hu out of range", i, gpio_tab[i]);
+                       return;
+               }
+       }
+
+       index = gpio_tab[CALIBRATE_GPIO] - 1;
+       pd[index].func = PTP_PF_PHYSYNC;
+       pd[index].chan = 0;
+
+       index = gpio_tab[PEROUT_GPIO] - 1;
+       pd[index].func = PTP_PF_PEROUT;
+       pd[index].chan = 0;
+
+       for (i = EXTTS0_GPIO; i < GPIO_TABLE_SIZE; i++) {
+               index = gpio_tab[i] - 1;
+               pd[index].func = PTP_PF_EXTTS;
+               pd[index].chan = i - EXTTS0_GPIO;
+       }
+}
+
 /* a list of clocks and a mutex to protect it */
 static LIST_HEAD(phyter_clocks);
 static DEFINE_MUTEX(phyter_clocks_lock);
@@ -266,15 +298,22 @@ static u64 phy2txts(struct phy_txts *p)
        return ns;
 }
 
-static void periodic_output(struct dp83640_clock *clock,
-                           struct ptp_clock_request *clkreq, bool on)
+static int periodic_output(struct dp83640_clock *clock,
+                          struct ptp_clock_request *clkreq, bool on)
 {
        struct dp83640_private *dp83640 = clock->chosen;
        struct phy_device *phydev = dp83640->phydev;
-       u32 sec, nsec, period;
+       u32 sec, nsec, pwidth;
        u16 gpio, ptp_trig, trigger, val;
 
-       gpio = on ? gpio_tab[PEROUT_GPIO] : 0;
+       if (on) {
+               gpio = 1 + ptp_find_pin(clock->ptp_clock, PTP_PF_PEROUT, 0);
+               if (gpio < 1)
+                       return -EINVAL;
+       } else {
+               gpio = 0;
+       }
+
        trigger = PER_TRIGGER;
 
        ptp_trig = TRIG_WR |
@@ -291,13 +330,14 @@ static void periodic_output(struct dp83640_clock *clock,
                ext_write(0, phydev, PAGE5, PTP_TRIG, ptp_trig);
                ext_write(0, phydev, PAGE4, PTP_CTL, val);
                mutex_unlock(&clock->extreg_lock);
-               return;
+               return 0;
        }
 
        sec = clkreq->perout.start.sec;
        nsec = clkreq->perout.start.nsec;
-       period = clkreq->perout.period.sec * 1000000000UL;
-       period += clkreq->perout.period.nsec;
+       pwidth = clkreq->perout.period.sec * 1000000000UL;
+       pwidth += clkreq->perout.period.nsec;
+       pwidth /= 2;
 
        mutex_lock(&clock->extreg_lock);
 
@@ -310,8 +350,8 @@ static void periodic_output(struct dp83640_clock *clock,
        ext_write(0, phydev, PAGE4, PTP_TDR, nsec >> 16);      /* ns[31:16] */
        ext_write(0, phydev, PAGE4, PTP_TDR, sec & 0xffff);    /* sec[15:0] */
        ext_write(0, phydev, PAGE4, PTP_TDR, sec >> 16);       /* sec[31:16] */
-       ext_write(0, phydev, PAGE4, PTP_TDR, period & 0xffff); /* ns[15:0] */
-       ext_write(0, phydev, PAGE4, PTP_TDR, period >> 16);    /* ns[31:16] */
+       ext_write(0, phydev, PAGE4, PTP_TDR, pwidth & 0xffff); /* ns[15:0] */
+       ext_write(0, phydev, PAGE4, PTP_TDR, pwidth >> 16);    /* ns[31:16] */
 
        /*enable trigger*/
        val &= ~TRIG_LOAD;
@@ -319,6 +359,7 @@ static void periodic_output(struct dp83640_clock *clock,
        ext_write(0, phydev, PAGE4, PTP_CTL, val);
 
        mutex_unlock(&clock->extreg_lock);
+       return 0;
 }
 
 /* ptp clock methods */
@@ -424,20 +465,26 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
        struct dp83640_clock *clock =
                container_of(ptp, struct dp83640_clock, caps);
        struct phy_device *phydev = clock->chosen->phydev;
-       int index;
+       unsigned int index;
        u16 evnt, event_num, gpio_num;
 
        switch (rq->type) {
        case PTP_CLK_REQ_EXTTS:
                index = rq->extts.index;
-               if (index < 0 || index >= N_EXT_TS)
+               if (index >= N_EXT_TS)
                        return -EINVAL;
                event_num = EXT_EVENT + index;
                evnt = EVNT_WR | (event_num & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
                if (on) {
-                       gpio_num = gpio_tab[EXTTS0_GPIO + index];
+                       gpio_num = 1 + ptp_find_pin(clock->ptp_clock,
+                                                   PTP_PF_EXTTS, index);
+                       if (gpio_num < 1)
+                               return -EINVAL;
                        evnt |= (gpio_num & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
-                       evnt |= EVNT_RISE;
+                       if (rq->extts.flags & PTP_FALLING_EDGE)
+                               evnt |= EVNT_FALL;
+                       else
+                               evnt |= EVNT_RISE;
                }
                ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
                return 0;
@@ -445,8 +492,7 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
        case PTP_CLK_REQ_PEROUT:
                if (rq->perout.index != 0)
                        return -EINVAL;
-               periodic_output(clock, rq, on);
-               return 0;
+               return periodic_output(clock, rq, on);
 
        default:
                break;
@@ -455,6 +501,12 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
        return -EOPNOTSUPP;
 }
 
+static int ptp_dp83640_verify(struct ptp_clock_info *ptp, unsigned int pin,
+                             enum ptp_pin_function func, unsigned int chan)
+{
+       return 0;
+}
+
 static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 };
 static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
 
@@ -872,6 +924,7 @@ static void dp83640_free_clocks(void)
                mutex_destroy(&clock->extreg_lock);
                mutex_destroy(&clock->clock_lock);
                put_device(&clock->bus->dev);
+               kfree(clock->caps.pin_config);
                kfree(clock);
        }
 
@@ -891,12 +944,18 @@ static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
        clock->caps.n_alarm     = 0;
        clock->caps.n_ext_ts    = N_EXT_TS;
        clock->caps.n_per_out   = 1;
+       clock->caps.n_pins      = DP83640_N_PINS;
        clock->caps.pps         = 0;
        clock->caps.adjfreq     = ptp_dp83640_adjfreq;
        clock->caps.adjtime     = ptp_dp83640_adjtime;
        clock->caps.gettime     = ptp_dp83640_gettime;
        clock->caps.settime     = ptp_dp83640_settime;
        clock->caps.enable      = ptp_dp83640_enable;
+       clock->caps.verify      = ptp_dp83640_verify;
+       /*
+        * Convert the module param defaults into a dynamic pin configuration.
+        */
+       dp83640_gpio_defaults(clock->caps.pin_config);
        /*
         * Get a reference to this bus instance.
         */
@@ -947,6 +1006,13 @@ static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)
        if (!clock)
                goto out;
 
+       clock->caps.pin_config = kzalloc(sizeof(struct ptp_pin_desc) *
+                                        DP83640_N_PINS, GFP_KERNEL);
+       if (!clock->caps.pin_config) {
+               kfree(clock);
+               clock = NULL;
+               goto out;
+       }
        dp83640_clock_init(clock, bus);
        list_add_tail(&phyter_clocks, &clock->list);
 out:
@@ -1003,11 +1069,6 @@ static int dp83640_probe(struct phy_device *phydev)
        } else
                list_add_tail(&dp83640->list, &clock->phylist);
 
-       if (clock->chosen && !list_empty(&clock->phylist))
-               recalibrate(clock);
-       else
-               enable_broadcast(dp83640->phydev, clock->page, 1);
-
        dp83640_clock_put(clock);
        return 0;
 
@@ -1058,6 +1119,21 @@ static void dp83640_remove(struct phy_device *phydev)
        kfree(dp83640);
 }
 
+static int dp83640_config_init(struct phy_device *phydev)
+{
+       struct dp83640_private *dp83640 = phydev->priv;
+       struct dp83640_clock *clock = dp83640->clock;
+
+       if (clock->chosen && !list_empty(&clock->phylist))
+               recalibrate(clock);
+       else
+               enable_broadcast(phydev, clock->page, 1);
+
+       enable_status_frames(phydev, true);
+       ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+       return 0;
+}
+
 static int dp83640_ack_interrupt(struct phy_device *phydev)
 {
        int err = phy_read(phydev, MII_DP83640_MISR);
@@ -1195,11 +1271,6 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
 
        mutex_lock(&dp83640->clock->extreg_lock);
 
-       if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) {
-               enable_status_frames(phydev, true);
-               ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
-       }
-
        ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0);
        ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0);
 
@@ -1281,6 +1352,7 @@ static void dp83640_txtstamp(struct phy_device *phydev,
                }
                /* fall through */
        case HWTSTAMP_TX_ON:
+               skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
                skb_queue_tail(&dp83640->tx_queue, skb);
                schedule_work(&dp83640->ts_work);
                break;
@@ -1330,6 +1402,7 @@ static struct phy_driver dp83640_driver = {
        .flags          = PHY_HAS_INTERRUPT,
        .probe          = dp83640_probe,
        .remove         = dp83640_remove,
+       .config_init    = dp83640_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .ack_interrupt  = dp83640_ack_interrupt,
@@ -1353,7 +1426,7 @@ static void __exit dp83640_exit(void)
 }
 
 MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver");
-MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.at>");
+MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
 MODULE_LICENSE("GPL");
 
 module_init(dp83640_init);
index bb88bc7d81fb28436f7ee4094580a32e620ee705..15bc7f9ea224b44daab666cab2ff62c4e61019b5 100644 (file)
@@ -90,11 +90,6 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        return 0;
 }
 
-static int sun4i_mdio_reset(struct mii_bus *bus)
-{
-       return 0;
-}
-
 static int sun4i_mdio_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -110,7 +105,6 @@ static int sun4i_mdio_probe(struct platform_device *pdev)
        bus->name = "sun4i_mii_bus";
        bus->read = &sun4i_mdio_read;
        bus->write = &sun4i_mdio_write;
-       bus->reset = &sun4i_mdio_reset;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
        bus->parent = &pdev->dev;
 
@@ -170,6 +164,9 @@ static int sun4i_mdio_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id sun4i_mdio_dt_ids[] = {
+       { .compatible = "allwinner,sun4i-a10-mdio" },
+
+       /* Deprecated */
        { .compatible = "allwinner,sun4i-mdio" },
        { }
 };
index 71e49000fbf33fc50d08e3c6979014c89fdb4478..76f54b32a120832f2ce212c129592a6f30ab83df 100644 (file)
@@ -432,8 +432,28 @@ phy_id_show(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR_RO(phy_id);
 
+static ssize_t
+phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct phy_device *phydev = to_phy_device(dev);
+
+       return sprintf(buf, "%s\n", phy_modes(phydev->interface));
+}
+static DEVICE_ATTR_RO(phy_interface);
+
+static ssize_t
+phy_has_fixups_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct phy_device *phydev = to_phy_device(dev);
+
+       return sprintf(buf, "%d\n", phydev->has_fixups);
+}
+static DEVICE_ATTR_RO(phy_has_fixups);
+
 static struct attribute *mdio_dev_attrs[] = {
        &dev_attr_phy_id.attr,
+       &dev_attr_phy_interface.attr,
+       &dev_attr_phy_has_fixups.attr,
        NULL,
 };
 ATTRIBUTE_GROUPS(mdio_dev);
index 5a8993b0cafc374c5c0f114ab01dc7618263570d..5ad971a55c5d9f21ffb3ded8e9d5704534095d21 100644 (file)
@@ -148,15 +148,52 @@ static int ks8737_config_intr(struct phy_device *phydev)
        return rc < 0 ? rc : 0;
 }
 
+static int kszphy_setup_led(struct phy_device *phydev,
+                           unsigned int reg, unsigned int shift)
+{
+
+       struct device *dev = &phydev->dev;
+       struct device_node *of_node = dev->of_node;
+       int rc, temp;
+       u32 val;
+
+       if (!of_node && dev->parent->of_node)
+               of_node = dev->parent->of_node;
+
+       if (of_property_read_u32(of_node, "micrel,led-mode", &val))
+               return 0;
+
+       temp = phy_read(phydev, reg);
+       if (temp < 0)
+               return temp;
+
+       temp &= ~(3 << shift);
+       temp |= val << shift;
+       rc = phy_write(phydev, reg, temp);
+
+       return rc < 0 ? rc : 0;
+}
+
 static int kszphy_config_init(struct phy_device *phydev)
 {
        return 0;
 }
 
+static int kszphy_config_init_led8041(struct phy_device *phydev)
+{
+       /* single led control, register 0x1e bits 15..14 */
+       return kszphy_setup_led(phydev, 0x1e, 14);
+}
+
 static int ksz8021_config_init(struct phy_device *phydev)
 {
-       int rc;
        const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE;
+       int rc;
+
+       rc = kszphy_setup_led(phydev, 0x1f, 4);
+       if (rc)
+               dev_err(&phydev->dev, "failed to set led mode\n");
+
        phy_write(phydev, MII_KSZPHY_OMSO, val);
        rc = ksz_config_flags(phydev);
        return rc < 0 ? rc : 0;
@@ -166,6 +203,10 @@ static int ks8051_config_init(struct phy_device *phydev)
 {
        int rc;
 
+       rc = kszphy_setup_led(phydev, 0x1f, 4);
+       if (rc)
+               dev_err(&phydev->dev, "failed to set led mode\n");
+
        rc = ksz_config_flags(phydev);
        return rc < 0 ? rc : 0;
 }
@@ -327,7 +368,7 @@ static struct phy_driver ksphy_driver[] = {
        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
                                | SUPPORTED_Asym_Pause),
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
-       .config_init    = kszphy_config_init,
+       .config_init    = kszphy_config_init_led8041,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
@@ -342,7 +383,7 @@ static struct phy_driver ksphy_driver[] = {
        .features       = PHY_BASIC_FEATURES |
                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
-       .config_init    = kszphy_config_init,
+       .config_init    = kszphy_config_init_led8041,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
@@ -371,7 +412,7 @@ static struct phy_driver ksphy_driver[] = {
        .phy_id_mask    = 0x00ffffff,
        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
-       .config_init    = kszphy_config_init,
+       .config_init    = kszphy_config_init_led8041,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
index 19c9eca0ef2638165dc9dc087d87aee934d28348..1d788f19135bdf5e59e71a11eed935981a172ca8 100644 (file)
 
 #include <asm/irq.h>
 
+static const char *phy_speed_to_str(int speed)
+{
+       switch (speed) {
+       case SPEED_10:
+               return "10Mbps";
+       case SPEED_100:
+               return "100Mbps";
+       case SPEED_1000:
+               return "1Gbps";
+       case SPEED_2500:
+               return "2.5Gbps";
+       case SPEED_10000:
+               return "10Gbps";
+       case SPEED_UNKNOWN:
+               return "Unknown";
+       default:
+               return "Unsupported (update phy.c)";
+       }
+}
+
 /**
  * phy_print_status - Convenience function to print out the current phy status
  * @phydev: the phy_device struct
 void phy_print_status(struct phy_device *phydev)
 {
        if (phydev->link) {
-               pr_info("%s - Link is Up - %d/%s\n",
-                       dev_name(&phydev->dev),
-                       phydev->speed,
-                       DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+               netdev_info(phydev->attached_dev,
+                       "Link is Up - %s/%s - flow control %s\n",
+                       phy_speed_to_str(phydev->speed),
+                       DUPLEX_FULL == phydev->duplex ? "Full" : "Half",
+                       phydev->pause ? "rx/tx" : "off");
        } else  {
-               pr_info("%s - Link is Down\n", dev_name(&phydev->dev));
+               netdev_info(phydev->attached_dev, "Link is Down\n");
        }
 }
 EXPORT_SYMBOL(phy_print_status);
@@ -62,7 +83,7 @@ EXPORT_SYMBOL(phy_print_status);
  * If the @phydev driver has an ack_interrupt function, call it to
  * ack and clear the phy device's interrupt.
  *
- * Returns 0 on success on < 0 on error.
+ * Returns 0 on success or < 0 on error.
  */
 static int phy_clear_interrupt(struct phy_device *phydev)
 {
@@ -77,7 +98,7 @@ static int phy_clear_interrupt(struct phy_device *phydev)
  * @phydev: the phy_device struct
  * @interrupts: interrupt flags to configure for this @phydev
  *
- * Returns 0 on success on < 0 on error.
+ * Returns 0 on success or < 0 on error.
  */
 static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
 {
@@ -93,15 +114,16 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
  * phy_aneg_done - return auto-negotiation status
  * @phydev: target phy_device struct
  *
- * Description: Reads the status register and returns 0 either if
- *   auto-negotiation is incomplete, or if there was an error.
- *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
+ * Description: Return the auto-negotiation status from this @phydev
+ * Returns > 0 on success or < 0 on error. 0 means that auto-negotiation
+ * is still pending.
  */
 static inline int phy_aneg_done(struct phy_device *phydev)
 {
-       int retval = phy_read(phydev, MII_BMSR);
+       if (phydev->drv->aneg_done)
+               return phydev->drv->aneg_done(phydev);
 
-       return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+       return genphy_aneg_done(phydev);
 }
 
 /* A structure for mapping a particular speed and duplex
@@ -164,9 +186,9 @@ static const struct phy_setting settings[] = {
  *   of that setting.  Returns the index of the last setting if
  *   none of the others match.
  */
-static inline int phy_find_setting(int speed, int duplex)
+static inline unsigned int phy_find_setting(int speed, int duplex)
 {
-       int idx = 0;
+       unsigned int idx = 0;
 
        while (idx < ARRAY_SIZE(settings) &&
               (settings[idx].speed != speed || settings[idx].duplex != duplex))
@@ -185,7 +207,7 @@ static inline int phy_find_setting(int speed, int duplex)
  *   the mask in features.  Returns the index of the last setting
  *   if nothing else matches.
  */
-static inline int phy_find_valid(int idx, u32 features)
+static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
 {
        while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
                idx++;
@@ -204,7 +226,7 @@ static inline int phy_find_valid(int idx, u32 features)
 static void phy_sanitize_settings(struct phy_device *phydev)
 {
        u32 features = phydev->supported;
-       int idx;
+       unsigned int idx;
 
        /* Sanitize settings based on PHY capabilities */
        if ((features & SUPPORTED_Autoneg) == 0)
@@ -283,7 +305,10 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
 
        ethtool_cmd_speed_set(cmd, phydev->speed);
        cmd->duplex = phydev->duplex;
-       cmd->port = PORT_MII;
+       if (phydev->interface == PHY_INTERFACE_MODE_MOCA)
+               cmd->port = PORT_BNC;
+       else
+               cmd->port = PORT_MII;
        cmd->phy_address = phydev->addr;
        cmd->transceiver = phy_is_internal(phydev) ?
                XCVR_INTERNAL : XCVR_EXTERNAL;
@@ -954,7 +979,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
            (phydev->interface == PHY_INTERFACE_MODE_RGMII))) {
                int eee_lp, eee_cap, eee_adv;
                u32 lp, cap, adv;
-               int idx, status;
+               int status;
+               unsigned int idx;
 
                /* Read phy status to properly get the right settings */
                status = phy_read_status(phydev);
index 4b03e63639b74e8fbac760ec2cd701940ad50686..0ce606624296a80492b18d89a27634614aad5497 100644 (file)
@@ -139,6 +139,7 @@ static int phy_scan_fixups(struct phy_device *phydev)
                                mutex_unlock(&phy_fixup_lock);
                                return err;
                        }
+                       phydev->has_fixups = true;
                }
        }
        mutex_unlock(&phy_fixup_lock);
@@ -534,16 +535,16 @@ static int phy_poll_reset(struct phy_device *phydev)
 
 int phy_init_hw(struct phy_device *phydev)
 {
-       int ret;
+       int ret = 0;
 
        if (!phydev->drv || !phydev->drv->config_init)
                return 0;
 
-       ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
-       if (ret < 0)
-               return ret;
+       if (phydev->drv->soft_reset)
+               ret = phydev->drv->soft_reset(phydev);
+       else
+               ret = genphy_soft_reset(phydev);
 
-       ret = phy_poll_reset(phydev);
        if (ret < 0)
                return ret;
 
@@ -683,10 +684,9 @@ EXPORT_SYMBOL(phy_detach);
 int phy_suspend(struct phy_device *phydev)
 {
        struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
-       struct ethtool_wolinfo wol;
+       struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
 
        /* If the device has WOL enabled, we cannot suspend the PHY */
-       wol.cmd = ETHTOOL_GWOL;
        phy_ethtool_get_wol(phydev, &wol);
        if (wol.wolopts)
                return -EBUSY;
@@ -719,7 +719,7 @@ int phy_resume(struct phy_device *phydev)
 static int genphy_config_advert(struct phy_device *phydev)
 {
        u32 advertise;
-       int oldadv, adv;
+       int oldadv, adv, bmsr;
        int err, changed = 0;
 
        /* Only allow advertising what this PHY supports */
@@ -744,26 +744,36 @@ static int genphy_config_advert(struct phy_device *phydev)
                changed = 1;
        }
 
+       bmsr = phy_read(phydev, MII_BMSR);
+       if (bmsr < 0)
+               return bmsr;
+
+       /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+        * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+        * logical 1.
+        */
+       if (!(bmsr & BMSR_ESTATEN))
+               return changed;
+
        /* Configure gigabit if it's supported */
+       adv = phy_read(phydev, MII_CTRL1000);
+       if (adv < 0)
+               return adv;
+
+       oldadv = adv;
+       adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+
        if (phydev->supported & (SUPPORTED_1000baseT_Half |
                                 SUPPORTED_1000baseT_Full)) {
-               adv = phy_read(phydev, MII_CTRL1000);
-               if (adv < 0)
-                       return adv;
-
-               oldadv = adv;
-               adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
                adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
-
-               if (adv != oldadv) {
-                       err = phy_write(phydev, MII_CTRL1000, adv);
-
-                       if (err < 0)
-                               return err;
+               if (adv != oldadv)
                        changed = 1;
-               }
        }
 
+       err = phy_write(phydev, MII_CTRL1000, adv);
+       if (err < 0)
+               return err;
+
        return changed;
 }
 
@@ -855,6 +865,22 @@ int genphy_config_aneg(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_config_aneg);
 
+/**
+ * genphy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
+ *
+ * Description: Reads the status register and returns 0 either if
+ *   auto-negotiation is incomplete, or if there was an error.
+ *   Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
+ */
+int genphy_aneg_done(struct phy_device *phydev)
+{
+       int retval = phy_read(phydev, MII_BMSR);
+
+       return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE);
+}
+EXPORT_SYMBOL(genphy_aneg_done);
+
 static int gen10g_config_aneg(struct phy_device *phydev)
 {
        return 0;
@@ -906,6 +932,8 @@ int genphy_read_status(struct phy_device *phydev)
        int err;
        int lpa;
        int lpagb = 0;
+       int common_adv;
+       int common_adv_gb = 0;
 
        /* Update the link, but return if there was an error */
        err = genphy_update_link(phydev);
@@ -927,7 +955,7 @@ int genphy_read_status(struct phy_device *phydev)
 
                        phydev->lp_advertising =
                                mii_stat1000_to_ethtool_lpa_t(lpagb);
-                       lpagb &= adv << 2;
+                       common_adv_gb = lpagb & adv << 2;
                }
 
                lpa = phy_read(phydev, MII_LPA);
@@ -940,25 +968,25 @@ int genphy_read_status(struct phy_device *phydev)
                if (adv < 0)
                        return adv;
 
-               lpa &= adv;
+               common_adv = lpa & adv;
 
                phydev->speed = SPEED_10;
                phydev->duplex = DUPLEX_HALF;
                phydev->pause = 0;
                phydev->asym_pause = 0;
 
-               if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+               if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
                        phydev->speed = SPEED_1000;
 
-                       if (lpagb & LPA_1000FULL)
+                       if (common_adv_gb & LPA_1000FULL)
                                phydev->duplex = DUPLEX_FULL;
-               } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+               } else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
                        phydev->speed = SPEED_100;
 
-                       if (lpa & LPA_100FULL)
+                       if (common_adv & LPA_100FULL)
                                phydev->duplex = DUPLEX_FULL;
                } else
-                       if (lpa & LPA_10FULL)
+                       if (common_adv & LPA_10FULL)
                                phydev->duplex = DUPLEX_FULL;
 
                if (phydev->duplex == DUPLEX_FULL) {
@@ -1018,6 +1046,27 @@ static int gen10g_read_status(struct phy_device *phydev)
        return 0;
 }
 
+/**
+ * genphy_soft_reset - software reset the PHY via BMCR_RESET bit
+ * @phydev: target phy_device struct
+ *
+ * Description: Perform a software PHY reset using the standard
+ * BMCR_RESET bit and poll for the reset bit to be cleared.
+ *
+ * Returns: 0 on success, < 0 on failure
+ */
+int genphy_soft_reset(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       if (ret < 0)
+               return ret;
+
+       return phy_poll_reset(phydev);
+}
+EXPORT_SYMBOL(genphy_soft_reset);
+
 static int genphy_config_init(struct phy_device *phydev)
 {
        int val;
@@ -1064,6 +1113,12 @@ static int genphy_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int gen10g_soft_reset(struct phy_device *phydev)
+{
+       /* Do nothing for now */
+       return 0;
+}
+
 static int gen10g_config_init(struct phy_device *phydev)
 {
        /* Temporarily just say we support everything */
@@ -1238,9 +1293,11 @@ static struct phy_driver genphy_driver[] = {
        .phy_id         = 0xffffffff,
        .phy_id_mask    = 0xffffffff,
        .name           = "Generic PHY",
+       .soft_reset     = genphy_soft_reset,
        .config_init    = genphy_config_init,
        .features       = 0,
        .config_aneg    = genphy_config_aneg,
+       .aneg_done      = genphy_aneg_done,
        .read_status    = genphy_read_status,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
@@ -1249,6 +1306,7 @@ static struct phy_driver genphy_driver[] = {
        .phy_id         = 0xffffffff,
        .phy_id_mask    = 0xffffffff,
        .name           = "Generic 10G PHY",
+       .soft_reset     = gen10g_soft_reset,
        .config_init    = gen10g_config_init,
        .features       = 0,
        .config_aneg    = gen10g_config_aneg,
index 72ff14b811c621c3a6694a2e4941d2a4c41651ed..e3923ebb693fccc276db45de7c7d9551ee6bc208 100644 (file)
@@ -143,9 +143,8 @@ struct ppp {
        struct sk_buff_head mrq;        /* MP: receive reconstruction queue */
 #endif /* CONFIG_PPP_MULTILINK */
 #ifdef CONFIG_PPP_FILTER
-       struct sock_filter *pass_filter;        /* filter for packets to pass */
-       struct sock_filter *active_filter;/* filter for pkts to reset idle */
-       unsigned pass_len, active_len;
+       struct sk_filter *pass_filter;  /* filter for packets to pass */
+       struct sk_filter *active_filter;/* filter for pkts to reset idle */
 #endif /* CONFIG_PPP_FILTER */
        struct net      *ppp_net;       /* the net we belong to */
        struct ppp_link_stats stats64;  /* 64 bit network stats */
@@ -755,28 +754,42 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case PPPIOCSPASS:
        {
                struct sock_filter *code;
+
                err = get_filter(argp, &code);
                if (err >= 0) {
+                       struct sock_fprog fprog = {
+                               .len = err,
+                               .filter = code,
+                       };
+
                        ppp_lock(ppp);
-                       kfree(ppp->pass_filter);
-                       ppp->pass_filter = code;
-                       ppp->pass_len = err;
+                       if (ppp->pass_filter)
+                               sk_unattached_filter_destroy(ppp->pass_filter);
+                       err = sk_unattached_filter_create(&ppp->pass_filter,
+                                                         &fprog);
+                       kfree(code);
                        ppp_unlock(ppp);
-                       err = 0;
                }
                break;
        }
        case PPPIOCSACTIVE:
        {
                struct sock_filter *code;
+
                err = get_filter(argp, &code);
                if (err >= 0) {
+                       struct sock_fprog fprog = {
+                               .len = err,
+                               .filter = code,
+                       };
+
                        ppp_lock(ppp);
-                       kfree(ppp->active_filter);
-                       ppp->active_filter = code;
-                       ppp->active_len = err;
+                       if (ppp->active_filter)
+                               sk_unattached_filter_destroy(ppp->active_filter);
+                       err = sk_unattached_filter_create(&ppp->active_filter,
+                                                         &fprog);
+                       kfree(code);
                        ppp_unlock(ppp);
-                       err = 0;
                }
                break;
        }
@@ -1184,7 +1197,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                   a four-byte PPP header on each packet */
                *skb_push(skb, 2) = 1;
                if (ppp->pass_filter &&
-                   sk_run_filter(skb, ppp->pass_filter) == 0) {
+                   SK_RUN_FILTER(ppp->pass_filter, skb) == 0) {
                        if (ppp->debug & 1)
                                netdev_printk(KERN_DEBUG, ppp->dev,
                                              "PPP: outbound frame "
@@ -1194,7 +1207,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
                }
                /* if this packet passes the active filter, record the time */
                if (!(ppp->active_filter &&
-                     sk_run_filter(skb, ppp->active_filter) == 0))
+                     SK_RUN_FILTER(ppp->active_filter, skb) == 0))
                        ppp->last_xmit = jiffies;
                skb_pull(skb, 2);
 #else
@@ -1818,7 +1831,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
 
                        *skb_push(skb, 2) = 0;
                        if (ppp->pass_filter &&
-                           sk_run_filter(skb, ppp->pass_filter) == 0) {
+                           SK_RUN_FILTER(ppp->pass_filter, skb) == 0) {
                                if (ppp->debug & 1)
                                        netdev_printk(KERN_DEBUG, ppp->dev,
                                                      "PPP: inbound frame "
@@ -1827,7 +1840,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
                                return;
                        }
                        if (!(ppp->active_filter &&
-                             sk_run_filter(skb, ppp->active_filter) == 0))
+                             SK_RUN_FILTER(ppp->active_filter, skb) == 0))
                                ppp->last_recv = jiffies;
                        __skb_pull(skb, 2);
                } else
@@ -2672,6 +2685,10 @@ ppp_create_interface(struct net *net, int unit, int *retp)
        ppp->minseq = -1;
        skb_queue_head_init(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
+#ifdef CONFIG_PPP_FILTER
+       ppp->pass_filter = NULL;
+       ppp->active_filter = NULL;
+#endif /* CONFIG_PPP_FILTER */
 
        /*
         * drum roll: don't forget to set
@@ -2802,10 +2819,15 @@ static void ppp_destroy_interface(struct ppp *ppp)
        skb_queue_purge(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
 #ifdef CONFIG_PPP_FILTER
-       kfree(ppp->pass_filter);
-       ppp->pass_filter = NULL;
-       kfree(ppp->active_filter);
-       ppp->active_filter = NULL;
+       if (ppp->pass_filter) {
+               sk_unattached_filter_destroy(ppp->pass_filter);
+               ppp->pass_filter = NULL;
+       }
+
+       if (ppp->active_filter) {
+               sk_unattached_filter_destroy(ppp->active_filter);
+               ppp->active_filter = NULL;
+       }
 #endif /* CONFIG_PPP_FILTER */
 
        kfree_skb(ppp->xmit_pending);
index 28407426fd6fdbc7dc0e21eb83c8acaba380065b..33008c1d1d678756ae8fbae13238763c24cc603e 100644 (file)
@@ -1031,8 +1031,7 @@ static void team_port_leave(struct team *team, struct team_port *port)
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port,
-                                   gfp_t gfp)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port)
 {
        struct netpoll *np;
        int err;
@@ -1040,11 +1039,11 @@ static int team_port_enable_netpoll(struct team *team, struct team_port *port,
        if (!team->dev->npinfo)
                return 0;
 
-       np = kzalloc(sizeof(*np), gfp);
+       np = kzalloc(sizeof(*np), GFP_KERNEL);
        if (!np)
                return -ENOMEM;
 
-       err = __netpoll_setup(np, port->dev, gfp);
+       err = __netpoll_setup(np, port->dev);
        if (err) {
                kfree(np);
                return err;
@@ -1067,8 +1066,7 @@ static void team_port_disable_netpoll(struct team_port *port)
        kfree(np);
 }
 #else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port,
-                                   gfp_t gfp)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port)
 {
        return 0;
 }
@@ -1156,7 +1154,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_vids_add;
        }
 
-       err = team_port_enable_netpoll(team, port, GFP_KERNEL);
+       err = team_port_enable_netpoll(team, port);
        if (err) {
                netdev_err(dev, "Failed to enable netpoll on device %s\n",
                           portname);
@@ -1540,16 +1538,10 @@ static int team_init(struct net_device *dev)
        mutex_init(&team->lock);
        team_set_no_mode(team);
 
-       team->pcpu_stats = alloc_percpu(struct team_pcpu_stats);
+       team->pcpu_stats = netdev_alloc_pcpu_stats(struct team_pcpu_stats);
        if (!team->pcpu_stats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct team_pcpu_stats *team_stats;
-               team_stats = per_cpu_ptr(team->pcpu_stats, i);
-               u64_stats_init(&team_stats->syncp);
-       }
-
        for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
                INIT_HLIST_HEAD(&team->en_port_hlist[i]);
        INIT_LIST_HEAD(&team->port_list);
@@ -1648,7 +1640,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
 }
 
 static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb,
-                            void *accel_priv)
+                            void *accel_priv, select_queue_fallback_t fallback)
 {
        /*
         * This helper function exists to help dev_pick_tx get the correct
@@ -1767,13 +1759,13 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
        for_each_possible_cpu(i) {
                p = per_cpu_ptr(team->pcpu_stats, i);
                do {
-                       start = u64_stats_fetch_begin_bh(&p->syncp);
+                       start = u64_stats_fetch_begin_irq(&p->syncp);
                        rx_packets      = p->rx_packets;
                        rx_bytes        = p->rx_bytes;
                        rx_multicast    = p->rx_multicast;
                        tx_packets      = p->tx_packets;
                        tx_bytes        = p->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                stats->rx_packets       += rx_packets;
                stats->rx_bytes         += rx_bytes;
@@ -1856,7 +1848,7 @@ static void team_netpoll_cleanup(struct net_device *dev)
 }
 
 static int team_netpoll_setup(struct net_device *dev,
-                             struct netpoll_info *npifo, gfp_t gfp)
+                             struct netpoll_info *npifo)
 {
        struct team *team = netdev_priv(dev);
        struct team_port *port;
@@ -1864,7 +1856,7 @@ static int team_netpoll_setup(struct net_device *dev,
 
        mutex_lock(&team->lock);
        list_for_each_entry(port, &team->port_list, list) {
-               err = team_port_enable_netpoll(team, port, gfp);
+               err = team_port_enable_netpoll(team, port);
                if (err) {
                        __team_netpoll_cleanup(team);
                        break;
index d671fc3ac5ac26ad2b7666617fab5adc1042e569..dbde3412ee5eafdeb39cd238e8af4f19368917c6 100644 (file)
@@ -432,9 +432,9 @@ static void __lb_one_cpu_stats_add(struct lb_stats *acc_stats,
        struct lb_stats tmp;
 
        do {
-               start = u64_stats_fetch_begin_bh(syncp);
+               start = u64_stats_fetch_begin_irq(syncp);
                tmp.tx_bytes = cpu_stats->tx_bytes;
-       } while (u64_stats_fetch_retry_bh(syncp, start));
+       } while (u64_stats_fetch_retry_irq(syncp, start));
        acc_stats->tx_bytes += tmp.tx_bytes;
 }
 
index 44c4db8450f0347b4ea6ce861da7f05524ebdb5d..ee328ba101e72a9e3f150d8c24068182be86abc5 100644 (file)
@@ -366,7 +366,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
  * hope the rxq no. may help here.
  */
 static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb,
-                           void *accel_priv)
+                           void *accel_priv, select_queue_fallback_t fallback)
 {
        struct tun_struct *tun = netdev_priv(dev);
        struct tun_flow_entry *e;
@@ -452,7 +452,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
 
                --tun->numqueues;
                if (clean) {
-                       rcu_assign_pointer(tfile->tun, NULL);
+                       RCU_INIT_POINTER(tfile->tun, NULL);
                        sock_put(&tfile->sk);
                } else
                        tun_disable_queue(tun, tfile);
@@ -499,12 +499,12 @@ static void tun_detach_all(struct net_device *dev)
                tfile = rtnl_dereference(tun->tfiles[i]);
                BUG_ON(!tfile);
                wake_up_all(&tfile->wq.wait);
-               rcu_assign_pointer(tfile->tun, NULL);
+               RCU_INIT_POINTER(tfile->tun, NULL);
                --tun->numqueues;
        }
        list_for_each_entry(tfile, &tun->disabled, next) {
                wake_up_all(&tfile->wq.wait);
-               rcu_assign_pointer(tfile->tun, NULL);
+               RCU_INIT_POINTER(tfile->tun, NULL);
        }
        BUG_ON(tun->numqueues != 0);
 
@@ -1686,7 +1686,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                                   TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
                                   NETIF_F_HW_VLAN_STAG_TX;
                dev->features = dev->hw_features;
-               dev->vlan_features = dev->features;
+               dev->vlan_features = dev->features &
+                                    ~(NETIF_F_HW_VLAN_CTAG_TX |
+                                      NETIF_F_HW_VLAN_STAG_TX);
 
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false);
@@ -2192,7 +2194,7 @@ static int tun_chr_open(struct inode *inode, struct file * file)
                                            &tun_proto);
        if (!tfile)
                return -ENOMEM;
-       rcu_assign_pointer(tfile->tun, NULL);
+       RCU_INIT_POINTER(tfile->tun, NULL);
        tfile->net = get_net(current->nsproxy->net_ns);
        tfile->flags = 0;
        tfile->ifindex = 0;
index 6b638a066c1d33edfa9082fde204d7da16898aa8..7e7269fd3707728d16705fc27c93c2f7a45b666f 100644 (file)
@@ -292,6 +292,21 @@ config USB_NET_SR9700
          This option adds support for CoreChip-sz SR9700 based USB 1.1
          10/100 Ethernet adapters.
 
+config USB_NET_SR9800
+       tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
+       depends on USB_USBNET
+       select CRC32
+       ---help---
+         Say Y if you want to use one of the following 100Mbps USB Ethernet
+         device based on the CoreChip-sz SR9800 chip.
+
+         This driver makes the adapter appear as a normal Ethernet interface,
+         typically on eth0, if it is the only ethernet device, or perhaps on
+         eth1, if you have a PCI or ISA ethernet card installed.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sr9800.
+
 config USB_NET_SMSC75XX
        tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
        depends on USB_USBNET
index b17b5e88bbaf71acc06640a0f3fe6967b53ff2ab..e2797f1e1b31ee51f82c11d50b23e6bd274d29ab 100644 (file)
@@ -11,10 +11,11 @@ obj-$(CONFIG_USB_HSO)               += hso.o
 obj-$(CONFIG_USB_NET_AX8817X)  += asix.o
 asix-y := asix_devices.o asix_common.o ax88172a.o
 obj-$(CONFIG_USB_NET_AX88179_178A)      += ax88179_178a.o
-obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
+obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
 obj-$(CONFIG_USB_NET_CDC_EEM)  += cdc_eem.o
 obj-$(CONFIG_USB_NET_DM9601)   += dm9601.o
 obj-$(CONFIG_USB_NET_SR9700)   += sr9700.o
+obj-$(CONFIG_USB_NET_SR9800)   += sr9800.o
 obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o
 obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o
 obj-$(CONFIG_USB_NET_GL620A)   += gl620a.o
index 9765a7d4766dcd4a717bd7cd0bea56c71953deb1..5d194093f3e1f3b3c1893faf0cf8ebb266facdad 100644 (file)
@@ -917,7 +917,8 @@ static const struct driver_info ax88178_info = {
        .status = asix_status,
        .link_reset = ax88178_link_reset,
        .reset = ax88178_reset,
-       .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |
+                FLAG_MULTI_PACKET,
        .rx_fixup = asix_rx_fixup_common,
        .tx_fixup = asix_tx_fixup,
 };
index d6f64dad05bcb707c0c26dbe2886abd73e760db1..054e59ca6946446389cd22eb1e851a6b4fad6633 100644 (file)
@@ -1029,20 +1029,12 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = 0x03;
        dev->mii.supports_gmii = 1;
 
-       if (usb_device_no_sg_constraint(dev->udev))
-               dev->can_dma_sg = 1;
-
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                              NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                                 NETIF_F_RXCSUM;
 
-       if (dev->can_dma_sg) {
-               dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
-               dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
-       }
-
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
               AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
@@ -1118,6 +1110,10 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        u16 hdr_off;
        u32 *pkt_hdr;
 
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        skb_trim(skb, skb->len - 4);
        memcpy(&rx_hdr, skb_tail_pointer(skb), 4);
        le32_to_cpus(&rx_hdr);
@@ -1391,6 +1387,19 @@ static const struct driver_info ax88178a_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info dlink_dub1312_info = {
+       .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct driver_info sitecom_info = {
        .description = "Sitecom USB 3.0 to Gigabit Adapter",
        .bind = ax88179_bind,
@@ -1417,6 +1426,19 @@ static const struct driver_info samsung_info = {
        .tx_fixup = ax88179_tx_fixup,
 };
 
+static const struct driver_info lenovo_info = {
+       .description = "Lenovo OneLinkDock Gigabit LAN",
+       .bind = ax88179_bind,
+       .unbind = ax88179_unbind,
+       .status = ax88179_status,
+       .link_reset = ax88179_link_reset,
+       .reset = ax88179_reset,
+       .stop = ax88179_stop,
+       .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+       .rx_fixup = ax88179_rx_fixup,
+       .tx_fixup = ax88179_tx_fixup,
+};
+
 static const struct usb_device_id products[] = {
 {
        /* ASIX AX88179 10/100/1000 */
@@ -1426,6 +1448,10 @@ static const struct usb_device_id products[] = {
        /* ASIX AX88178A 10/100/1000 */
        USB_DEVICE(0x0b95, 0x178a),
        .driver_info = (unsigned long)&ax88178a_info,
+}, {
+       /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */
+       USB_DEVICE(0x2001, 0x4a00),
+       .driver_info = (unsigned long)&dlink_dub1312_info,
 }, {
        /* Sitecom USB 3.0 to Gigabit Adapter */
        USB_DEVICE(0x0df6, 0x0072),
@@ -1434,6 +1460,10 @@ static const struct usb_device_id products[] = {
        /* Samsung USB Ethernet Adapter */
        USB_DEVICE(0x04e8, 0xa100),
        .driver_info = (unsigned long)&samsung_info,
+}, {
+       /* Lenovo OneLinkDock Gigabit LAN */
+       USB_DEVICE(0x17ef, 0x304b),
+       .driver_info = (unsigned long)&lenovo_info,
 },
        { },
 };
index 42e176912c8ea151606883c0b8563e45fa95a447..bd363b27e8540e3bfe2acc6173adcc8a1952f4b7 100644 (file)
@@ -652,6 +652,13 @@ static const struct usb_device_id  products[] = {
        .driver_info = 0,
 },
 
+/* Samsung USB Ethernet Adapters */
+{
+       USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = 0,
+},
+
 /* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
index dbff290ed0e4f5ac4752efbe56eeea0fda0c419f..549dbac710ed5f576f84cedf375df8588e5a7dc5 100644 (file)
@@ -68,12 +68,12 @@ static struct usb_driver cdc_ncm_driver;
 static int cdc_ncm_setup(struct usbnet *dev)
 {
        struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
-       struct usb_cdc_ncm_ntb_parameters ncm_parm;
        u32 val;
        u8 flags;
        u8 iface_no;
        int err;
        int eth_hlen;
+       u16 mbim_mtu;
        u16 ntb_fmt_supported;
        __le16 max_datagram_size;
 
@@ -82,22 +82,22 @@ static int cdc_ncm_setup(struct usbnet *dev)
        err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
                              USB_TYPE_CLASS | USB_DIR_IN
                              |USB_RECIP_INTERFACE,
-                             0, iface_no, &ncm_parm,
-                             sizeof(ncm_parm));
+                             0, iface_no, &ctx->ncm_parm,
+                             sizeof(ctx->ncm_parm));
        if (err < 0) {
                dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
                return err; /* GET_NTB_PARAMETERS is required */
        }
 
        /* read correct set of parameters according to device mode */
-       ctx->rx_max = le32_to_cpu(ncm_parm.dwNtbInMaxSize);
-       ctx->tx_max = le32_to_cpu(ncm_parm.dwNtbOutMaxSize);
-       ctx->tx_remainder = le16_to_cpu(ncm_parm.wNdpOutPayloadRemainder);
-       ctx->tx_modulus = le16_to_cpu(ncm_parm.wNdpOutDivisor);
-       ctx->tx_ndp_modulus = le16_to_cpu(ncm_parm.wNdpOutAlignment);
+       ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+       ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+       ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+       ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+       ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
        /* devices prior to NCM Errata shall set this field to zero */
-       ctx->tx_max_datagrams = le16_to_cpu(ncm_parm.wNtbOutMaxDatagrams);
-       ntb_fmt_supported = le16_to_cpu(ncm_parm.bmNtbFormatsSupported);
+       ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
+       ntb_fmt_supported = le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported);
 
        /* there are some minor differences in NCM and MBIM defaults */
        if (cdc_ncm_comm_intf_is_mbim(ctx->control->cur_altsetting)) {
@@ -146,7 +146,7 @@ static int cdc_ncm_setup(struct usbnet *dev)
        }
 
        /* inform device about NTB input size changes */
-       if (ctx->rx_max != le32_to_cpu(ncm_parm.dwNtbInMaxSize)) {
+       if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
                __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
 
                err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
@@ -162,14 +162,6 @@ static int cdc_ncm_setup(struct usbnet *dev)
                dev_dbg(&dev->intf->dev, "Using default maximum transmit length=%d\n",
                        CDC_NCM_NTB_MAX_SIZE_TX);
                ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
-
-               /* Adding a pad byte here simplifies the handling in
-                * cdc_ncm_fill_tx_frame, by making tx_max always
-                * represent the real skb max size.
-                */
-               if (ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
-                       ctx->tx_max++;
-
        }
 
        /*
@@ -261,6 +253,14 @@ out:
        /* set MTU to max supported by the device if necessary */
        if (dev->net->mtu > ctx->max_datagram_size - eth_hlen)
                dev->net->mtu = ctx->max_datagram_size - eth_hlen;
+
+       /* do not exceed operater preferred MTU */
+       if (ctx->mbim_extended_desc) {
+               mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
+               if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
+                       dev->net->mtu = mbim_mtu;
+       }
+
        return 0;
 }
 
@@ -399,6 +399,14 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
                        ctx->mbim_desc = (const struct usb_cdc_mbim_desc *)buf;
                        break;
 
+               case USB_CDC_MBIM_EXTENDED_TYPE:
+                       if (buf[0] < sizeof(*(ctx->mbim_extended_desc)))
+                               break;
+
+                       ctx->mbim_extended_desc =
+                               (const struct usb_cdc_mbim_extended_desc *)buf;
+                       break;
+
                default:
                        break;
                }
@@ -439,6 +447,10 @@ advance:
                goto error2;
        }
 
+       /* initialize data interface */
+       if (cdc_ncm_setup(dev))
+               goto error2;
+
        /* configure data interface */
        temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
        if (temp) {
@@ -453,12 +465,6 @@ advance:
                goto error2;
        }
 
-       /* initialize data interface */
-       if (cdc_ncm_setup(dev)) {
-               dev_dbg(&intf->dev, "cdc_ncm_setup() failed\n");
-               goto error2;
-       }
-
        usb_set_intfdata(ctx->data, dev);
        usb_set_intfdata(ctx->control, dev);
 
@@ -475,6 +481,15 @@ advance:
        dev->hard_mtu = ctx->tx_max;
        dev->rx_urb_size = ctx->rx_max;
 
+       /* cdc_ncm_setup will override dwNtbOutMaxSize if it is
+        * outside the sane range. Adding a pad byte here if necessary
+        * simplifies the handling in cdc_ncm_fill_tx_frame, making
+        * tx_max always represent the real skb max size.
+        */
+       if (ctx->tx_max != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
+           ctx->tx_max % usb_maxpacket(dev->udev, dev->out, 1) == 0)
+               ctx->tx_max++;
+
        return 0;
 
 error2:
index e4a8a93fbaf7eec07ca3af2d2c813c08609b9c12..1cc24e6f23e2528150a3e9a660e134732e5cd988 100644 (file)
@@ -84,6 +84,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        u32                     size;
        u32                     count;
 
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        header = (struct gl_header *) skb->data;
 
        // get the packet count of the received skb
index 1a482344b3f507e97486059d56280dfd3f23d37c..660bd5ea9fc0b311918812af8d3959c830b96cf4 100644 (file)
@@ -1201,16 +1201,18 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
        struct hso_serial *serial = urb->context;
        int status = urb->status;
 
+       D4("\n--- Got serial_read_bulk callback %02x ---", status);
+
        /* sanity check */
        if (!serial) {
                D1("serial == NULL");
                return;
-       } else if (status) {
+       }
+       if (status) {
                handle_usb_error(status, __func__, serial->parent);
                return;
        }
 
-       D4("\n--- Got serial_read_bulk callback %02x ---", status);
        D1("Actual length = %d\n", urb->actual_length);
        DUMP1(urb->transfer_buffer, urb->actual_length);
 
@@ -1218,25 +1220,13 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
        if (serial->port.count == 0)
                return;
 
-       if (status == 0) {
-               if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
-                       fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
-               /* Valid data, handle RX data */
-               spin_lock(&serial->serial_lock);
-               serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
-               put_rxbuf_data_and_resubmit_bulk_urb(serial);
-               spin_unlock(&serial->serial_lock);
-       } else if (status == -ENOENT || status == -ECONNRESET) {
-               /* Unlinked - check for throttled port. */
-               D2("Port %d, successfully unlinked urb", serial->minor);
-               spin_lock(&serial->serial_lock);
-               serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
-               hso_resubmit_rx_bulk_urb(serial, urb);
-               spin_unlock(&serial->serial_lock);
-       } else {
-               D2("Port %d, status = %d for read urb", serial->minor, status);
-               return;
-       }
+       if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
+               fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
+       /* Valid data, handle RX data */
+       spin_lock(&serial->serial_lock);
+       serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
+       put_rxbuf_data_and_resubmit_bulk_urb(serial);
+       spin_unlock(&serial->serial_lock);
 }
 
 /*
index acfcc32b323d87c1b6f4e64788802af932f74319..8f37efd2d2fbb3ec05fcde896b8b9e88136c2f35 100644 (file)
@@ -210,7 +210,7 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                         * (0x86dd) so Linux can understand it.
                         */
                        if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60)
-                               ethhdr->h_proto = __constant_htons(ETH_P_IPV6);
+                               ethhdr->h_proto = htons(ETH_P_IPV6);
                }
 
                if (count) {
index a305a7b2dae6f85ce4877a2f38e7d413688d5b1c..82d844a8ebd093e79c26ada9fc728fec8b10576e 100644 (file)
@@ -526,8 +526,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
        u8 status;
 
-       if (skb->len == 0) {
-               dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len) {
+               dev_err(&dev->udev->dev, "unexpected tiny rx frame\n");
                return 0;
        }
 
index 0a85d92277750d061300f269b19f6c4be54dbe07..4cbdb1307f3e2ed0ad850a5ab076f80aaee26ce5 100644 (file)
@@ -364,6 +364,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
        struct nc_trailer       *trailer;
        u16                     hdr_len, packet_len;
 
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        if (!(skb->len & 0x01)) {
                netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n",
                           skb->len, dev->net->hard_header_len, dev->hard_mtu,
index 23bdd5b9274ddb6becb5eabad2d4709b7b2a732d..313cb6cd4848e033bab664788c24c0a88ce55996 100644 (file)
@@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
        __be16 proto;
 
-       /* usbnet rx_complete guarantees that skb->len is at least
-        * hard_header_len, so we can inspect the dest address without
-        * checking skb->len
-        */
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        switch (skb->data[0] & 0xf0) {
        case 0x40:
                proto = htons(ETH_P_IP);
@@ -712,6 +712,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x19d2, 0x1255, 3)},
        {QMI_FIXED_INTF(0x19d2, 0x1255, 4)},
        {QMI_FIXED_INTF(0x19d2, 0x1256, 4)},
+       {QMI_FIXED_INTF(0x19d2, 0x1270, 5)},    /* ZTE MF667 */
        {QMI_FIXED_INTF(0x19d2, 0x1401, 2)},
        {QMI_FIXED_INTF(0x19d2, 0x1402, 2)},    /* ZTE MF60 */
        {QMI_FIXED_INTF(0x19d2, 0x1424, 2)},
@@ -723,6 +724,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 19)},   /* Sierra Wireless MC7710 in QMI mode */
        {QMI_FIXED_INTF(0x1199, 0x901c, 8)},    /* Sierra Wireless EM7700 */
+       {QMI_FIXED_INTF(0x1199, 0x9051, 8)},    /* Netgear AirCard 340U */
        {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)},    /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */
        {QMI_FIXED_INTF(0x2357, 0x0201, 4)},    /* TP-LINK HSUPA Modem MA180 */
        {QMI_FIXED_INTF(0x2357, 0x9000, 4)},    /* TP-LINK MA260 */
@@ -730,6 +732,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)},    /* Telit LE920 */
        {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)},    /* Olivetti Olicard 200 */
        {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)},    /* Cinterion PLxx */
+       {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)},    /* Cinterion PHxx,PXxx */
 
        /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index e8fac732c6f1c9792124983adedf613253f70cfa..18e12a3f7fc302399167bd32712a5ed66fe8fd36 100644 (file)
 #include <linux/list.h>
 #include <linux/ip.h>
 #include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v1.04.0 (2014/01/15)"
+#define DRIVER_VERSION "v1.06.0 (2014/03/03)"
 #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
 #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
 #define MODULENAME "r8152"
 #define PLA_TCR0               0xe610
 #define PLA_TCR1               0xe612
 #define PLA_TXFIFO_CTRL                0xe618
-#define PLA_RSTTELLY           0xe800
+#define PLA_RSTTALLY           0xe800
 #define PLA_CR                 0xe813
 #define PLA_CRWECR             0xe81c
+#define PLA_CONFIG12           0xe81e  /* CONFIG1, CONFIG2 */
+#define PLA_CONFIG34           0xe820  /* CONFIG3, CONFIG4 */
 #define PLA_CONFIG5            0xe822
 #define PLA_PHY_PWR            0xe84c
 #define PLA_OOB_CTRL           0xe84f
@@ -69,7 +72,7 @@
 #define PLA_MISC_0             0xe858
 #define PLA_MISC_1             0xe85a
 #define PLA_OCP_GPHY_BASE      0xe86c
-#define PLA_TELLYCNT           0xe890
+#define PLA_TALLYCNT           0xe890
 #define PLA_SFF_STS_7          0xe8de
 #define PLA_PHYSTATUS          0xe908
 #define PLA_BP_BA              0xfc26
 /* PLA_TCR1 */
 #define VERSION_MASK           0x7cf0
 
+/* PLA_RSTTALLY */
+#define TALLY_RESET            0x0001
+
 /* PLA_CR */
 #define CR_RST                 0x10
 #define CR_RE                  0x08
 /* PAL_BDC_CR */
 #define ALDPS_PROXY_MODE       0x0001
 
+/* PLA_CONFIG34 */
+#define LINK_ON_WAKE_EN                0x0010
+#define LINK_OFF_WAKE_EN       0x0008
+
 /* PLA_CONFIG5 */
+#define BWF_EN                 0x0040
+#define MWF_EN                 0x0020
+#define UWF_EN                 0x0010
 #define LAN_WAKE_EN            0x0002
 
 /* PLA_LED_FEATURE */
@@ -436,6 +449,9 @@ enum rtl8152_flags {
        RTL8152_SET_RX_MODE,
        WORK_ENABLE,
        RTL8152_LINK_CHG,
+       SELECTIVE_SUSPEND,
+       PHY_RESET,
+       SCHEDULE_TASKLET,
 };
 
 /* Define these values to match your device */
@@ -452,11 +468,37 @@ enum rtl8152_flags {
 #define REALTEK_USB_DEVICE(vend, prod) \
        USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC)
 
+struct tally_counter {
+       __le64  tx_packets;
+       __le64  rx_packets;
+       __le64  tx_errors;
+       __le32  rx_errors;
+       __le16  rx_missed;
+       __le16  align_errors;
+       __le32  tx_one_collision;
+       __le32  tx_multi_collision;
+       __le64  rx_unicast;
+       __le64  rx_broadcast;
+       __le32  rx_multicast;
+       __le16  tx_aborted;
+       __le16  tx_underun;
+};
+
 struct rx_desc {
        __le32 opts1;
 #define RX_LEN_MASK                    0x7fff
+
        __le32 opts2;
+#define RD_UDP_CS                      (1 << 23)
+#define RD_TCP_CS                      (1 << 22)
+#define RD_IPV6_CS                     (1 << 20)
+#define RD_IPV4_CS                     (1 << 19)
+
        __le32 opts3;
+#define IPF                            (1 << 23) /* IP checksum fail */
+#define UDPF                           (1 << 22) /* UDP checksum fail */
+#define TCPF                           (1 << 21) /* TCP checksum fail */
+
        __le32 opts4;
        __le32 opts5;
        __le32 opts6;
@@ -466,13 +508,21 @@ struct tx_desc {
        __le32 opts1;
 #define TX_FS                  (1 << 31) /* First segment of a packet */
 #define TX_LS                  (1 << 30) /* Final segment of a packet */
-#define TX_LEN_MASK            0x3ffff
+#define GTSENDV4               (1 << 28)
+#define GTSENDV6               (1 << 27)
+#define GTTCPHO_SHIFT          18
+#define GTTCPHO_MAX            0x7fU
+#define TX_LEN_MAX             0x3ffffU
 
        __le32 opts2;
 #define UDP_CS                 (1 << 31) /* Calculate UDP/IP checksum */
 #define TCP_CS                 (1 << 30) /* Calculate TCP/IP checksum */
 #define IPV4_CS                        (1 << 29) /* Calculate IPv4 checksum */
 #define IPV6_CS                        (1 << 28) /* Calculate IPv6 checksum */
+#define MSS_SHIFT              17
+#define MSS_MAX                        0x7ffU
+#define TCPHO_SHIFT            17
+#define TCPHO_MAX              0x7ffU
 };
 
 struct r8152;
@@ -514,11 +564,13 @@ struct r8152 {
                void (*init)(struct r8152 *);
                int (*enable)(struct r8152 *);
                void (*disable)(struct r8152 *);
+               void (*up)(struct r8152 *);
                void (*down)(struct r8152 *);
                void (*unload)(struct r8152 *);
        } rtl_ops;
 
        int intr_interval;
+       u32 saved_wolopts;
        u32 msg_enable;
        u32 tx_qlen;
        u16 ocp_base;
@@ -537,12 +589,21 @@ enum rtl_version {
        RTL_VER_MAX
 };
 
+enum tx_csum_stat {
+       TX_CSUM_SUCCESS = 0,
+       TX_CSUM_TSO,
+       TX_CSUM_NONE
+};
+
 /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
  * The RTL chips use a 64 element hash table based on the Ethernet CRC.
  */
 static const int multicast_filter_limit = 32;
 static unsigned int rx_buf_sz = 16384;
 
+#define RTL_LIMITED_TSO_SIZE   (rx_buf_sz - sizeof(struct tx_desc) - \
+                                VLAN_ETH_HLEN - VLAN_HLEN)
+
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
@@ -580,6 +641,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
                               value, index, tmp, size, 500);
 
        kfree(tmp);
+
        return ret;
 }
 
@@ -865,11 +927,21 @@ static u16 sram_read(struct r8152 *tp, u16 addr)
 static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
 {
        struct r8152 *tp = netdev_priv(netdev);
+       int ret;
 
        if (phy_id != R8152_PHY_ID)
                return -EINVAL;
 
-       return r8152_mdio_read(tp, reg);
+       ret = usb_autopm_get_interface(tp->intf);
+       if (ret < 0)
+               goto out;
+
+       ret = r8152_mdio_read(tp, reg);
+
+       usb_autopm_put_interface(tp->intf);
+
+out:
+       return ret;
 }
 
 static
@@ -880,7 +952,12 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val)
        if (phy_id != R8152_PHY_ID)
                return;
 
+       if (usb_autopm_get_interface(tp->intf) < 0)
+               return;
+
        r8152_mdio_write(tp, reg, val);
+
+       usb_autopm_put_interface(tp->intf);
 }
 
 static
@@ -889,11 +966,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
 static inline void set_ethernet_addr(struct r8152 *tp)
 {
        struct net_device *dev = tp->netdev;
+       int ret;
        u8 node_id[8] = {0};
 
-       if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
+       if (tp->version == RTL_VER_01)
+               ret = pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id);
+       else
+               ret = pla_ocp_read(tp, PLA_BACKUP, sizeof(node_id), node_id);
+
+       if (ret < 0) {
                netif_notice(tp, probe, dev, "inet addr fail\n");
-       else {
+       } else {
+               if (tp->version != RTL_VER_01) {
+                       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR,
+                                      CRWECR_CONFIG);
+                       pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES,
+                                     sizeof(node_id), node_id);
+                       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR,
+                                      CRWECR_NORAML);
+               }
+
                memcpy(dev->dev_addr, node_id, dev->addr_len);
                memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        }
@@ -916,15 +1008,9 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
        return 0;
 }
 
-static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 static void read_bulk_callback(struct urb *urb)
 {
        struct net_device *netdev;
-       unsigned long flags;
        int status = urb->status;
        struct rx_agg *agg;
        struct r8152 *tp;
@@ -951,14 +1037,16 @@ static void read_bulk_callback(struct urb *urb)
        if (!netif_carrier_ok(netdev))
                return;
 
+       usb_mark_last_busy(tp->udev);
+
        switch (status) {
        case 0:
                if (urb->actual_length < ETH_ZLEN)
                        break;
 
-               spin_lock_irqsave(&tp->rx_lock, flags);
+               spin_lock(&tp->rx_lock);
                list_add_tail(&agg->list, &tp->rx_done);
-               spin_unlock_irqrestore(&tp->rx_lock, flags);
+               spin_unlock(&tp->rx_lock);
                tasklet_schedule(&tp->tl);
                return;
        case -ESHUTDOWN:
@@ -981,9 +1069,9 @@ static void read_bulk_callback(struct urb *urb)
        if (result == -ENODEV) {
                netif_device_detach(tp->netdev);
        } else if (result) {
-               spin_lock_irqsave(&tp->rx_lock, flags);
+               spin_lock(&tp->rx_lock);
                list_add_tail(&agg->list, &tp->rx_done);
-               spin_unlock_irqrestore(&tp->rx_lock, flags);
+               spin_unlock(&tp->rx_lock);
                tasklet_schedule(&tp->tl);
        }
 }
@@ -991,7 +1079,7 @@ static void read_bulk_callback(struct urb *urb)
 static void write_bulk_callback(struct urb *urb)
 {
        struct net_device_stats *stats;
-       unsigned long flags;
+       struct net_device *netdev;
        struct tx_agg *agg;
        struct r8152 *tp;
        int status = urb->status;
@@ -1004,21 +1092,24 @@ static void write_bulk_callback(struct urb *urb)
        if (!tp)
                return;
 
-       stats = rtl8152_get_stats(tp->netdev);
+       netdev = tp->netdev;
+       stats = &netdev->stats;
        if (status) {
                if (net_ratelimit())
-                       netdev_warn(tp->netdev, "Tx status %d\n", status);
+                       netdev_warn(netdev, "Tx status %d\n", status);
                stats->tx_errors += agg->skb_num;
        } else {
                stats->tx_packets += agg->skb_num;
                stats->tx_bytes += agg->skb_len;
        }
 
-       spin_lock_irqsave(&tp->tx_lock, flags);
+       spin_lock(&tp->tx_lock);
        list_add_tail(&agg->list, &tp->tx_free);
-       spin_unlock_irqrestore(&tp->tx_lock, flags);
+       spin_unlock(&tp->tx_lock);
 
-       if (!netif_carrier_ok(tp->netdev))
+       usb_autopm_put_interface_async(tp->intf);
+
+       if (!netif_carrier_ok(netdev))
                return;
 
        if (!test_bit(WORK_ENABLE, &tp->flags))
@@ -1223,6 +1314,9 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
        struct tx_agg *agg = NULL;
        unsigned long flags;
 
+       if (list_empty(&tp->tx_free))
+               return NULL;
+
        spin_lock_irqsave(&tp->tx_lock, flags);
        if (!list_empty(&tp->tx_free)) {
                struct list_head *cursor;
@@ -1236,24 +1330,138 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
        return agg;
 }
 
-static void
-r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
+static inline __be16 get_protocol(struct sk_buff *skb)
+{
+       __be16 protocol;
+
+       if (skb->protocol == htons(ETH_P_8021Q))
+               protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+       else
+               protocol = skb->protocol;
+
+       return protocol;
+}
+
+/*
+ * r8152_csum_workaround()
+ * The hw limites the value the transport offset. When the offset is out of the
+ * range, calculate the checksum by sw.
+ */
+static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb,
+                                 struct sk_buff_head *list)
+{
+       if (skb_shinfo(skb)->gso_size) {
+               netdev_features_t features = tp->netdev->features;
+               struct sk_buff_head seg_list;
+               struct sk_buff *segs, *nskb;
+
+               features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO);
+               segs = skb_gso_segment(skb, features);
+               if (IS_ERR(segs) || !segs)
+                       goto drop;
+
+               __skb_queue_head_init(&seg_list);
+
+               do {
+                       nskb = segs;
+                       segs = segs->next;
+                       nskb->next = NULL;
+                       __skb_queue_tail(&seg_list, nskb);
+               } while (segs);
+
+               skb_queue_splice(&seg_list, list);
+               dev_kfree_skb(skb);
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               if (skb_checksum_help(skb) < 0)
+                       goto drop;
+
+               __skb_queue_head(list, skb);
+       } else {
+               struct net_device_stats *stats;
+
+drop:
+               stats = &tp->netdev->stats;
+               stats->tx_dropped++;
+               dev_kfree_skb(skb);
+       }
+}
+
+/*
+ * msdn_giant_send_check()
+ * According to the document of microsoft, the TCP Pseudo Header excludes the
+ * packet length for IPv6 TCP large packets.
+ */
+static int msdn_giant_send_check(struct sk_buff *skb)
+{
+       const struct ipv6hdr *ipv6h;
+       struct tcphdr *th;
+       int ret;
+
+       ret = skb_cow_head(skb, 0);
+       if (ret)
+               return ret;
+
+       ipv6h = ipv6_hdr(skb);
+       th = tcp_hdr(skb);
+
+       th->check = 0;
+       th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0);
+
+       return ret;
+}
+
+static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
+                        struct sk_buff *skb, u32 len, u32 transport_offset)
 {
-       memset(desc, 0, sizeof(*desc));
+       u32 mss = skb_shinfo(skb)->gso_size;
+       u32 opts1, opts2 = 0;
+       int ret = TX_CSUM_SUCCESS;
+
+       WARN_ON_ONCE(len > TX_LEN_MAX);
+
+       opts1 = len | TX_FS | TX_LS;
+
+       if (mss) {
+               if (transport_offset > GTTCPHO_MAX) {
+                       netif_warn(tp, tx_err, tp->netdev,
+                                  "Invalid transport offset 0x%x for TSO\n",
+                                  transport_offset);
+                       ret = TX_CSUM_TSO;
+                       goto unavailable;
+               }
 
-       desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
+               switch (get_protocol(skb)) {
+               case htons(ETH_P_IP):
+                       opts1 |= GTSENDV4;
+                       break;
+
+               case htons(ETH_P_IPV6):
+                       if (msdn_giant_send_check(skb)) {
+                               ret = TX_CSUM_TSO;
+                               goto unavailable;
+                       }
+                       opts1 |= GTSENDV6;
+                       break;
+
+               default:
+                       WARN_ON_ONCE(1);
+                       break;
+               }
 
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               __be16 protocol;
+               opts1 |= transport_offset << GTTCPHO_SHIFT;
+               opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 ip_protocol;
-               u32 opts2 = 0;
 
-               if (skb->protocol == htons(ETH_P_8021Q))
-                       protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-               else
-                       protocol = skb->protocol;
+               if (transport_offset > TCPHO_MAX) {
+                       netif_warn(tp, tx_err, tp->netdev,
+                                  "Invalid transport offset 0x%x\n",
+                                  transport_offset);
+                       ret = TX_CSUM_NONE;
+                       goto unavailable;
+               }
 
-               switch (protocol) {
+               switch (get_protocol(skb)) {
                case htons(ETH_P_IP):
                        opts2 |= IPV4_CS;
                        ip_protocol = ip_hdr(skb)->protocol;
@@ -1269,24 +1477,34 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
                        break;
                }
 
-               if (ip_protocol == IPPROTO_TCP) {
+               if (ip_protocol == IPPROTO_TCP)
                        opts2 |= TCP_CS;
-                       opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17;
-               } else if (ip_protocol == IPPROTO_UDP) {
+               else if (ip_protocol == IPPROTO_UDP)
                        opts2 |= UDP_CS;
-               } else {
+               else
                        WARN_ON_ONCE(1);
-               }
 
-               desc->opts2 = cpu_to_le32(opts2);
+               opts2 |= transport_offset << TCPHO_SHIFT;
        }
+
+       desc->opts2 = cpu_to_le32(opts2);
+       desc->opts1 = cpu_to_le32(opts1);
+
+unavailable:
+       return ret;
 }
 
 static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
 {
-       int remain;
+       struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
+       int remain, ret;
        u8 *tx_data;
 
+       __skb_queue_head_init(&skb_head);
+       spin_lock(&tx_queue->lock);
+       skb_queue_splice_init(tx_queue, &skb_head);
+       spin_unlock(&tx_queue->lock);
+
        tx_data = agg->head;
        agg->skb_num = agg->skb_len = 0;
        remain = rx_buf_sz;
@@ -1295,32 +1513,56 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                struct tx_desc *tx_desc;
                struct sk_buff *skb;
                unsigned int len;
+               u32 offset;
 
-               skb = skb_dequeue(&tp->tx_queue);
+               skb = __skb_dequeue(&skb_head);
                if (!skb)
                        break;
 
-               remain -= sizeof(*tx_desc);
-               len = skb->len;
-               if (remain < len) {
-                       skb_queue_head(&tp->tx_queue, skb);
+               len = skb->len + sizeof(*tx_desc);
+
+               if (len > remain) {
+                       __skb_queue_head(&skb_head, skb);
                        break;
                }
 
                tx_data = tx_agg_align(tx_data);
                tx_desc = (struct tx_desc *)tx_data;
+
+               offset = (u32)skb_transport_offset(skb);
+
+               if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) {
+                       r8152_csum_workaround(tp, skb, &skb_head);
+                       continue;
+               }
+
                tx_data += sizeof(*tx_desc);
 
-               r8152_tx_csum(tp, tx_desc, skb);
-               memcpy(tx_data, skb->data, len);
-               agg->skb_num++;
+               len = skb->len;
+               if (skb_copy_bits(skb, 0, tx_data, len) < 0) {
+                       struct net_device_stats *stats = &tp->netdev->stats;
+
+                       stats->tx_dropped++;
+                       dev_kfree_skb_any(skb);
+                       tx_data -= sizeof(*tx_desc);
+                       continue;
+               }
+
+               tx_data += len;
                agg->skb_len += len;
+               agg->skb_num++;
+
                dev_kfree_skb_any(skb);
 
-               tx_data += len;
                remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head);
        }
 
+       if (!skb_queue_empty(&skb_head)) {
+               spin_lock(&tx_queue->lock);
+               skb_queue_splice(&skb_head, tx_queue);
+               spin_unlock(&tx_queue->lock);
+       }
+
        netif_tx_lock(tp->netdev);
 
        if (netif_queue_stopped(tp->netdev) &&
@@ -1329,20 +1571,67 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
 
        netif_tx_unlock(tp->netdev);
 
+       ret = usb_autopm_get_interface_async(tp->intf);
+       if (ret < 0)
+               goto out_tx_fill;
+
        usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
                          agg->head, (int)(tx_data - (u8 *)agg->head),
                          (usb_complete_t)write_bulk_callback, agg);
 
-       return usb_submit_urb(agg->urb, GFP_ATOMIC);
+       ret = usb_submit_urb(agg->urb, GFP_ATOMIC);
+       if (ret < 0)
+               usb_autopm_put_interface_async(tp->intf);
+
+out_tx_fill:
+       return ret;
+}
+
+static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc)
+{
+       u8 checksum = CHECKSUM_NONE;
+       u32 opts2, opts3;
+
+       if (tp->version == RTL_VER_01)
+               goto return_result;
+
+       opts2 = le32_to_cpu(rx_desc->opts2);
+       opts3 = le32_to_cpu(rx_desc->opts3);
+
+       if (opts2 & RD_IPV4_CS) {
+               if (opts3 & IPF)
+                       checksum = CHECKSUM_NONE;
+               else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF))
+                       checksum = CHECKSUM_NONE;
+               else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF))
+                       checksum = CHECKSUM_NONE;
+               else
+                       checksum = CHECKSUM_UNNECESSARY;
+       } else if (RD_IPV6_CS) {
+               if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF))
+                       checksum = CHECKSUM_UNNECESSARY;
+               else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF))
+                       checksum = CHECKSUM_UNNECESSARY;
+       }
+
+return_result:
+       return checksum;
 }
 
 static void rx_bottom(struct r8152 *tp)
 {
        unsigned long flags;
-       struct list_head *cursor, *next;
+       struct list_head *cursor, *next, rx_queue;
+
+       if (list_empty(&tp->rx_done))
+               return;
 
+       INIT_LIST_HEAD(&rx_queue);
        spin_lock_irqsave(&tp->rx_lock, flags);
-       list_for_each_safe(cursor, next, &tp->rx_done) {
+       list_splice_init(&tp->rx_done, &rx_queue);
+       spin_unlock_irqrestore(&tp->rx_lock, flags);
+
+       list_for_each_safe(cursor, next, &rx_queue) {
                struct rx_desc *rx_desc;
                struct rx_agg *agg;
                int len_used = 0;
@@ -1351,7 +1640,6 @@ static void rx_bottom(struct r8152 *tp)
                int ret;
 
                list_del_init(cursor);
-               spin_unlock_irqrestore(&tp->rx_lock, flags);
 
                agg = list_entry(cursor, struct rx_agg, list);
                urb = agg->urb;
@@ -1364,7 +1652,7 @@ static void rx_bottom(struct r8152 *tp)
 
                while (urb->actual_length > len_used) {
                        struct net_device *netdev = tp->netdev;
-                       struct net_device_stats *stats;
+                       struct net_device_stats *stats = &netdev->stats;
                        unsigned int pkt_len;
                        struct sk_buff *skb;
 
@@ -1376,23 +1664,24 @@ static void rx_bottom(struct r8152 *tp)
                        if (urb->actual_length < len_used)
                                break;
 
-                       stats = rtl8152_get_stats(netdev);
-
                        pkt_len -= CRC_SIZE;
                        rx_data += sizeof(struct rx_desc);
 
                        skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
                        if (!skb) {
                                stats->rx_dropped++;
-                               break;
+                               goto find_next_rx;
                        }
+
+                       skb->ip_summed = r8152_rx_csum(tp, rx_desc);
                        memcpy(skb->data, rx_data, pkt_len);
                        skb_put(skb, pkt_len);
                        skb->protocol = eth_type_trans(skb, netdev);
-                       netif_rx(skb);
+                       netif_receive_skb(skb);
                        stats->rx_packets++;
                        stats->rx_bytes += pkt_len;
 
+find_next_rx:
                        rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE);
                        rx_desc = (struct rx_desc *)rx_data;
                        len_used = (int)(rx_data - (u8 *)agg->head);
@@ -1401,13 +1690,13 @@ static void rx_bottom(struct r8152 *tp)
 
 submit:
                ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
-               spin_lock_irqsave(&tp->rx_lock, flags);
                if (ret && ret != -ENODEV) {
-                       list_add_tail(&agg->list, next);
+                       spin_lock_irqsave(&tp->rx_lock, flags);
+                       list_add_tail(&agg->list, &tp->rx_done);
+                       spin_unlock_irqrestore(&tp->rx_lock, flags);
                        tasklet_schedule(&tp->tl);
                }
        }
-       spin_unlock_irqrestore(&tp->rx_lock, flags);
 }
 
 static void tx_bottom(struct r8152 *tp)
@@ -1426,19 +1715,18 @@ static void tx_bottom(struct r8152 *tp)
 
                res = r8152_tx_agg_fill(tp, agg);
                if (res) {
-                       struct net_device_stats *stats;
-                       struct net_device *netdev;
-                       unsigned long flags;
-
-                       netdev = tp->netdev;
-                       stats = rtl8152_get_stats(netdev);
+                       struct net_device *netdev = tp->netdev;
 
                        if (res == -ENODEV) {
                                netif_device_detach(netdev);
                        } else {
+                               struct net_device_stats *stats = &netdev->stats;
+                               unsigned long flags;
+
                                netif_warn(tp, tx_err, netdev,
                                           "failed tx_urb %d\n", res);
                                stats->tx_dropped += agg->skb_num;
+
                                spin_lock_irqsave(&tp->tx_lock, flags);
                                list_add_tail(&agg->list, &tp->tx_free);
                                spin_unlock_irqrestore(&tp->tx_lock, flags);
@@ -1478,6 +1766,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
        return usb_submit_urb(agg->urb, mem_flags);
 }
 
+static void rtl_drop_queued_tx(struct r8152 *tp)
+{
+       struct net_device_stats *stats = &tp->netdev->stats;
+       struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue;
+       struct sk_buff *skb;
+
+       if (skb_queue_empty(tx_queue))
+               return;
+
+       __skb_queue_head_init(&skb_head);
+       spin_lock_bh(&tx_queue->lock);
+       skb_queue_splice_init(tx_queue, &skb_head);
+       spin_unlock_bh(&tx_queue->lock);
+
+       while ((skb = __skb_dequeue(&skb_head))) {
+               dev_kfree_skb(skb);
+               stats->tx_dropped++;
+       }
+}
+
 static void rtl8152_tx_timeout(struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
@@ -1541,7 +1849,7 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
 }
 
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
-                                           struct net_device *netdev)
+                                       struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
 
@@ -1549,13 +1857,17 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
 
        skb_queue_tail(&tp->tx_queue, skb);
 
-       if (list_empty(&tp->tx_free) &&
-           skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
+       if (!list_empty(&tp->tx_free)) {
+               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+                       set_bit(SCHEDULE_TASKLET, &tp->flags);
+                       schedule_delayed_work(&tp->schedule, 0);
+               } else {
+                       usb_mark_last_busy(tp->udev);
+                       tasklet_schedule(&tp->tl);
+               }
+       } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen)
                netif_stop_queue(netdev);
 
-       if (!list_empty(&tp->tx_free))
-               tasklet_schedule(&tp->tl);
-
        return NETDEV_TX_OK;
 }
 
@@ -1613,6 +1925,18 @@ static void rtl_set_eee_plus(struct r8152 *tp)
        }
 }
 
+static void rxdy_gated_en(struct r8152 *tp, bool enable)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
+       if (enable)
+               ocp_data |= RXDY_GATED_EN;
+       else
+               ocp_data &= ~RXDY_GATED_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+}
+
 static int rtl_enable(struct r8152 *tp)
 {
        u32 ocp_data;
@@ -1624,9 +1948,7 @@ static int rtl_enable(struct r8152 *tp)
        ocp_data |= CR_RE | CR_TE;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-       ocp_data &= ~RXDY_GATED_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+       rxdy_gated_en(tp, false);
 
        INIT_LIST_HEAD(&tp->rx_done);
        ret = 0;
@@ -1681,8 +2003,6 @@ static int rtl8153_enable(struct r8152 *tp)
 
 static void rtl8152_disable(struct r8152 *tp)
 {
-       struct net_device_stats *stats = rtl8152_get_stats(tp->netdev);
-       struct sk_buff *skb;
        u32 ocp_data;
        int i;
 
@@ -1690,17 +2010,12 @@ static void rtl8152_disable(struct r8152 *tp)
        ocp_data &= ~RCR_ACPT_ALL;
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
 
-       while ((skb = skb_dequeue(&tp->tx_queue))) {
-               dev_kfree_skb(skb);
-               stats->tx_dropped++;
-       }
+       rtl_drop_queued_tx(tp);
 
        for (i = 0; i < RTL8152_MAX_TX; i++)
                usb_kill_urb(tp->tx_info[i].urb);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-       ocp_data |= RXDY_GATED_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+       rxdy_gated_en(tp, true);
 
        for (i = 0; i < 1000; i++) {
                ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
@@ -1721,80 +2036,271 @@ static void rtl8152_disable(struct r8152 *tp)
        rtl8152_nic_reset(tp);
 }
 
-static void r8152b_exit_oob(struct r8152 *tp)
+static void r8152_power_cut_en(struct r8152 *tp, bool enable)
 {
-       u32     ocp_data;
-       int     i;
+       u32 ocp_data;
 
-       ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
-       ocp_data &= ~RCR_ACPT_ALL;
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
+       if (enable)
+               ocp_data |= POWER_CUT;
+       else
+               ocp_data &= ~POWER_CUT;
+       ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-       ocp_data |= RXDY_GATED_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
+       ocp_data &= ~RESUME_INDICATE;
+       ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+}
 
-       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
-       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
+#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
 
-       ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-       ocp_data &= ~NOW_IS_OOB;
-       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+static u32 __rtl_get_wol(struct r8152 *tp)
+{
+       u32 ocp_data;
+       u32 wolopts = 0;
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-       ocp_data &= ~MCU_BORW_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+       ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+       if (!(ocp_data & LAN_WAKE_EN))
+               return 0;
 
-       for (i = 0; i < 1000; i++) {
-               ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-               if (ocp_data & LINK_LIST_READY)
-                       break;
-               mdelay(1);
-       }
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+       if (ocp_data & LINK_ON_WAKE_EN)
+               wolopts |= WAKE_PHY;
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
-       ocp_data |= RE_INIT_LL;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+       if (ocp_data & UWF_EN)
+               wolopts |= WAKE_UCAST;
+       if (ocp_data & BWF_EN)
+               wolopts |= WAKE_BCAST;
+       if (ocp_data & MWF_EN)
+               wolopts |= WAKE_MCAST;
 
-       for (i = 0; i < 1000; i++) {
-               ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
-               if (ocp_data & LINK_LIST_READY)
-                       break;
-               mdelay(1);
-       }
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
+       if (ocp_data & MAGIC_EN)
+               wolopts |= WAKE_MAGIC;
 
-       rtl8152_nic_reset(tp);
+       return wolopts;
+}
 
-       /* rx share fifo credit full threshold */
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
+static void __rtl_set_wol(struct r8152 *tp, u32 wolopts)
+{
+       u32 ocp_data;
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_DEV_STAT);
-       ocp_data &= STAT_SPEED_MASK;
-       if (ocp_data == STAT_SPEED_FULL) {
-               /* rx share fifo credit near full threshold */
-               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
-                               RXFIFO_THR2_FULL);
-               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
-                               RXFIFO_THR3_FULL);
-       } else {
-               /* rx share fifo credit near full threshold */
-               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
-                               RXFIFO_THR2_HIGH);
-               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
-                               RXFIFO_THR3_HIGH);
-       }
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
 
-       /* TX share fifo free credit full threshold */
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+       ocp_data &= ~LINK_ON_WAKE_EN;
+       if (wolopts & WAKE_PHY)
+               ocp_data |= LINK_ON_WAKE_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5);
+       ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN);
+       if (wolopts & WAKE_UCAST)
+               ocp_data |= UWF_EN;
+       if (wolopts & WAKE_BCAST)
+               ocp_data |= BWF_EN;
+       if (wolopts & WAKE_MCAST)
+               ocp_data |= MWF_EN;
+       if (wolopts & WAKE_ANY)
+               ocp_data |= LAN_WAKE_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
 
-       ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
-       ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
-       ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
-                       TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
-       ocp_data &= ~CPCR_RX_VLAN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
+       ocp_data &= ~MAGIC_EN;
+       if (wolopts & WAKE_MAGIC)
+               ocp_data |= MAGIC_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
+
+       if (wolopts & WAKE_ANY)
+               device_set_wakeup_enable(&tp->udev->dev, true);
+       else
+               device_set_wakeup_enable(&tp->udev->dev, false);
+}
+
+static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable)
+{
+       if (enable) {
+               u32 ocp_data;
+
+               __rtl_set_wol(tp, WAKE_ANY);
+
+               ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+
+               ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34);
+               ocp_data |= LINK_OFF_WAKE_EN;
+               ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+
+               ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+       } else {
+               __rtl_set_wol(tp, tp->saved_wolopts);
+       }
+}
+
+static void rtl_phy_reset(struct r8152 *tp)
+{
+       u16 data;
+       int i;
+
+       clear_bit(PHY_RESET, &tp->flags);
+
+       data = r8152_mdio_read(tp, MII_BMCR);
+
+       /* don't reset again before the previous one complete */
+       if (data & BMCR_RESET)
+               return;
+
+       data |= BMCR_RESET;
+       r8152_mdio_write(tp, MII_BMCR, data);
+
+       for (i = 0; i < 50; i++) {
+               msleep(20);
+               if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
+                       break;
+       }
+}
+
+static void rtl_clear_bp(struct r8152 *tp)
+{
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
+       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
+       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
+       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
+       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
+       mdelay(3);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
+       ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
+}
+
+static void r8153_clear_bp(struct r8152 *tp)
+{
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
+       ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
+       rtl_clear_bp(tp);
+}
+
+static void r8153_teredo_off(struct r8152 *tp)
+{
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
+       ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
+
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
+}
+
+static void r8152b_disable_aldps(struct r8152 *tp)
+{
+       ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
+       msleep(20);
+}
+
+static inline void r8152b_enable_aldps(struct r8152 *tp)
+{
+       ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
+                                           LINKENA | DIS_SDSAVE);
+}
+
+static void r8152b_hw_phy_cfg(struct r8152 *tp)
+{
+       u16 data;
+
+       data = r8152_mdio_read(tp, MII_BMCR);
+       if (data & BMCR_PDOWN) {
+               data &= ~BMCR_PDOWN;
+               r8152_mdio_write(tp, MII_BMCR, data);
+       }
+
+       r8152b_disable_aldps(tp);
+
+       rtl_clear_bp(tp);
+
+       r8152b_enable_aldps(tp);
+       set_bit(PHY_RESET, &tp->flags);
+}
+
+static void r8152b_exit_oob(struct r8152 *tp)
+{
+       u32 ocp_data;
+       int i;
+
+       ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+       ocp_data &= ~RCR_ACPT_ALL;
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+       rxdy_gated_en(tp, true);
+       r8153_teredo_off(tp);
+       r8152b_hw_phy_cfg(tp);
+
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00);
+
+       ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+       ocp_data &= ~NOW_IS_OOB;
+       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+       ocp_data &= ~MCU_BORW_EN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+       for (i = 0; i < 1000; i++) {
+               ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+               if (ocp_data & LINK_LIST_READY)
+                       break;
+               mdelay(1);
+       }
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7);
+       ocp_data |= RE_INIT_LL;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+       for (i = 0; i < 1000; i++) {
+               ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL);
+               if (ocp_data & LINK_LIST_READY)
+                       break;
+               mdelay(1);
+       }
+
+       rtl8152_nic_reset(tp);
+
+       /* rx share fifo credit full threshold */
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_DEV_STAT);
+       ocp_data &= STAT_SPEED_MASK;
+       if (ocp_data == STAT_SPEED_FULL) {
+               /* rx share fifo credit near full threshold */
+               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+                               RXFIFO_THR2_FULL);
+               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+                               RXFIFO_THR3_FULL);
+       } else {
+               /* rx share fifo credit near full threshold */
+               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+                               RXFIFO_THR2_HIGH);
+               ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+                               RXFIFO_THR3_HIGH);
+       }
+
+       /* TX share fifo free credit full threshold */
+       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
+
+       ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
+       ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
+       ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA,
+                       TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
+       ocp_data &= ~CPCR_RX_VLAN;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
 
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
 
@@ -1838,10 +2344,6 @@ static void r8152b_enter_oob(struct r8152 *tp)
 
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
-       ocp_data |= MAGIC_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
-
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR);
        ocp_data |= CPCR_RX_VLAN;
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
@@ -1854,36 +2356,26 @@ static void r8152b_enter_oob(struct r8152 *tp)
        ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
-       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-       ocp_data &= ~RXDY_GATED_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+       rxdy_gated_en(tp, false);
 
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
        ocp_data |= RCR_APM | RCR_AM | RCR_AB;
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
 }
 
-static void r8152b_disable_aldps(struct r8152 *tp)
-{
-       ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
-       msleep(20);
-}
-
-static inline void r8152b_enable_aldps(struct r8152 *tp)
-{
-       ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
-                                           LINKENA | DIS_SDSAVE);
-}
-
 static void r8153_hw_phy_cfg(struct r8152 *tp)
 {
        u32 ocp_data;
        u16 data;
 
        ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L);
-       r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
+       data = r8152_mdio_read(tp, MII_BMCR);
+       if (data & BMCR_PDOWN) {
+               data &= ~BMCR_PDOWN;
+               r8152_mdio_write(tp, MII_BMCR, data);
+       }
+
+       r8153_clear_bp(tp);
 
        if (tp->version == RTL_VER_03) {
                data = ocp_reg_read(tp, OCP_EEE_CFG);
@@ -1919,9 +2411,11 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
        data = sram_read(tp, SRAM_10M_AMP2);
        data |= AMP_DN;
        sram_write(tp, SRAM_10M_AMP2, data);
+
+       set_bit(PHY_RESET, &tp->flags);
 }
 
-static void r8153_u1u2en(struct r8152 *tp, int enable)
+static void r8153_u1u2en(struct r8152 *tp, bool enable)
 {
        u8 u1u2[8];
 
@@ -1933,7 +2427,7 @@ static void r8153_u1u2en(struct r8152 *tp, int enable)
        usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2);
 }
 
-static void r8153_u2p3en(struct r8152 *tp, int enable)
+static void r8153_u2p3en(struct r8152 *tp, bool enable)
 {
        u32 ocp_data;
 
@@ -1945,7 +2439,7 @@ static void r8153_u2p3en(struct r8152 *tp, int enable)
        ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data);
 }
 
-static void r8153_power_cut_en(struct r8152 *tp, int enable)
+static void r8153_power_cut_en(struct r8152 *tp, bool enable)
 {
        u32 ocp_data;
 
@@ -1961,28 +2455,12 @@ static void r8153_power_cut_en(struct r8152 *tp, int enable)
        ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data);
 }
 
-static void r8153_teredo_off(struct r8152 *tp)
-{
-       u32 ocp_data;
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
-       ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN);
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
-
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
-}
-
 static void r8153_first_init(struct r8152 *tp)
 {
        u32 ocp_data;
        int i;
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-       ocp_data |= RXDY_GATED_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
-
+       rxdy_gated_en(tp, true);
        r8153_teredo_off(tp);
 
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -2075,10 +2553,6 @@ static void r8153_enter_oob(struct r8152 *tp)
 
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
 
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL);
-       ocp_data |= MAGIC_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
-
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG);
        ocp_data &= ~TEREDO_WAKE_MASK;
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
@@ -2095,11 +2569,7 @@ static void r8153_enter_oob(struct r8152 *tp)
        ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
        ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
 
-       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN);
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
-       ocp_data &= ~RXDY_GATED_EN;
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+       rxdy_gated_en(tp, false);
 
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
        ocp_data |= RCR_APM | RCR_AM | RCR_AB;
@@ -2190,12 +2660,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
                bmcr = BMCR_ANENABLE | BMCR_ANRESTART;
        }
 
+       if (test_bit(PHY_RESET, &tp->flags))
+               bmcr |= BMCR_RESET;
+
        if (tp->mii.supports_gmii)
                r8152_mdio_write(tp, MII_CTRL1000, gbcr);
 
        r8152_mdio_write(tp, MII_ADVERTISE, anar);
        r8152_mdio_write(tp, MII_BMCR, bmcr);
 
+       if (test_bit(PHY_RESET, &tp->flags)) {
+               int i;
+
+               clear_bit(PHY_RESET, &tp->flags);
+               for (i = 0; i < 50; i++) {
+                       msleep(20);
+                       if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0)
+                               break;
+               }
+       }
+
 out:
 
        return ret;
@@ -2203,12 +2687,7 @@ out:
 
 static void rtl8152_down(struct r8152 *tp)
 {
-       u32     ocp_data;
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
-       ocp_data &= ~POWER_CUT;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-
+       r8152_power_cut_en(tp, false);
        r8152b_disable_aldps(tp);
        r8152b_enter_oob(tp);
        r8152b_enable_aldps(tp);
@@ -2216,8 +2695,8 @@ static void rtl8152_down(struct r8152 *tp)
 
 static void rtl8153_down(struct r8152 *tp)
 {
-       r8153_u1u2en(tp, 0);
-       r8153_power_cut_en(tp, 0);
+       r8153_u1u2en(tp, false);
+       r8153_power_cut_en(tp, false);
        r8153_disable_aldps(tp);
        r8153_enter_oob(tp);
        r8153_enable_aldps(tp);
@@ -2252,6 +2731,9 @@ static void rtl_work_func_t(struct work_struct *work)
 {
        struct r8152 *tp = container_of(work, struct r8152, schedule.work);
 
+       if (usb_autopm_get_interface(tp->intf) < 0)
+               return;
+
        if (!test_bit(WORK_ENABLE, &tp->flags))
                goto out1;
 
@@ -2264,8 +2746,17 @@ static void rtl_work_func_t(struct work_struct *work)
        if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
                _rtl8152_set_rx_mode(tp->netdev);
 
+       if (test_bit(SCHEDULE_TASKLET, &tp->flags) &&
+           (tp->speed & LINK_STATUS)) {
+               clear_bit(SCHEDULE_TASKLET, &tp->flags);
+               tasklet_schedule(&tp->tl);
+       }
+
+       if (test_bit(PHY_RESET, &tp->flags))
+               rtl_phy_reset(tp);
+
 out1:
-       return;
+       usb_autopm_put_interface(tp->intf);
 }
 
 static int rtl8152_open(struct net_device *netdev)
@@ -2273,15 +2764,27 @@ static int rtl8152_open(struct net_device *netdev)
        struct r8152 *tp = netdev_priv(netdev);
        int res = 0;
 
-       res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
-       if (res) {
-               if (res == -ENODEV)
-                       netif_device_detach(tp->netdev);
-               netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
-                          res);
-               return res;
+       res = alloc_all_mem(tp);
+       if (res)
+               goto out;
+
+       res = usb_autopm_get_interface(tp->intf);
+       if (res < 0) {
+               free_all_mem(tp);
+               goto out;
        }
 
+       /* The WORK_ENABLE may be set when autoresume occurs */
+       if (test_bit(WORK_ENABLE, &tp->flags)) {
+               clear_bit(WORK_ENABLE, &tp->flags);
+               usb_kill_urb(tp->intr_urb);
+               cancel_delayed_work_sync(&tp->schedule);
+               if (tp->speed & LINK_STATUS)
+                       tp->rtl_ops.disable(tp);
+       }
+
+       tp->rtl_ops.up(tp);
+
        rtl8152_set_speed(tp, AUTONEG_ENABLE,
                          tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
                          DUPLEX_FULL);
@@ -2290,6 +2793,18 @@ static int rtl8152_open(struct net_device *netdev)
        netif_start_queue(netdev);
        set_bit(WORK_ENABLE, &tp->flags);
 
+       res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
+       if (res) {
+               if (res == -ENODEV)
+                       netif_device_detach(tp->netdev);
+               netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n",
+                          res);
+               free_all_mem(tp);
+       }
+
+       usb_autopm_put_interface(tp->intf);
+
+out:
        return res;
 }
 
@@ -2298,37 +2813,34 @@ static int rtl8152_close(struct net_device *netdev)
        struct r8152 *tp = netdev_priv(netdev);
        int res = 0;
 
-       usb_kill_urb(tp->intr_urb);
        clear_bit(WORK_ENABLE, &tp->flags);
+       usb_kill_urb(tp->intr_urb);
        cancel_delayed_work_sync(&tp->schedule);
        netif_stop_queue(netdev);
-       tasklet_disable(&tp->tl);
-       tp->rtl_ops.disable(tp);
-       tasklet_enable(&tp->tl);
 
-       return res;
-}
+       res = usb_autopm_get_interface(tp->intf);
+       if (res < 0) {
+               rtl_drop_queued_tx(tp);
+       } else {
+               /*
+                * The autosuspend may have been enabled and wouldn't
+                * be disable when autoresume occurs, because the
+                * netif_running() would be false.
+                */
+               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+                       rtl_runtime_suspend_enable(tp, false);
+                       clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+               }
 
-static void rtl_clear_bp(struct r8152 *tp)
-{
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0);
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0);
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0);
-       ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0);
-       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0);
-       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0);
-       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0);
-       ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0);
-       mdelay(3);
-       ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0);
-       ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0);
-}
+               tasklet_disable(&tp->tl);
+               tp->rtl_ops.down(tp);
+               tasklet_enable(&tp->tl);
+               usb_autopm_put_interface(tp->intf);
+       }
 
-static void r8153_clear_bp(struct r8152 *tp)
-{
-       ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0);
-       ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0);
-       rtl_clear_bp(tp);
+       free_all_mem(tp);
+
+       return res;
 }
 
 static void r8152b_enable_eee(struct r8152 *tp)
@@ -2379,18 +2891,18 @@ static void r8152b_enable_fc(struct r8152 *tp)
        r8152_mdio_write(tp, MII_ADVERTISE, anar);
 }
 
-static void r8152b_hw_phy_cfg(struct r8152 *tp)
+static void rtl_tally_reset(struct r8152 *tp)
 {
-       r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE);
-       r8152b_disable_aldps(tp);
+       u32 ocp_data;
+
+       ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY);
+       ocp_data |= TALLY_RESET;
+       ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
 }
 
 static void r8152b_init(struct r8152 *tp)
 {
        u32 ocp_data;
-       int i;
-
-       rtl_clear_bp(tp);
 
        if (tp->version == RTL_VER_01) {
                ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
@@ -2398,17 +2910,7 @@ static void r8152b_init(struct r8152 *tp)
                ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
        }
 
-       r8152b_hw_phy_cfg(tp);
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
-       ocp_data &= ~POWER_CUT;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
-       ocp_data &= ~RESUME_INDICATE;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
-
-       r8152b_exit_oob(tp);
+       r8152_power_cut_en(tp, false);
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
        ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
@@ -2424,14 +2926,7 @@ static void r8152b_init(struct r8152 *tp)
        r8152b_enable_eee(tp);
        r8152b_enable_aldps(tp);
        r8152b_enable_fc(tp);
-
-       r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
-                                      BMCR_ANRESTART);
-       for (i = 0; i < 100; i++) {
-               udelay(100);
-               if (!(r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET))
-                       break;
-       }
+       rtl_tally_reset(tp);
 
        /* enable rx aggregation */
        ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
@@ -2444,7 +2939,7 @@ static void r8153_init(struct r8152 *tp)
        u32 ocp_data;
        int i;
 
-       r8153_u1u2en(tp, 0);
+       r8153_u1u2en(tp, false);
 
        for (i = 0; i < 500; i++) {
                if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) &
@@ -2460,14 +2955,12 @@ static void r8153_init(struct r8152 *tp)
                msleep(20);
        }
 
-       r8153_u2p3en(tp, 0);
+       r8153_u2p3en(tp, false);
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
        ocp_data &= ~TIMER11_EN;
        ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
 
-       r8153_clear_bp(tp);
-
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE);
        ocp_data &= ~LED_MODE_MASK;
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
@@ -2485,10 +2978,8 @@ static void r8153_init(struct r8152 *tp)
        ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
        ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
 
-       r8153_power_cut_en(tp, 0);
-       r8153_u1u2en(tp, 1);
-
-       r8153_first_init(tp);
+       r8153_power_cut_en(tp, false);
+       r8153_u1u2en(tp, true);
 
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO);
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO);
@@ -2503,26 +2994,31 @@ static void r8153_init(struct r8152 *tp)
        r8153_enable_eee(tp);
        r8153_enable_aldps(tp);
        r8152b_enable_fc(tp);
-
-       r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE |
-                                      BMCR_ANRESTART);
+       rtl_tally_reset(tp);
 }
 
 static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct r8152 *tp = usb_get_intfdata(intf);
 
-       netif_device_detach(tp->netdev);
+       if (PMSG_IS_AUTO(message))
+               set_bit(SELECTIVE_SUSPEND, &tp->flags);
+       else
+               netif_device_detach(tp->netdev);
 
        if (netif_running(tp->netdev)) {
                clear_bit(WORK_ENABLE, &tp->flags);
                usb_kill_urb(tp->intr_urb);
                cancel_delayed_work_sync(&tp->schedule);
-               tasklet_disable(&tp->tl);
+               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+                       rtl_runtime_suspend_enable(tp, true);
+               } else {
+                       tasklet_disable(&tp->tl);
+                       tp->rtl_ops.down(tp);
+                       tasklet_enable(&tp->tl);
+               }
        }
 
-       tp->rtl_ops.down(tp);
-
        return 0;
 }
 
@@ -2530,22 +3026,77 @@ static int rtl8152_resume(struct usb_interface *intf)
 {
        struct r8152 *tp = usb_get_intfdata(intf);
 
-       tp->rtl_ops.init(tp);
-       netif_device_attach(tp->netdev);
+       if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+               tp->rtl_ops.init(tp);
+               netif_device_attach(tp->netdev);
+       }
+
        if (netif_running(tp->netdev)) {
-               rtl8152_set_speed(tp, AUTONEG_ENABLE,
+               if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+                       rtl_runtime_suspend_enable(tp, false);
+                       clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+                       if (tp->speed & LINK_STATUS)
+                               tp->rtl_ops.disable(tp);
+               } else {
+                       tp->rtl_ops.up(tp);
+                       rtl8152_set_speed(tp, AUTONEG_ENABLE,
                                tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
                                DUPLEX_FULL);
+               }
                tp->speed = 0;
                netif_carrier_off(tp->netdev);
                set_bit(WORK_ENABLE, &tp->flags);
                usb_submit_urb(tp->intr_urb, GFP_KERNEL);
-               tasklet_enable(&tp->tl);
        }
 
        return 0;
 }
 
+static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct r8152 *tp = netdev_priv(dev);
+
+       if (usb_autopm_get_interface(tp->intf) < 0)
+               return;
+
+       wol->supported = WAKE_ANY;
+       wol->wolopts = __rtl_get_wol(tp);
+
+       usb_autopm_put_interface(tp->intf);
+}
+
+static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct r8152 *tp = netdev_priv(dev);
+       int ret;
+
+       ret = usb_autopm_get_interface(tp->intf);
+       if (ret < 0)
+               goto out_set_wol;
+
+       __rtl_set_wol(tp, wol->wolopts);
+       tp->saved_wolopts = wol->wolopts & WAKE_ANY;
+
+       usb_autopm_put_interface(tp->intf);
+
+out_set_wol:
+       return ret;
+}
+
+static u32 rtl8152_get_msglevel(struct net_device *dev)
+{
+       struct r8152 *tp = netdev_priv(dev);
+
+       return tp->msg_enable;
+}
+
+static void rtl8152_set_msglevel(struct net_device *dev, u32 value)
+{
+       struct r8152 *tp = netdev_priv(dev);
+
+       tp->msg_enable = value;
+}
+
 static void rtl8152_get_drvinfo(struct net_device *netdev,
                                struct ethtool_drvinfo *info)
 {
@@ -2570,8 +3121,76 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
 static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct r8152 *tp = netdev_priv(dev);
+       int ret;
+
+       ret = usb_autopm_get_interface(tp->intf);
+       if (ret < 0)
+               goto out;
+
+       ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
 
-       return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex);
+       usb_autopm_put_interface(tp->intf);
+
+out:
+       return ret;
+}
+
+static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = {
+       "tx_packets",
+       "rx_packets",
+       "tx_errors",
+       "rx_errors",
+       "rx_missed",
+       "align_errors",
+       "tx_single_collisions",
+       "tx_multi_collisions",
+       "rx_unicast",
+       "rx_broadcast",
+       "rx_multicast",
+       "tx_aborted",
+       "tx_underrun",
+};
+
+static int rtl8152_get_sset_count(struct net_device *dev, int sset)
+{
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(rtl8152_gstrings);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void rtl8152_get_ethtool_stats(struct net_device *dev,
+                                     struct ethtool_stats *stats, u64 *data)
+{
+       struct r8152 *tp = netdev_priv(dev);
+       struct tally_counter tally;
+
+       generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA);
+
+       data[0] = le64_to_cpu(tally.tx_packets);
+       data[1] = le64_to_cpu(tally.rx_packets);
+       data[2] = le64_to_cpu(tally.tx_errors);
+       data[3] = le32_to_cpu(tally.rx_errors);
+       data[4] = le16_to_cpu(tally.rx_missed);
+       data[5] = le16_to_cpu(tally.align_errors);
+       data[6] = le32_to_cpu(tally.tx_one_collision);
+       data[7] = le32_to_cpu(tally.tx_multi_collision);
+       data[8] = le64_to_cpu(tally.rx_unicast);
+       data[9] = le64_to_cpu(tally.rx_broadcast);
+       data[10] = le32_to_cpu(tally.rx_multicast);
+       data[11] = le16_to_cpu(tally.tx_aborted);
+       data[12] = le16_to_cpu(tally.tx_underun);
+}
+
+static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+       switch (stringset) {
+       case ETH_SS_STATS:
+               memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings));
+               break;
+       }
 }
 
 static struct ethtool_ops ops = {
@@ -2579,13 +3198,24 @@ static struct ethtool_ops ops = {
        .get_settings = rtl8152_get_settings,
        .set_settings = rtl8152_set_settings,
        .get_link = ethtool_op_get_link,
+       .get_msglevel = rtl8152_get_msglevel,
+       .set_msglevel = rtl8152_set_msglevel,
+       .get_wol = rtl8152_get_wol,
+       .set_wol = rtl8152_set_wol,
+       .get_strings = rtl8152_get_strings,
+       .get_sset_count = rtl8152_get_sset_count,
+       .get_ethtool_stats = rtl8152_get_ethtool_stats,
 };
 
 static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
 {
        struct r8152 *tp = netdev_priv(netdev);
        struct mii_ioctl_data *data = if_mii(rq);
-       int res = 0;
+       int res;
+
+       res = usb_autopm_get_interface(tp->intf);
+       if (res < 0)
+               goto out;
 
        switch (cmd) {
        case SIOCGMIIPHY:
@@ -2608,6 +3238,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
                res = -EOPNOTSUPP;
        }
 
+       usb_autopm_put_interface(tp->intf);
+
+out:
        return res;
 }
 
@@ -2660,22 +3293,13 @@ static void r8152b_get_version(struct r8152 *tp)
 
 static void rtl8152_unload(struct r8152 *tp)
 {
-       u32     ocp_data;
-
-       if (tp->version != RTL_VER_01) {
-               ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL);
-               ocp_data |= POWER_CUT;
-               ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
-       }
-
-       ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
-       ocp_data &= ~RESUME_INDICATE;
-       ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+       if (tp->version != RTL_VER_01)
+               r8152_power_cut_en(tp, true);
 }
 
 static void rtl8153_unload(struct r8152 *tp)
 {
-       r8153_power_cut_en(tp, 1);
+       r8153_power_cut_en(tp, true);
 }
 
 static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
@@ -2690,6 +3314,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
                        ops->init               = r8152b_init;
                        ops->enable             = rtl8152_enable;
                        ops->disable            = rtl8152_disable;
+                       ops->up                 = r8152b_exit_oob;
                        ops->down               = rtl8152_down;
                        ops->unload             = rtl8152_unload;
                        ret = 0;
@@ -2698,6 +3323,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
                        ops->init               = r8153_init;
                        ops->enable             = rtl8153_enable;
                        ops->disable            = rtl8152_disable;
+                       ops->up                 = r8153_first_init;
                        ops->down               = rtl8153_down;
                        ops->unload             = rtl8153_unload;
                        ret = 0;
@@ -2713,6 +3339,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id)
                        ops->init               = r8153_init;
                        ops->enable             = rtl8153_enable;
                        ops->disable            = rtl8152_disable;
+                       ops->up                 = r8153_first_init;
                        ops->down               = rtl8153_down;
                        ops->unload             = rtl8153_unload;
                        ret = 0;
@@ -2740,6 +3367,12 @@ static int rtl8152_probe(struct usb_interface *intf,
        struct net_device *netdev;
        int ret;
 
+       if (udev->actconfig->desc.bConfigurationValue != 1) {
+               usb_driver_set_configuration(udev, 1);
+               return -ENODEV;
+       }
+
+       usb_reset_device(udev);
        netdev = alloc_etherdev(sizeof(struct r8152));
        if (!netdev) {
                dev_err(&intf->dev, "Out of memory\n");
@@ -2764,9 +3397,15 @@ static int rtl8152_probe(struct usb_interface *intf,
        netdev->netdev_ops = &rtl8152_netdev_ops;
        netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
 
-       netdev->features |= NETIF_F_IP_CSUM;
-       netdev->hw_features = NETIF_F_IP_CSUM;
+       netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+                           NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM |
+                           NETIF_F_TSO6;
+       netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
+                             NETIF_F_TSO | NETIF_F_FRAGLIST |
+                             NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+
        SET_ETHTOOL_OPS(netdev, &ops);
+       netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
 
        tp->mii.dev = netdev;
        tp->mii.mdio_read = read_mii_word;
@@ -2776,14 +3415,12 @@ static int rtl8152_probe(struct usb_interface *intf,
        tp->mii.phy_id = R8152_PHY_ID;
        tp->mii.supports_gmii = 0;
 
+       intf->needs_remote_wakeup = 1;
+
        r8152b_get_version(tp);
        tp->rtl_ops.init(tp);
        set_ethernet_addr(tp);
 
-       ret = alloc_all_mem(tp);
-       if (ret)
-               goto out;
-
        usb_set_intfdata(intf, tp);
 
        ret = register_netdev(netdev);
@@ -2792,6 +3429,12 @@ static int rtl8152_probe(struct usb_interface *intf,
                goto out1;
        }
 
+       tp->saved_wolopts = __rtl_get_wol(tp);
+       if (tp->saved_wolopts)
+               device_set_wakeup_enable(&udev->dev, true);
+       else
+               device_set_wakeup_enable(&udev->dev, false);
+
        netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
 
        return 0;
@@ -2813,16 +3456,15 @@ static void rtl8152_disconnect(struct usb_interface *intf)
                tasklet_kill(&tp->tl);
                unregister_netdev(tp->netdev);
                tp->rtl_ops.unload(tp);
-               free_all_mem(tp);
                free_netdev(tp->netdev);
        }
 }
 
 /* table of devices that work with this driver */
 static struct usb_device_id rtl8152_table[] = {
-       {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
-       {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
-       {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
+       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)},
+       {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)},
+       {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)},
        {}
 };
 
@@ -2836,6 +3478,8 @@ static struct usb_driver rtl8152_driver = {
        .suspend =      rtl8152_suspend,
        .resume =       rtl8152_resume,
        .reset_resume = rtl8152_resume,
+       .supports_autosuspend = 1,
+       .disable_hub_initiated_lpm = 1,
 };
 
 module_usb_driver(rtl8152_driver);
diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c
deleted file mode 100644 (file)
index f0a8791..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/mii.h>
-#include <linux/usb.h>
-#include <linux/usb/cdc.h>
-#include <linux/usb/usbnet.h>
-
-#define RTL815x_REQT_READ      0xc0
-#define RTL815x_REQT_WRITE     0x40
-#define RTL815x_REQ_GET_REGS   0x05
-#define RTL815x_REQ_SET_REGS   0x05
-
-#define MCU_TYPE_PLA           0x0100
-#define OCP_BASE               0xe86c
-#define BASE_MII               0xa400
-
-#define BYTE_EN_DWORD          0xff
-#define BYTE_EN_WORD           0x33
-#define BYTE_EN_BYTE           0x11
-
-#define R815x_PHY_ID           32
-#define REALTEK_VENDOR_ID      0x0bda
-
-
-static int pla_read_word(struct usb_device *udev, u16 index)
-{
-       int ret;
-       u8 shift = index & 2;
-       __le32 *tmp;
-
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       index &= ~3;
-
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret < 0)
-               goto out2;
-
-       ret = __le32_to_cpu(*tmp);
-       ret >>= (shift * 8);
-       ret &= 0xffff;
-
-out2:
-       kfree(tmp);
-       return ret;
-}
-
-static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
-{
-       __le32 *tmp;
-       u32 mask = 0xffff;
-       u16 byen = BYTE_EN_WORD;
-       u8 shift = index & 2;
-       int ret;
-
-       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               return -ENOMEM;
-
-       data &= mask;
-
-       if (shift) {
-               byen <<= shift;
-               mask <<= (shift * 8);
-               data <<= (shift * 8);
-               index &= ~3;
-       }
-
-       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                             RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
-       if (ret < 0)
-               goto out3;
-
-       data |= __le32_to_cpu(*tmp) & ~mask;
-       *tmp = __cpu_to_le32(data);
-
-       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                             RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-                             index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
-                             500);
-
-out3:
-       kfree(tmp);
-       return ret;
-}
-
-static int ocp_reg_read(struct usbnet *dev, u16 addr)
-{
-       u16 ocp_base, ocp_index;
-       int ret;
-
-       ocp_base = addr & 0xf000;
-       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
-       if (ret < 0)
-               goto out;
-
-       ocp_index = (addr & 0x0fff) | 0xb000;
-       ret = pla_read_word(dev->udev, ocp_index);
-
-out:
-       return ret;
-}
-
-static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
-{
-       u16 ocp_base, ocp_index;
-       int ret;
-
-       ocp_base = addr & 0xf000;
-       ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
-       if (ret < 0)
-               goto out1;
-
-       ocp_index = (addr & 0x0fff) | 0xb000;
-       ret = pla_write_word(dev->udev, ocp_index, data);
-
-out1:
-       return ret;
-}
-
-static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
-{
-       struct usbnet *dev = netdev_priv(netdev);
-       int ret;
-
-       if (phy_id != R815x_PHY_ID)
-               return -EINVAL;
-
-       if (usb_autopm_get_interface(dev->intf) < 0)
-               return -ENODEV;
-
-       ret = ocp_reg_read(dev, BASE_MII + reg * 2);
-
-       usb_autopm_put_interface(dev->intf);
-       return ret;
-}
-
-static
-void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
-{
-       struct usbnet *dev = netdev_priv(netdev);
-
-       if (phy_id != R815x_PHY_ID)
-               return;
-
-       if (usb_autopm_get_interface(dev->intf) < 0)
-               return;
-
-       ocp_reg_write(dev, BASE_MII + reg * 2, val);
-
-       usb_autopm_put_interface(dev->intf);
-}
-
-static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-       int status;
-
-       status = usbnet_cdc_bind(dev, intf);
-       if (status < 0)
-               return status;
-
-       dev->mii.dev = dev->net;
-       dev->mii.mdio_read = r815x_mdio_read;
-       dev->mii.mdio_write = r815x_mdio_write;
-       dev->mii.phy_id_mask = 0x3f;
-       dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = R815x_PHY_ID;
-       dev->mii.supports_gmii = 1;
-
-       return status;
-}
-
-static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
-{
-       int status;
-
-       status = usbnet_cdc_bind(dev, intf);
-       if (status < 0)
-               return status;
-
-       dev->mii.dev = dev->net;
-       dev->mii.mdio_read = r815x_mdio_read;
-       dev->mii.mdio_write = r815x_mdio_write;
-       dev->mii.phy_id_mask = 0x3f;
-       dev->mii.reg_num_mask = 0x1f;
-       dev->mii.phy_id = R815x_PHY_ID;
-       dev->mii.supports_gmii = 0;
-
-       return status;
-}
-
-static const struct driver_info r8152_info = {
-       .description =  "RTL8152 ECM Device",
-       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       .bind =         r8152_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
-       .manage_power = usbnet_manage_power,
-};
-
-static const struct driver_info r8153_info = {
-       .description =  "RTL8153 ECM Device",
-       .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       .bind =         r8153_bind,
-       .unbind =       usbnet_cdc_unbind,
-       .status =       usbnet_cdc_status,
-       .manage_power = usbnet_manage_power,
-};
-
-static const struct usb_device_id products[] = {
-{
-       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &r8152_info,
-},
-
-{
-       USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
-                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
-       .driver_info = (unsigned long) &r8153_info,
-},
-
-       { },            /* END */
-};
-MODULE_DEVICE_TABLE(usb, products);
-
-static struct usb_driver r815x_driver = {
-       .name =         "r815x",
-       .id_table =     products,
-       .probe =        usbnet_probe,
-       .disconnect =   usbnet_disconnect,
-       .suspend =      usbnet_suspend,
-       .resume =       usbnet_resume,
-       .reset_resume = usbnet_resume,
-       .supports_autosuspend = 1,
-       .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(r815x_driver);
-
-MODULE_AUTHOR("Hayes Wang");
-MODULE_DESCRIPTION("Realtek USB ECM device");
-MODULE_LICENSE("GPL");
index a48bc0f20c1a860a66299d00391381cf58972b95..524a47a2812075490ac601b93590dd06d4caeccb 100644 (file)
@@ -492,6 +492,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind);
  */
 int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        /* peripheral may have batched packets to us... */
        while (likely(skb->len)) {
                struct rndis_data_hdr   *hdr = (void *)skb->data;
index f17b9e02dd348166333d691a06b8b12b0a48a3e7..d9e7892262faa6a0543807d4d411163a5f59ac78 100644 (file)
@@ -2106,6 +2106,10 @@ static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
 
 static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        while (skb->len > 0) {
                u32 rx_cmd_a, rx_cmd_b, align_count, size;
                struct sk_buff *ax_skb;
index 8dd54a0f7b2973a29596fdb5ef99143269ce30cc..424db65e43962545b1746df63deb23833bf0c18b 100644 (file)
@@ -1723,6 +1723,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
 
 static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 {
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
        while (skb->len > 0) {
                u32 header, align_count;
                struct sk_buff *ax_skb;
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
new file mode 100644 (file)
index 0000000..b94a0fb
--- /dev/null
@@ -0,0 +1,874 @@
+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
+ *
+ * Author : Liu Junliang <liujunliang_ljl@163.com>
+ *
+ * Based on asix_common.c, asix_devices.c
+ *
+ * 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/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+#include <linux/slab.h>
+#include <linux/if_vlan.h>
+
+#include "sr9800.h"
+
+static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+                           u16 size, void *data)
+{
+       int err;
+
+       err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index,
+                             data, size);
+       if ((err != size) && (err >= 0))
+               err = -EINVAL;
+
+       return err;
+}
+
+static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+                            u16 size, void *data)
+{
+       int err;
+
+       err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index,
+                             data, size);
+       if ((err != size) && (err >= 0))
+               err = -EINVAL;
+
+       return err;
+}
+
+static void
+sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+                  u16 size, void *data)
+{
+       usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data,
+                              size);
+}
+
+static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+       int offset = 0;
+
+       /* This check is no longer done by usbnet */
+       if (skb->len < dev->net->hard_header_len)
+               return 0;
+
+       while (offset + sizeof(u32) < skb->len) {
+               struct sk_buff *sr_skb;
+               u16 size;
+               u32 header = get_unaligned_le32(skb->data + offset);
+
+               offset += sizeof(u32);
+               /* get the packet length */
+               size = (u16) (header & 0x7ff);
+               if (size != ((~header >> 16) & 0x07ff)) {
+                       netdev_err(dev->net, "%s : Bad Header Length\n",
+                                  __func__);
+                       return 0;
+               }
+
+               if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
+                   (size + offset > skb->len)) {
+                       netdev_err(dev->net, "%s : Bad RX Length %d\n",
+                                  __func__, size);
+                       return 0;
+               }
+               sr_skb = netdev_alloc_skb_ip_align(dev->net, size);
+               if (!sr_skb)
+                       return 0;
+
+               skb_put(sr_skb, size);
+               memcpy(sr_skb->data, skb->data + offset, size);
+               usbnet_skb_return(dev, sr_skb);
+
+               offset += (size + 1) & 0xfffe;
+       }
+
+       if (skb->len != offset) {
+               netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__,
+                          skb->len);
+               return 0;
+       }
+
+       return 1;
+}
+
+static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+                                       gfp_t flags)
+{
+       int headroom = skb_headroom(skb);
+       int tailroom = skb_tailroom(skb);
+       u32 padbytes = 0xffff0000;
+       u32 packet_len;
+       int padlen;
+
+       padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4;
+
+       if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) {
+               if ((headroom < 4) || (tailroom < padlen)) {
+                       skb->data = memmove(skb->head + 4, skb->data,
+                                           skb->len);
+                       skb_set_tail_pointer(skb, skb->len);
+               }
+       } else {
+               struct sk_buff *skb2;
+               skb2 = skb_copy_expand(skb, 4, padlen, flags);
+               dev_kfree_skb_any(skb);
+               skb = skb2;
+               if (!skb)
+                       return NULL;
+       }
+
+       skb_push(skb, 4);
+       packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+       cpu_to_le32s(&packet_len);
+       skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
+
+       if (padlen) {
+               cpu_to_le32s(&padbytes);
+               memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
+               skb_put(skb, sizeof(padbytes));
+       }
+
+       return skb;
+}
+
+static void sr_status(struct usbnet *dev, struct urb *urb)
+{
+       struct sr9800_int_data *event;
+       int link;
+
+       if (urb->actual_length < 8)
+               return;
+
+       event = urb->transfer_buffer;
+       link = event->link & 0x01;
+       if (netif_carrier_ok(dev->net) != link) {
+               usbnet_link_change(dev, link, 1);
+               netdev_dbg(dev->net, "Link Status is: %d\n", link);
+       }
+
+       return;
+}
+
+static inline int sr_set_sw_mii(struct usbnet *dev)
+{
+       int ret;
+
+       ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+       if (ret < 0)
+               netdev_err(dev->net, "Failed to enable software MII access\n");
+       return ret;
+}
+
+static inline int sr_set_hw_mii(struct usbnet *dev)
+{
+       int ret;
+
+       ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+       if (ret < 0)
+               netdev_err(dev->net, "Failed to enable hardware MII access\n");
+       return ret;
+}
+
+static inline int sr_get_phy_addr(struct usbnet *dev)
+{
+       u8 buf[2];
+       int ret;
+
+       ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf);
+       if (ret < 0) {
+               netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n",
+                          __func__, ret);
+               goto out;
+       }
+       netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__,
+                  *((__le16 *)buf));
+
+       ret = buf[1];
+
+out:
+       return ret;
+}
+
+static int sr_sw_reset(struct usbnet *dev, u8 flags)
+{
+       int ret;
+
+       ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL);
+       if (ret < 0)
+               netdev_err(dev->net, "Failed to send software reset:%02x\n",
+                          ret);
+
+       return ret;
+}
+
+static u16 sr_read_rx_ctl(struct usbnet *dev)
+{
+       __le16 v;
+       int ret;
+
+       ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v);
+       if (ret < 0) {
+               netdev_err(dev->net, "Error reading RX_CTL register:%02x\n",
+                          ret);
+               goto out;
+       }
+
+       ret = le16_to_cpu(v);
+out:
+       return ret;
+}
+
+static int sr_write_rx_ctl(struct usbnet *dev, u16 mode)
+{
+       int ret;
+
+       netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode);
+       ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+       if (ret < 0)
+               netdev_err(dev->net,
+                          "Failed to write RX_CTL mode to 0x%04x:%02x\n",
+                          mode, ret);
+
+       return ret;
+}
+
+static u16 sr_read_medium_status(struct usbnet *dev)
+{
+       __le16 v;
+       int ret;
+
+       ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
+       if (ret < 0) {
+               netdev_err(dev->net,
+                          "Error reading Medium Status register:%02x\n", ret);
+               return ret;     /* TODO: callers not checking for error ret */
+       }
+
+       return le16_to_cpu(v);
+}
+
+static int sr_write_medium_mode(struct usbnet *dev, u16 mode)
+{
+       int ret;
+
+       netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode);
+       ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+       if (ret < 0)
+               netdev_err(dev->net,
+                          "Failed to write Medium Mode mode to 0x%04x:%02x\n",
+                          mode, ret);
+       return ret;
+}
+
+static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep)
+{
+       int ret;
+
+       netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value);
+       ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+       if (ret < 0)
+               netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n",
+                          value, ret);
+       if (sleep)
+               msleep(sleep);
+
+       return ret;
+}
+
+/* SR9800 have a 16-bit RX_CTL value */
+static void sr_set_multicast(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct sr_data *data = (struct sr_data *)&dev->data;
+       u16 rx_ctl = SR_DEFAULT_RX_CTL;
+
+       if (net->flags & IFF_PROMISC) {
+               rx_ctl |= SR_RX_CTL_PRO;
+       } else if (net->flags & IFF_ALLMULTI ||
+                  netdev_mc_count(net) > SR_MAX_MCAST) {
+               rx_ctl |= SR_RX_CTL_AMALL;
+       } else if (netdev_mc_empty(net)) {
+               /* just broadcast and directed */
+       } else {
+               /* We use the 20 byte dev->data
+                * for our 8 byte filter buffer
+                * to avoid allocating memory that
+                * is tricky to free later
+                */
+               struct netdev_hw_addr *ha;
+               u32 crc_bits;
+
+               memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE);
+
+               /* Build the multicast hash filter. */
+               netdev_for_each_mc_addr(ha, net) {
+                       crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+                       data->multi_filter[crc_bits >> 3] |=
+                           1 << (crc_bits & 7);
+               }
+
+               sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0,
+                                  SR_MCAST_FILTER_SIZE, data->multi_filter);
+
+               rx_ctl |= SR_RX_CTL_AM;
+       }
+
+       sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int sr_mdio_read(struct net_device *net, int phy_id, int loc)
+{
+       struct usbnet *dev = netdev_priv(net);
+       __le16 res;
+
+       mutex_lock(&dev->phy_mutex);
+       sr_set_sw_mii(dev);
+       sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res);
+       sr_set_hw_mii(dev);
+       mutex_unlock(&dev->phy_mutex);
+
+       netdev_dbg(dev->net,
+                  "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__,
+                  phy_id, loc, le16_to_cpu(res));
+
+       return le16_to_cpu(res);
+}
+
+static void
+sr_mdio_write(struct net_device *net, int phy_id, int loc, int val)
+{
+       struct usbnet *dev = netdev_priv(net);
+       __le16 res = cpu_to_le16(val);
+
+       netdev_dbg(dev->net,
+                  "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__,
+                  phy_id, loc, val);
+       mutex_lock(&dev->phy_mutex);
+       sr_set_sw_mii(dev);
+       sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
+       sr_set_hw_mii(dev);
+       mutex_unlock(&dev->phy_mutex);
+}
+
+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
+static u32 sr_get_phyid(struct usbnet *dev)
+{
+       int phy_reg;
+       u32 phy_id;
+       int i;
+
+       /* Poll for the rare case the FW or phy isn't ready yet.  */
+       for (i = 0; i < 100; i++) {
+               phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
+               if (phy_reg != 0 && phy_reg != 0xFFFF)
+                       break;
+               mdelay(1);
+       }
+
+       if (phy_reg <= 0 || phy_reg == 0xFFFF)
+               return 0;
+
+       phy_id = (phy_reg & 0xffff) << 16;
+
+       phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
+       if (phy_reg < 0)
+               return 0;
+
+       phy_id |= (phy_reg & 0xffff);
+
+       return phy_id;
+}
+
+static void
+sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+       struct usbnet *dev = netdev_priv(net);
+       u8 opt;
+
+       if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
+               wolinfo->supported = 0;
+               wolinfo->wolopts = 0;
+               return;
+       }
+       wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+       wolinfo->wolopts = 0;
+       if (opt & SR_MONITOR_LINK)
+               wolinfo->wolopts |= WAKE_PHY;
+       if (opt & SR_MONITOR_MAGIC)
+               wolinfo->wolopts |= WAKE_MAGIC;
+}
+
+static int
+sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+       struct usbnet *dev = netdev_priv(net);
+       u8 opt = 0;
+
+       if (wolinfo->wolopts & WAKE_PHY)
+               opt |= SR_MONITOR_LINK;
+       if (wolinfo->wolopts & WAKE_MAGIC)
+               opt |= SR_MONITOR_MAGIC;
+
+       if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE,
+                        opt, 0, 0, NULL) < 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int sr_get_eeprom_len(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct sr_data *data = (struct sr_data *)&dev->data;
+
+       return data->eeprom_len;
+}
+
+static int sr_get_eeprom(struct net_device *net,
+                             struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct usbnet *dev = netdev_priv(net);
+       __le16 *ebuf = (__le16 *)data;
+       int ret;
+       int i;
+
+       /* Crude hack to ensure that we don't overwrite memory
+        * if an odd length is supplied
+        */
+       if (eeprom->len % 2)
+               return -EINVAL;
+
+       eeprom->magic = SR_EEPROM_MAGIC;
+
+       /* sr9800 returns 2 bytes from eeprom on read */
+       for (i = 0; i < eeprom->len / 2; i++) {
+               ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i,
+                                 0, 2, &ebuf[i]);
+               if (ret < 0)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static void sr_get_drvinfo(struct net_device *net,
+                                struct ethtool_drvinfo *info)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct sr_data *data = (struct sr_data *)&dev->data;
+
+       /* Inherit standard device info */
+       usbnet_get_drvinfo(net, info);
+       strncpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+       strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       info->eedump_len = data->eeprom_len;
+}
+
+static u32 sr_get_link(struct net_device *net)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       return mii_link_ok(&dev->mii);
+}
+
+static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static int sr_set_mac_address(struct net_device *net, void *p)
+{
+       struct usbnet *dev = netdev_priv(net);
+       struct sr_data *data = (struct sr_data *)&dev->data;
+       struct sockaddr *addr = p;
+
+       if (netif_running(net))
+               return -EBUSY;
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+
+       /* We use the 20 byte dev->data
+        * for our 6 byte mac buffer
+        * to avoid allocating memory that
+        * is tricky to free later
+        */
+       memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
+       sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+                          data->mac_addr);
+
+       return 0;
+}
+
+static const struct ethtool_ops sr9800_ethtool_ops = {
+       .get_drvinfo    = sr_get_drvinfo,
+       .get_link       = sr_get_link,
+       .get_msglevel   = usbnet_get_msglevel,
+       .set_msglevel   = usbnet_set_msglevel,
+       .get_wol        = sr_get_wol,
+       .set_wol        = sr_set_wol,
+       .get_eeprom_len = sr_get_eeprom_len,
+       .get_eeprom     = sr_get_eeprom,
+       .get_settings   = usbnet_get_settings,
+       .set_settings   = usbnet_set_settings,
+       .nway_reset     = usbnet_nway_reset,
+};
+
+static int sr9800_link_reset(struct usbnet *dev)
+{
+       struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+       u16 mode;
+
+       mii_check_media(&dev->mii, 1, 1);
+       mii_ethtool_gset(&dev->mii, &ecmd);
+       mode = SR9800_MEDIUM_DEFAULT;
+
+       if (ethtool_cmd_speed(&ecmd) != SPEED_100)
+               mode &= ~SR_MEDIUM_PS;
+
+       if (ecmd.duplex != DUPLEX_FULL)
+               mode &= ~SR_MEDIUM_FD;
+
+       netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n",
+                  __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
+
+       sr_write_medium_mode(dev, mode);
+
+       return 0;
+}
+
+
+static int sr9800_set_default_mode(struct usbnet *dev)
+{
+       u16 rx_ctl;
+       int ret;
+
+       sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+       sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+                     ADVERTISE_ALL | ADVERTISE_CSMA);
+       mii_nway_restart(&dev->mii);
+
+       ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT);
+       if (ret < 0)
+               goto out;
+
+       ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012,
+                               SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT,
+                               SR9800_IPG2_DEFAULT, 0, NULL);
+       if (ret < 0) {
+               netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret);
+               goto out;
+       }
+
+       /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+       ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL);
+       if (ret < 0)
+               goto out;
+
+       rx_ctl = sr_read_rx_ctl(dev);
+       netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n",
+                  rx_ctl);
+
+       rx_ctl = sr_read_medium_status(dev);
+       netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n",
+                  rx_ctl);
+
+       return 0;
+out:
+       return ret;
+}
+
+static int sr9800_reset(struct usbnet *dev)
+{
+       struct sr_data *data = (struct sr_data *)&dev->data;
+       int ret, embd_phy;
+       u16 rx_ctl;
+
+       ret = sr_write_gpio(dev,
+                       SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5);
+       if (ret < 0)
+               goto out;
+
+       embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
+
+       ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+       if (ret < 0) {
+               netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
+               goto out;
+       }
+
+       ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL);
+       if (ret < 0)
+               goto out;
+
+       msleep(150);
+
+       ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
+       if (ret < 0)
+               goto out;
+
+       msleep(150);
+
+       if (embd_phy) {
+               ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+               if (ret < 0)
+                       goto out;
+       } else {
+               ret = sr_sw_reset(dev, SR_SWRESET_PRTE);
+               if (ret < 0)
+                       goto out;
+       }
+
+       msleep(150);
+       rx_ctl = sr_read_rx_ctl(dev);
+       netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
+       ret = sr_write_rx_ctl(dev, 0x0000);
+       if (ret < 0)
+               goto out;
+
+       rx_ctl = sr_read_rx_ctl(dev);
+       netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+
+       ret = sr_sw_reset(dev, SR_SWRESET_PRL);
+       if (ret < 0)
+               goto out;
+
+       msleep(150);
+
+       ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL);
+       if (ret < 0)
+               goto out;
+
+       msleep(150);
+
+       ret = sr9800_set_default_mode(dev);
+       if (ret < 0)
+               goto out;
+
+       /* Rewrite MAC address */
+       memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+       ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+                                                       data->mac_addr);
+       if (ret < 0)
+               goto out;
+
+       return 0;
+
+out:
+       return ret;
+}
+
+static const struct net_device_ops sr9800_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_set_mac_address    = sr_set_mac_address,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = sr_ioctl,
+       .ndo_set_rx_mode        = sr_set_multicast,
+};
+
+static int sr9800_phy_powerup(struct usbnet *dev)
+{
+       int ret;
+
+       /* set the embedded Ethernet PHY in power-down state */
+       ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL);
+       if (ret < 0) {
+               netdev_err(dev->net, "Failed to power down PHY : %d\n", ret);
+               return ret;
+       }
+       msleep(20);
+
+       /* set the embedded Ethernet PHY in power-up state */
+       ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+       if (ret < 0) {
+               netdev_err(dev->net, "Failed to reset PHY: %d\n", ret);
+               return ret;
+       }
+       msleep(600);
+
+       /* set the embedded Ethernet PHY in reset state */
+       ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
+       if (ret < 0) {
+               netdev_err(dev->net, "Failed to power up PHY: %d\n", ret);
+               return ret;
+       }
+       msleep(20);
+
+       /* set the embedded Ethernet PHY in power-up state */
+       ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+       if (ret < 0) {
+               netdev_err(dev->net, "Failed to reset PHY: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct sr_data *data = (struct sr_data *)&dev->data;
+       u16 led01_mux, led23_mux;
+       int ret, embd_phy;
+       u32 phyid;
+       u16 rx_ctl;
+
+       data->eeprom_len = SR9800_EEPROM_LEN;
+
+       usbnet_get_endpoints(dev, intf);
+
+       /* LED Setting Rule :
+        * AABB:CCDD
+        * AA : MFA0(LED0)
+        * BB : MFA1(LED1)
+        * CC : MFA2(LED2), Reserved for SR9800
+        * DD : MFA3(LED3), Reserved for SR9800
+        */
+       led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK;
+       led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE;
+       ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL);
+       if (ret < 0) {
+                       netdev_err(dev->net, "set LINK LED failed : %d\n", ret);
+                       goto out;
+       }
+
+       /* Get the MAC address */
+       ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN,
+                         dev->net->dev_addr);
+       if (ret < 0) {
+               netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret);
+               return ret;
+       }
+       netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr);
+
+       /* Initialize MII structure */
+       dev->mii.dev = dev->net;
+       dev->mii.mdio_read = sr_mdio_read;
+       dev->mii.mdio_write = sr_mdio_write;
+       dev->mii.phy_id_mask = 0x1f;
+       dev->mii.reg_num_mask = 0x1f;
+       dev->mii.phy_id = sr_get_phy_addr(dev);
+
+       dev->net->netdev_ops = &sr9800_netdev_ops;
+       dev->net->ethtool_ops = &sr9800_ethtool_ops;
+
+       embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
+       /* Reset the PHY to normal operation mode */
+       ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+       if (ret < 0) {
+               netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret);
+               return ret;
+       }
+
+       /* Init PHY routine */
+       ret = sr9800_phy_powerup(dev);
+       if (ret < 0)
+               goto out;
+
+       rx_ctl = sr_read_rx_ctl(dev);
+       netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl);
+       ret = sr_write_rx_ctl(dev, 0x0000);
+       if (ret < 0)
+               goto out;
+
+       rx_ctl = sr_read_rx_ctl(dev);
+       netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl);
+
+       /* Read PHYID register *AFTER* the PHY was reset properly */
+       phyid = sr_get_phyid(dev);
+       netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid);
+
+       /* medium mode setting */
+       ret = sr9800_set_default_mode(dev);
+       if (ret < 0)
+               goto out;
+
+       if (dev->udev->speed == USB_SPEED_HIGH) {
+               ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
+                       SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt,
+                       SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold,
+                       0, NULL);
+               if (ret < 0) {
+                       netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret);
+                       goto out;
+               }
+               dev->rx_urb_size =
+                       SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size;
+       } else {
+               ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
+                       SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt,
+                       SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold,
+                       0, NULL);
+               if (ret < 0) {
+                       netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret);
+                       goto out;
+               }
+               dev->rx_urb_size =
+                       SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size;
+       }
+       netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__,
+                  dev->rx_urb_size);
+       return 0;
+
+out:
+       return ret;
+}
+
+static const struct driver_info sr9800_driver_info = {
+       .description    = "CoreChip SR9800 USB 2.0 Ethernet",
+       .bind           = sr9800_bind,
+       .status         = sr_status,
+       .link_reset     = sr9800_link_reset,
+       .reset          = sr9800_reset,
+       .flags          = DRIVER_FLAG,
+       .rx_fixup       = sr_rx_fixup,
+       .tx_fixup       = sr_tx_fixup,
+};
+
+static const struct usb_device_id      products[] = {
+       {
+               USB_DEVICE(0x0fe6, 0x9800),     /* SR9800 Device  */
+               .driver_info = (unsigned long) &sr9800_driver_info,
+       },
+       {},             /* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr_driver = {
+       .name           = DRIVER_NAME,
+       .id_table       = products,
+       .probe          = usbnet_probe,
+       .suspend        = usbnet_suspend,
+       .resume         = usbnet_resume,
+       .disconnect     = usbnet_disconnect,
+       .supports_autosuspend = 1,
+};
+
+module_usb_driver(sr_driver);
+
+MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9800.h b/drivers/net/usb/sr9800.h
new file mode 100644 (file)
index 0000000..18f6702
--- /dev/null
@@ -0,0 +1,202 @@
+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
+ *
+ * Author : Liu Junliang <liujunliang_ljl@163.com>
+ *
+ * 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.
+ */
+
+#ifndef        _SR9800_H
+#define        _SR9800_H
+
+/* SR9800 spec. command table on Linux Platform */
+
+/* command : Software Station Management Control Reg */
+#define SR_CMD_SET_SW_MII              0x06
+/* command : PHY Read Reg */
+#define SR_CMD_READ_MII_REG            0x07
+/* command : PHY Write Reg */
+#define SR_CMD_WRITE_MII_REG           0x08
+/* command : Hardware Station Management Control Reg */
+#define SR_CMD_SET_HW_MII              0x0a
+/* command : SROM Read Reg */
+#define SR_CMD_READ_EEPROM             0x0b
+/* command : SROM Write Reg */
+#define SR_CMD_WRITE_EEPROM            0x0c
+/* command : SROM Write Enable Reg */
+#define SR_CMD_WRITE_ENABLE            0x0d
+/* command : SROM Write Disable Reg */
+#define SR_CMD_WRITE_DISABLE           0x0e
+/* command : RX Control Read Reg */
+#define SR_CMD_READ_RX_CTL             0x0f
+#define                SR_RX_CTL_PRO                   (1 << 0)
+#define                SR_RX_CTL_AMALL                 (1 << 1)
+#define                SR_RX_CTL_SEP                   (1 << 2)
+#define                SR_RX_CTL_AB                    (1 << 3)
+#define                SR_RX_CTL_AM                    (1 << 4)
+#define                SR_RX_CTL_AP                    (1 << 5)
+#define                SR_RX_CTL_ARP                   (1 << 6)
+#define                SR_RX_CTL_SO                    (1 << 7)
+#define                SR_RX_CTL_RH1M                  (1 << 8)
+#define                SR_RX_CTL_RH2M                  (1 << 9)
+#define                SR_RX_CTL_RH3M                  (1 << 10)
+/* command : RX Control Write Reg */
+#define SR_CMD_WRITE_RX_CTL            0x10
+/* command : IPG0/IPG1/IPG2 Control Read Reg */
+#define SR_CMD_READ_IPG012             0x11
+/* command : IPG0/IPG1/IPG2 Control Write Reg */
+#define SR_CMD_WRITE_IPG012            0x12
+/* command : Node ID Read Reg */
+#define SR_CMD_READ_NODE_ID            0x13
+/* command : Node ID Write Reg */
+#define SR_CMD_WRITE_NODE_ID           0x14
+/* command : Multicast Filter Array Read Reg */
+#define        SR_CMD_READ_MULTI_FILTER        0x15
+/* command : Multicast Filter Array Write Reg */
+#define SR_CMD_WRITE_MULTI_FILTER      0x16
+/* command : Eth/HomePNA PHY Address Reg */
+#define SR_CMD_READ_PHY_ID             0x19
+/* command : Medium Status Read Reg */
+#define SR_CMD_READ_MEDIUM_STATUS      0x1a
+#define                SR_MONITOR_LINK                 (1 << 1)
+#define                SR_MONITOR_MAGIC                (1 << 2)
+#define                SR_MONITOR_HSFS                 (1 << 4)
+/* command : Medium Status Write Reg */
+#define SR_CMD_WRITE_MEDIUM_MODE       0x1b
+#define                SR_MEDIUM_GM                    (1 << 0)
+#define                SR_MEDIUM_FD                    (1 << 1)
+#define                SR_MEDIUM_AC                    (1 << 2)
+#define                SR_MEDIUM_ENCK                  (1 << 3)
+#define                SR_MEDIUM_RFC                   (1 << 4)
+#define                SR_MEDIUM_TFC                   (1 << 5)
+#define                SR_MEDIUM_JFE                   (1 << 6)
+#define                SR_MEDIUM_PF                    (1 << 7)
+#define                SR_MEDIUM_RE                    (1 << 8)
+#define                SR_MEDIUM_PS                    (1 << 9)
+#define                SR_MEDIUM_RSV                   (1 << 10)
+#define                SR_MEDIUM_SBP                   (1 << 11)
+#define                SR_MEDIUM_SM                    (1 << 12)
+/* command : Monitor Mode Status Read Reg */
+#define SR_CMD_READ_MONITOR_MODE       0x1c
+/* command : Monitor Mode Status Write Reg */
+#define SR_CMD_WRITE_MONITOR_MODE      0x1d
+/* command : GPIO Status Read Reg */
+#define SR_CMD_READ_GPIOS              0x1e
+#define                SR_GPIO_GPO0EN          (1 << 0) /* GPIO0 Output enable */
+#define                SR_GPIO_GPO_0           (1 << 1) /* GPIO0 Output value */
+#define                SR_GPIO_GPO1EN          (1 << 2) /* GPIO1 Output enable */
+#define                SR_GPIO_GPO_1           (1 << 3) /* GPIO1 Output value */
+#define                SR_GPIO_GPO2EN          (1 << 4) /* GPIO2 Output enable */
+#define                SR_GPIO_GPO_2           (1 << 5) /* GPIO2 Output value */
+#define                SR_GPIO_RESERVED        (1 << 6) /* Reserved */
+#define                SR_GPIO_RSE             (1 << 7) /* Reload serial EEPROM */
+/* command : GPIO Status Write Reg */
+#define SR_CMD_WRITE_GPIOS             0x1f
+/* command : Eth PHY Power and Reset Control Reg */
+#define SR_CMD_SW_RESET                        0x20
+#define                SR_SWRESET_CLEAR                0x00
+#define                SR_SWRESET_RR                   (1 << 0)
+#define                SR_SWRESET_RT                   (1 << 1)
+#define                SR_SWRESET_PRTE                 (1 << 2)
+#define                SR_SWRESET_PRL                  (1 << 3)
+#define                SR_SWRESET_BZ                   (1 << 4)
+#define                SR_SWRESET_IPRL                 (1 << 5)
+#define                SR_SWRESET_IPPD                 (1 << 6)
+/* command : Software Interface Selection Status Read Reg */
+#define SR_CMD_SW_PHY_STATUS           0x21
+/* command : Software Interface Selection Status Write Reg */
+#define SR_CMD_SW_PHY_SELECT           0x22
+/* command : BULK in Buffer Size Reg */
+#define        SR_CMD_BULKIN_SIZE              0x2A
+/* command : LED_MUX Control Reg */
+#define        SR_CMD_LED_MUX                  0x70
+#define                SR_LED_MUX_TX_ACTIVE            (1 << 0)
+#define                SR_LED_MUX_RX_ACTIVE            (1 << 1)
+#define                SR_LED_MUX_COLLISION            (1 << 2)
+#define                SR_LED_MUX_DUP_COL              (1 << 3)
+#define                SR_LED_MUX_DUP                  (1 << 4)
+#define                SR_LED_MUX_SPEED                (1 << 5)
+#define                SR_LED_MUX_LINK_ACTIVE          (1 << 6)
+#define                SR_LED_MUX_LINK                 (1 << 7)
+
+/* Register Access Flags */
+#define SR_REQ_RD_REG   (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define SR_REQ_WR_REG   (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* Multicast Filter Array size & Max Number */
+#define        SR_MCAST_FILTER_SIZE            8
+#define        SR_MAX_MCAST                    64
+
+/* IPG0/1/2 Default Value */
+#define        SR9800_IPG0_DEFAULT             0x15
+#define        SR9800_IPG1_DEFAULT             0x0c
+#define        SR9800_IPG2_DEFAULT             0x12
+
+/* Medium Status Default Mode */
+#define SR9800_MEDIUM_DEFAULT  \
+       (SR_MEDIUM_FD | SR_MEDIUM_RFC | \
+        SR_MEDIUM_TFC | SR_MEDIUM_PS | \
+        SR_MEDIUM_AC | SR_MEDIUM_RE)
+
+/* RX Control Default Setting */
+#define SR_DEFAULT_RX_CTL      \
+       (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M)
+
+/* EEPROM Magic Number & EEPROM Size */
+#define SR_EEPROM_MAGIC                        0xdeadbeef
+#define SR9800_EEPROM_LEN              0xff
+
+/* SR9800 Driver Version and Driver Name */
+#define DRIVER_VERSION                 "11-Nov-2013"
+#define DRIVER_NAME                    "CoreChips"
+#define        DRIVER_FLAG             \
+       (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR |  FLAG_MULTI_PACKET)
+
+/* SR9800 BULKIN Buffer Size */
+#define SR9800_MAX_BULKIN_2K           0
+#define SR9800_MAX_BULKIN_4K           1
+#define SR9800_MAX_BULKIN_6K           2
+#define SR9800_MAX_BULKIN_8K           3
+#define SR9800_MAX_BULKIN_16K          4
+#define SR9800_MAX_BULKIN_20K          5
+#define SR9800_MAX_BULKIN_24K          6
+#define SR9800_MAX_BULKIN_32K          7
+
+struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = {
+       /* 2k */
+       {2048, 0x8000, 0x8001},
+       /* 4k */
+       {4096, 0x8100, 0x8147},
+       /* 6k */
+       {6144, 0x8200, 0x81EB},
+       /* 8k */
+       {8192, 0x8300, 0x83D7},
+       /* 16 */
+       {16384, 0x8400, 0x851E},
+       /* 20k */
+       {20480, 0x8500, 0x8666},
+       /* 24k */
+       {24576, 0x8600, 0x87AE},
+       /* 32k */
+       {32768, 0x8700, 0x8A3D},
+};
+
+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+struct sr_data {
+       u8 multi_filter[SR_MCAST_FILTER_SIZE];
+       u8 mac_addr[ETH_ALEN];
+       u8 phymode;
+       u8 ledmode;
+       u8 eeprom_len;
+};
+
+struct sr9800_int_data {
+       __le16 res1;
+       u8 link;
+       __le16 res2;
+       u8 status;
+       __le16 res3;
+} __packed;
+
+#endif /* _SR9800_H */
index 4671da755e7b87f60758259021bcc5ab7f7c6cd1..f9e96c4275589ebc63b3d87432fe50471c287872 100644 (file)
@@ -542,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
        }
        // else network stack removes extra byte if we forced a short packet
 
-       if (skb->len) {
-               /* all data was already cloned from skb inside the driver */
-               if (dev->driver_info->flags & FLAG_MULTI_PACKET)
-                       dev_kfree_skb_any(skb);
-               else
-                       usbnet_skb_return(dev, skb);
+       /* all data was already cloned from skb inside the driver */
+       if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+               goto done;
+
+       if (skb->len < ETH_HLEN) {
+               dev->net->stats.rx_errors++;
+               dev->net->stats.rx_length_errors++;
+               netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len);
+       } else {
+               usbnet_skb_return(dev, skb);
                return;
        }
 
-       netif_dbg(dev, rx_err, dev->net, "drop\n");
-       dev->net->stats.rx_errors++;
 done:
        skb_queue_tail(&dev->done, skb);
 }
@@ -574,13 +576,6 @@ static void rx_complete (struct urb *urb)
        switch (urb_status) {
        /* success */
        case 0:
-               if (skb->len < dev->net->hard_header_len) {
-                       state = rx_cleanup;
-                       dev->net->stats.rx_errors++;
-                       dev->net->stats.rx_length_errors++;
-                       netif_dbg(dev, rx_err, dev->net,
-                                 "rx length %d\n", skb->len);
-               }
                break;
 
        /* stalls need manual reset. this is rare ... except that
@@ -757,14 +752,12 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
 // precondition: never called in_interrupt
 static void usbnet_terminate_urbs(struct usbnet *dev)
 {
-       DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup);
        DECLARE_WAITQUEUE(wait, current);
        int temp;
 
        /* ensure there are no more active urbs */
-       add_wait_queue(&unlink_wakeup, &wait);
+       add_wait_queue(&dev->wait, &wait);
        set_current_state(TASK_UNINTERRUPTIBLE);
-       dev->wait = &unlink_wakeup;
        temp = unlink_urbs(dev, &dev->txq) +
                unlink_urbs(dev, &dev->rxq);
 
@@ -778,15 +771,14 @@ static void usbnet_terminate_urbs(struct usbnet *dev)
                                  "waited for %d urb completions\n", temp);
        }
        set_current_state(TASK_RUNNING);
-       dev->wait = NULL;
-       remove_wait_queue(&unlink_wakeup, &wait);
+       remove_wait_queue(&dev->wait, &wait);
 }
 
 int usbnet_stop (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
        struct driver_info      *info = dev->driver_info;
-       int                     retval;
+       int                     retval, pm;
 
        clear_bit(EVENT_DEV_OPEN, &dev->flags);
        netif_stop_queue (net);
@@ -796,6 +788,8 @@ int usbnet_stop (struct net_device *net)
                   net->stats.rx_packets, net->stats.tx_packets,
                   net->stats.rx_errors, net->stats.tx_errors);
 
+       /* to not race resume */
+       pm = usb_autopm_get_interface(dev->intf);
        /* allow minidriver to stop correctly (wireless devices to turn off
         * radio etc) */
        if (info->stop) {
@@ -822,6 +816,9 @@ int usbnet_stop (struct net_device *net)
        dev->flags = 0;
        del_timer_sync (&dev->delay);
        tasklet_kill (&dev->bh);
+       if (!pm)
+               usb_autopm_put_interface(dev->intf);
+
        if (info->manage_power &&
            !test_and_clear_bit(EVENT_NO_RUNTIME_PM, &dev->flags))
                info->manage_power(dev, 0);
@@ -1442,11 +1439,12 @@ static void usbnet_bh (unsigned long param)
        /* restart RX again after disabling due to high error rate */
        clear_bit(EVENT_RX_KILL, &dev->flags);
 
-       // waiting for all pending urbs to complete?
-       if (dev->wait) {
-               if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
-                       wake_up (dev->wait);
-               }
+       /* waiting for all pending urbs to complete?
+        * only then can we forgo submitting anew
+        */
+       if (waitqueue_active(&dev->wait)) {
+               if (dev->txq.qlen + dev->rxq.qlen + dev->done.qlen == 0)
+                       wake_up_all(&dev->wait);
 
        // or are we maybe short a few urbs?
        } else if (netif_running (dev->net) &&
@@ -1585,6 +1583,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        dev->driver_name = name;
        dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
                                | NETIF_MSG_PROBE | NETIF_MSG_LINK);
+       init_waitqueue_head(&dev->wait);
        skb_queue_head_init (&dev->rxq);
        skb_queue_head_init (&dev->txq);
        skb_queue_head_init (&dev->done);
@@ -1796,9 +1795,10 @@ int usbnet_resume (struct usb_interface *intf)
                spin_unlock_irq(&dev->txq.lock);
 
                if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
-                       /* handle remote wakeup ASAP */
-                       if (!dev->wait &&
-                               netif_device_present(dev->net) &&
+                       /* handle remote wakeup ASAP
+                        * we cannot race against stop
+                        */
+                       if (netif_device_present(dev->net) &&
                                !timer_pending(&dev->delay) &&
                                !test_bit(EVENT_RX_HALT, &dev->flags))
                                        rx_alloc_submit(dev, GFP_NOIO);
index 2ec2041b62d4eb215bf23f74ad82ba44332b8d3d..b4a10bcb66a0f62be1606fa34629d120913fc74d 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/etherdevice.h>
 #include <linux/u64_stats_sync.h>
 
+#include <net/rtnetlink.h>
 #include <net/dst.h>
 #include <net/xfrm.h>
 #include <linux/veth.h>
@@ -155,10 +156,10 @@ static u64 veth_stats_one(struct pcpu_vstats *result, struct net_device *dev)
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
                        packets = stats->packets;
                        bytes = stats->bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
                result->packets += packets;
                result->bytes += bytes;
        }
@@ -235,18 +236,9 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
 
 static int veth_dev_init(struct net_device *dev)
 {
-       int i;
-
-       dev->vstats = alloc_percpu(struct pcpu_vstats);
+       dev->vstats = netdev_alloc_pcpu_stats(struct pcpu_vstats);
        if (!dev->vstats)
                return -ENOMEM;
-
-       for_each_possible_cpu(i) {
-               struct pcpu_vstats *veth_stats;
-               veth_stats = per_cpu_ptr(dev->vstats, i);
-               u64_stats_init(&veth_stats->syncp);
-       }
-
        return 0;
 }
 
@@ -285,7 +277,11 @@ static void veth_setup(struct net_device *dev)
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->features |= VETH_FEATURES;
-       dev->vlan_features = dev->features;
+       dev->vlan_features = dev->features &
+                            ~(NETIF_F_HW_VLAN_CTAG_TX |
+                              NETIF_F_HW_VLAN_STAG_TX |
+                              NETIF_F_HW_VLAN_CTAG_RX |
+                              NETIF_F_HW_VLAN_STAG_RX);
        dev->destructor = veth_dev_free;
 
        dev->hw_features = VETH_FEATURES;
@@ -332,10 +328,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
 
                nla_peer = data[VETH_INFO_PEER];
                ifmp = nla_data(nla_peer);
-               err = nla_parse(peer_tb, IFLA_MAX,
-                               nla_data(nla_peer) + sizeof(struct ifinfomsg),
-                               nla_len(nla_peer) - sizeof(struct ifinfomsg),
-                               ifla_policy);
+               err = rtnl_nla_parse_ifla(peer_tb,
+                                         nla_data(nla_peer) + sizeof(struct ifinfomsg),
+                                         nla_len(nla_peer) - sizeof(struct ifinfomsg));
                if (err < 0)
                        return err;
 
index d75f8edf4fb370300d13bd22adcfe66e754fb5a2..6f15d9b315a11ceb8d46b40062a62d73379a8390 100644 (file)
@@ -671,8 +671,7 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
                if (err)
                        break;
        } while (rq->vq->num_free);
-       if (unlikely(!virtqueue_kick(rq->vq)))
-               return false;
+       virtqueue_kick(rq->vq);
        return !oom;
 }
 
@@ -877,15 +876,16 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
        err = xmit_skb(sq, skb);
 
        /* This should not happen! */
-       if (unlikely(err) || unlikely(!virtqueue_kick(sq->vq))) {
+       if (unlikely(err)) {
                dev->stats.tx_fifo_errors++;
                if (net_ratelimit())
                        dev_warn(&dev->dev,
                                 "Unexpected TXQ (%d) queue failure: %d\n", qnum, err);
                dev->stats.tx_dropped++;
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
+       virtqueue_kick(sq->vq);
 
        /* Don't wait up for transmitted skbs to be freed. */
        skb_orphan(skb);
@@ -1000,16 +1000,16 @@ static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,
                u64 tpackets, tbytes, rpackets, rbytes;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->tx_syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->tx_syncp);
                        tpackets = stats->tx_packets;
                        tbytes   = stats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->tx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->tx_syncp, start));
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->rx_syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->rx_syncp);
                        rpackets = stats->rx_packets;
                        rbytes   = stats->rx_bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->rx_syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->rx_syncp, start));
 
                tot->rx_packets += rpackets;
                tot->tx_packets += tpackets;
@@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev)
        /* If we can receive ANY GSO packets, we must allocate large ones. */
        if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
            virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
-           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+           virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
                vi->big_packets = true;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
index 3be786faaaec222f0226b8285dde01e88b147e59..97394345e5dd223fd77ede415ced81e6fb26f545 100644 (file)
@@ -1078,7 +1078,7 @@ unlock_drop_pkt:
        spin_unlock_irqrestore(&tq->tx_lock, flags);
 drop_pkt:
        tq->stats.drop_total++;
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
@@ -1762,11 +1762,20 @@ vmxnet3_netpoll(struct net_device *netdev)
 {
        struct vmxnet3_adapter *adapter = netdev_priv(netdev);
 
-       if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
-               vmxnet3_disable_all_intrs(adapter);
-
-       vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
-       vmxnet3_enable_all_intrs(adapter);
+       switch (adapter->intr.type) {
+#ifdef CONFIG_PCI_MSI
+       case VMXNET3_IT_MSIX: {
+               int i;
+               for (i = 0; i < adapter->num_rx_queues; i++)
+                       vmxnet3_msix_rx(0, &adapter->rx_queue[i]);
+               break;
+       }
+#endif
+       case VMXNET3_IT_MSI:
+       default:
+               vmxnet3_intr(0, adapter->netdev);
+               break;
+       }
 
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -2729,47 +2738,35 @@ vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
 /*
  * Enable MSIx vectors.
  * Returns :
- *     0 on successful enabling of required vectors,
  *     VMXNET3_LINUX_MIN_MSIX_VECT when only minimum number of vectors required
- *      could be enabled.
- *     number of vectors which can be enabled otherwise (this number is smaller
+ *      were enabled.
+ *     number of vectors which were enabled otherwise (this number is greater
  *      than VMXNET3_LINUX_MIN_MSIX_VECT)
  */
 
 static int
-vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
-                            int vectors)
-{
-       int err = 0, vector_threshold;
-       vector_threshold = VMXNET3_LINUX_MIN_MSIX_VECT;
-
-       while (vectors >= vector_threshold) {
-               err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
-                                     vectors);
-               if (!err) {
-                       adapter->intr.num_intrs = vectors;
-                       return 0;
-               } else if (err < 0) {
-                       dev_err(&adapter->netdev->dev,
-                                  "Failed to enable MSI-X, error: %d\n", err);
-                       vectors = 0;
-               } else if (err < vector_threshold) {
-                       break;
-               } else {
-                       /* If fails to enable required number of MSI-x vectors
-                        * try enabling minimum number of vectors required.
-                        */
-                       dev_err(&adapter->netdev->dev,
-                               "Failed to enable %d MSI-X, trying %d instead\n",
-                                   vectors, vector_threshold);
-                       vectors = vector_threshold;
-               }
+vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter, int nvec)
+{
+       int ret = pci_enable_msix_range(adapter->pdev,
+                                       adapter->intr.msix_entries, nvec, nvec);
+
+       if (ret == -ENOSPC && nvec > VMXNET3_LINUX_MIN_MSIX_VECT) {
+               dev_err(&adapter->netdev->dev,
+                       "Failed to enable %d MSI-X, trying %d\n",
+                       nvec, VMXNET3_LINUX_MIN_MSIX_VECT);
+
+               ret = pci_enable_msix_range(adapter->pdev,
+                                           adapter->intr.msix_entries,
+                                           VMXNET3_LINUX_MIN_MSIX_VECT,
+                                           VMXNET3_LINUX_MIN_MSIX_VECT);
        }
 
-       dev_info(&adapter->pdev->dev,
-                "Number of MSI-X interrupts which can be allocated "
-                "is lower than min threshold required.\n");
-       return err;
+       if (ret < 0) {
+               dev_err(&adapter->netdev->dev,
+                       "Failed to enable MSI-X, error: %d\n", ret);
+       }
+
+       return ret;
 }
 
 
@@ -2796,56 +2793,50 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
 
 #ifdef CONFIG_PCI_MSI
        if (adapter->intr.type == VMXNET3_IT_MSIX) {
-               int vector, err = 0;
-
-               adapter->intr.num_intrs = (adapter->share_intr ==
-                                          VMXNET3_INTR_TXSHARE) ? 1 :
-                                          adapter->num_tx_queues;
-               adapter->intr.num_intrs += (adapter->share_intr ==
-                                          VMXNET3_INTR_BUDDYSHARE) ? 0 :
-                                          adapter->num_rx_queues;
-               adapter->intr.num_intrs += 1;           /* for link event */
-
-               adapter->intr.num_intrs = (adapter->intr.num_intrs >
-                                          VMXNET3_LINUX_MIN_MSIX_VECT
-                                          ? adapter->intr.num_intrs :
-                                          VMXNET3_LINUX_MIN_MSIX_VECT);
-
-               for (vector = 0; vector < adapter->intr.num_intrs; vector++)
-                       adapter->intr.msix_entries[vector].entry = vector;
-
-               err = vmxnet3_acquire_msix_vectors(adapter,
-                                                  adapter->intr.num_intrs);
+               int i, nvec;
+
+               nvec  = adapter->share_intr == VMXNET3_INTR_TXSHARE ?
+                       1 : adapter->num_tx_queues;
+               nvec += adapter->share_intr == VMXNET3_INTR_BUDDYSHARE ?
+                       0 : adapter->num_rx_queues;
+               nvec += 1;      /* for link event */
+               nvec = nvec > VMXNET3_LINUX_MIN_MSIX_VECT ?
+                      nvec : VMXNET3_LINUX_MIN_MSIX_VECT;
+
+               for (i = 0; i < nvec; i++)
+                       adapter->intr.msix_entries[i].entry = i;
+
+               nvec = vmxnet3_acquire_msix_vectors(adapter, nvec);
+               if (nvec < 0)
+                       goto msix_err;
+
                /* If we cannot allocate one MSIx vector per queue
                 * then limit the number of rx queues to 1
                 */
-               if (err == VMXNET3_LINUX_MIN_MSIX_VECT) {
+               if (nvec == VMXNET3_LINUX_MIN_MSIX_VECT) {
                        if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
                            || adapter->num_rx_queues != 1) {
                                adapter->share_intr = VMXNET3_INTR_TXSHARE;
                                netdev_err(adapter->netdev,
                                           "Number of rx queues : 1\n");
                                adapter->num_rx_queues = 1;
-                               adapter->intr.num_intrs =
-                                               VMXNET3_LINUX_MIN_MSIX_VECT;
                        }
-                       return;
                }
-               if (!err)
-                       return;
 
+               adapter->intr.num_intrs = nvec;
+               return;
+
+msix_err:
                /* If we cannot allocate MSIx vectors use only one rx queue */
                dev_info(&adapter->pdev->dev,
                         "Failed to enable MSI-X, error %d. "
-                        "Limiting #rx queues to 1, try MSI.\n", err);
+                        "Limiting #rx queues to 1, try MSI.\n", nvec);
 
                adapter->intr.type = VMXNET3_IT_MSI;
        }
 
        if (adapter->intr.type == VMXNET3_IT_MSI) {
-               int err;
-               err = pci_enable_msi(adapter->pdev);
-               if (!err) {
+               if (!pci_enable_msi(adapter->pdev)) {
                        adapter->num_rx_queues = 1;
                        adapter->intr.num_intrs = 1;
                        return;
index 026a313c2d2da4c3eb57d0c5f6a051bbbdc852b2..0d862a5077ab53d01d7c4b6ffb6e4d5f9ed85725 100644 (file)
@@ -469,7 +469,6 @@ static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan,
 /* Look up Ethernet address in forwarding table */
 static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan,
                                        const u8 *mac)
-
 {
        struct hlist_head *head = vxlan_fdb_head(vxlan, mac);
        struct vxlan_fdb *f;
@@ -596,10 +595,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
                        NAPI_GRO_CB(p)->same_flow = 0;
                        continue;
                }
-               goto found;
        }
 
-found:
        type = eh->h_proto;
 
        rcu_read_lock();
@@ -1135,7 +1132,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct vxlan_sock *vs;
        struct vxlanhdr *vxh;
-       __be16 port;
 
        /* Need Vxlan and inner Ethernet header to be present */
        if (!pskb_may_pull(skb, VXLAN_HLEN))
@@ -1153,8 +1149,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
                goto drop;
 
-       port = inet_sk(sk)->inet_sport;
-
        vs = rcu_dereference_sk_user_data(sk);
        if (!vs)
                goto drop;
@@ -1321,6 +1315,9 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
 
                neigh_release(n);
 
+               if (reply == NULL)
+                       goto out;
+
                skb_reset_mac_header(reply);
                __skb_pull(reply, skb_network_offset(reply));
                reply->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1342,15 +1339,103 @@ out:
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
+
+static struct sk_buff *vxlan_na_create(struct sk_buff *request,
+       struct neighbour *n, bool isrouter)
+{
+       struct net_device *dev = request->dev;
+       struct sk_buff *reply;
+       struct nd_msg *ns, *na;
+       struct ipv6hdr *pip6;
+       u8 *daddr;
+       int na_olen = 8; /* opt hdr + ETH_ALEN for target */
+       int ns_olen;
+       int i, len;
+
+       if (dev == NULL)
+               return NULL;
+
+       len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) +
+               sizeof(*na) + na_olen + dev->needed_tailroom;
+       reply = alloc_skb(len, GFP_ATOMIC);
+       if (reply == NULL)
+               return NULL;
+
+       reply->protocol = htons(ETH_P_IPV6);
+       reply->dev = dev;
+       skb_reserve(reply, LL_RESERVED_SPACE(request->dev));
+       skb_push(reply, sizeof(struct ethhdr));
+       skb_set_mac_header(reply, 0);
+
+       ns = (struct nd_msg *)skb_transport_header(request);
+
+       daddr = eth_hdr(request)->h_source;
+       ns_olen = request->len - skb_transport_offset(request) - sizeof(*ns);
+       for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) {
+               if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) {
+                       daddr = ns->opt + i + sizeof(struct nd_opt_hdr);
+                       break;
+               }
+       }
+
+       /* Ethernet header */
+       ether_addr_copy(eth_hdr(reply)->h_dest, daddr);
+       ether_addr_copy(eth_hdr(reply)->h_source, n->ha);
+       eth_hdr(reply)->h_proto = htons(ETH_P_IPV6);
+       reply->protocol = htons(ETH_P_IPV6);
+
+       skb_pull(reply, sizeof(struct ethhdr));
+       skb_set_network_header(reply, 0);
+       skb_put(reply, sizeof(struct ipv6hdr));
+
+       /* IPv6 header */
+
+       pip6 = ipv6_hdr(reply);
+       memset(pip6, 0, sizeof(struct ipv6hdr));
+       pip6->version = 6;
+       pip6->priority = ipv6_hdr(request)->priority;
+       pip6->nexthdr = IPPROTO_ICMPV6;
+       pip6->hop_limit = 255;
+       pip6->daddr = ipv6_hdr(request)->saddr;
+       pip6->saddr = *(struct in6_addr *)n->primary_key;
+
+       skb_pull(reply, sizeof(struct ipv6hdr));
+       skb_set_transport_header(reply, 0);
+
+       na = (struct nd_msg *)skb_put(reply, sizeof(*na) + na_olen);
+
+       /* Neighbor Advertisement */
+       memset(na, 0, sizeof(*na)+na_olen);
+       na->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+       na->icmph.icmp6_router = isrouter;
+       na->icmph.icmp6_override = 1;
+       na->icmph.icmp6_solicited = 1;
+       na->target = ns->target;
+       ether_addr_copy(&na->opt[2], n->ha);
+       na->opt[0] = ND_OPT_TARGET_LL_ADDR;
+       na->opt[1] = na_olen >> 3;
+
+       na->icmph.icmp6_cksum = csum_ipv6_magic(&pip6->saddr,
+               &pip6->daddr, sizeof(*na)+na_olen, IPPROTO_ICMPV6,
+               csum_partial(na, sizeof(*na)+na_olen, 0));
+
+       pip6->payload_len = htons(sizeof(*na)+na_olen);
+
+       skb_push(reply, sizeof(struct ipv6hdr));
+
+       reply->ip_summed = CHECKSUM_UNNECESSARY;
+
+       return reply;
+}
+
 static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
 {
        struct vxlan_dev *vxlan = netdev_priv(dev);
-       struct neighbour *n;
-       union vxlan_addr ipa;
+       struct nd_msg *msg;
        const struct ipv6hdr *iphdr;
        const struct in6_addr *saddr, *daddr;
-       struct nd_msg *msg;
-       struct inet6_dev *in6_dev = NULL;
+       struct neighbour *n;
+       struct inet6_dev *in6_dev;
 
        in6_dev = __in6_dev_get(dev);
        if (!in6_dev)
@@ -1363,19 +1448,20 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
        saddr = &iphdr->saddr;
        daddr = &iphdr->daddr;
 
-       if (ipv6_addr_loopback(daddr) ||
-           ipv6_addr_is_multicast(daddr))
-               goto out;
-
        msg = (struct nd_msg *)skb_transport_header(skb);
        if (msg->icmph.icmp6_code != 0 ||
            msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
                goto out;
 
-       n = neigh_lookup(ipv6_stub->nd_tbl, daddr, dev);
+       if (ipv6_addr_loopback(daddr) ||
+           ipv6_addr_is_multicast(&msg->target))
+               goto out;
+
+       n = neigh_lookup(ipv6_stub->nd_tbl, &msg->target, dev);
 
        if (n) {
                struct vxlan_fdb *f;
+               struct sk_buff *reply;
 
                if (!(n->nud_state & NUD_CONNECTED)) {
                        neigh_release(n);
@@ -1389,13 +1475,23 @@ static int neigh_reduce(struct net_device *dev, struct sk_buff *skb)
                        goto out;
                }
 
-               ipv6_stub->ndisc_send_na(dev, n, saddr, &msg->target,
-                                        !!in6_dev->cnf.forwarding,
-                                        true, false, false);
+               reply = vxlan_na_create(skb, n,
+                                       !!(f ? f->flags & NTF_ROUTER : 0));
+
                neigh_release(n);
+
+               if (reply == NULL)
+                       goto out;
+
+               if (netif_rx_ni(reply) == NET_RX_DROP)
+                       dev->stats.rx_dropped++;
+
        } else if (vxlan->flags & VXLAN_F_L3MISS) {
-               ipa.sin6.sin6_addr = *daddr;
-               ipa.sa.sa_family = AF_INET6;
+               union vxlan_addr ipa = {
+                       .sin6.sin6_addr = msg->target,
+                       .sa.sa_family = AF_INET6,
+               };
+
                vxlan_ip_miss(dev, &ipa);
        }
 
@@ -1981,19 +2077,11 @@ static int vxlan_init(struct net_device *dev)
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_sock *vs;
-       int i;
 
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *vxlan_stats;
-               vxlan_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&vxlan_stats->syncp);
-       }
-
-
        spin_lock(&vn->sock_lock);
        vs = vxlan_find_sock(dev_net(dev), vxlan->dst_port);
        if (vs) {
index 0d1c7592efa08eac1dc7d02340e9f13db0895d2b..19f7cb2cdef3c133fa2d04b4b2560d0acc6c2c35 100644 (file)
@@ -71,12 +71,9 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev,
                       const void *saddr, unsigned len)
 {
        struct frhdr            hdr;
-       struct dlci_local       *dlp;
        unsigned int            hlen;
        char                    *dest;
 
-       dlp = netdev_priv(dev);
-
        hdr.control = FRAD_I_UI;
        switch (type)
        {
@@ -107,11 +104,9 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev,
 
 static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
 {
-       struct dlci_local *dlp;
        struct frhdr            *hdr;
        int                                     process, header;
 
-       dlp = netdev_priv(dev);
        if (!pskb_may_pull(skb, sizeof(*hdr))) {
                netdev_notice(dev, "invalid data no header\n");
                dev->stats.rx_errors++;
index 48896138418f21e206782bc259e8fa0b5da9ace7..a9970f1af976a5b0c34d41be8df61ed47365713b 100644 (file)
@@ -374,8 +374,7 @@ netdev_tx_t i2400m_hard_start_xmit(struct sk_buff *skb,
 
        d_fnstart(3, dev, "(skb %p net_dev %p)\n", skb, net_dev);
 
-       if (skb_header_cloned(skb) && 
-           pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+       if (skb_cow_head(skb, 0))
                goto drop;
 
        if (i2400m->state == I2400M_SS_IDLE)
index 0992f7c70e1ac7a93d4468c8d3484df49b0a714e..c8a9dfab1fee2ea4778046b186428ba3f014e054 100644 (file)
@@ -1547,6 +1547,7 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
                if (reg != last_val)
                        return true;
 
+               udelay(1);
                last_val = reg;
                if ((reg & 0x7E7FFFEF) == 0x00702400)
                        continue;
@@ -1559,8 +1560,6 @@ bool ath9k_hw_check_alive(struct ath_hw *ah)
                default:
                        return true;
                }
-
-               udelay(1);
        } while (count-- > 0);
 
        return false;
index f76e6b9bb8e6bbe5fdd2ecd6e4bd676b6170b6ff..87cbec47fb48371403daaa70b32c1b9bc40ce1ec 100644 (file)
@@ -2065,7 +2065,7 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
 
        ATH_TXBUF_RESET(bf);
 
-       if (tid) {
+       if (tid && ieee80211_is_data_present(hdr->frame_control)) {
                fragno = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
                seqno = tid->seq_next;
                hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT);
@@ -2188,7 +2188,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                txq->stopped = true;
        }
 
-       if (txctl->an)
+       if (txctl->an && ieee80211_is_data_present(hdr->frame_control))
                tid = ath_get_skb_tid(sc, txctl->an, skb);
 
        if (info->flags & IEEE80211_TX_CTL_PS_RESPONSE) {
index 58fc0962e2e25a6858a70da6f0e03d4198bd2199..f1e1bb338d681e71c96b130363bf04387c3ffa85 100644 (file)
@@ -41,30 +41,28 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
        switch (use_msi) {
        case 3:
        case 1:
+               wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
+               break;
        case 0:
+               wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
                break;
        default:
-               wil_err(wil, "Invalid use_msi=%d, default to 1\n",
-                       use_msi);
+               wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi);
                use_msi = 1;
        }
-       wil->n_msi = use_msi;
-       if (wil->n_msi) {
-               wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi);
-               rc = pci_enable_msi_block(pdev, wil->n_msi);
-               if (rc && (wil->n_msi == 3)) {
-                       wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
-                       wil->n_msi = 1;
-                       rc = pci_enable_msi_block(pdev, wil->n_msi);
-               }
-               if (rc) {
-                       wil_err(wil, "pci_enable_msi failed, use INTx\n");
-                       wil->n_msi = 0;
-               }
-       } else {
-               wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n");
+
+       if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) {
+               wil_err(wil, "3 MSI mode failed, try 1 MSI\n");
+               use_msi = 1;
+       }
+
+       if (use_msi == 1 && pci_enable_msi(pdev)) {
+               wil_err(wil, "pci_enable_msi failed, use INTx\n");
+               use_msi = 0;
        }
 
+       wil->n_msi = use_msi;
+
        rc = wil6210_init_irq(wil, pdev->irq);
        if (rc)
                goto stop_master;
index 47a6f3957b7f255a1300d7a4e65de8b7bfe9a03a..13c89a0c4ba7ec63f8d7a33688caafa3d407b9f7 100644 (file)
@@ -2140,8 +2140,10 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
                if (pkt_pad == NULL)
                        return -ENOMEM;
                ret = brcmf_sdio_txpkt_hdalign(bus, pkt_pad);
-               if (unlikely(ret < 0))
+               if (unlikely(ret < 0)) {
+                       kfree_skb(pkt_pad);
                        return ret;
+               }
                memcpy(pkt_pad->data,
                       pkt->data + pkt->len - tail_chop,
                       tail_chop);
index bb43251c18f2bb0bc7a87404372d7aed9d277113..c92f27aa71ede1f049c101a0ba185f31d982aaa3 100644 (file)
@@ -192,8 +192,7 @@ int mwifiex_cmd_append_11ac_tlv(struct mwifiex_private *priv,
                vht_cap->header.len  =
                                cpu_to_le16(sizeof(struct ieee80211_vht_cap));
                memcpy((u8 *)vht_cap + sizeof(struct mwifiex_ie_types_header),
-                      (u8 *)bss_desc->bcn_vht_cap +
-                      sizeof(struct ieee_types_header),
+                      (u8 *)bss_desc->bcn_vht_cap,
                       le16_to_cpu(vht_cap->header.len));
 
                mwifiex_fill_vht_cap_tlv(priv, &vht_cap->vht_cap,
index 70159dd01acfd521149d9c27821a654d4a4f5bc1..d14ead8beca860dba6c984d26df095b104bb1375 100644 (file)
@@ -323,8 +323,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
                ht_cap->header.len =
                                cpu_to_le16(sizeof(struct ieee80211_ht_cap));
                memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
-                      (u8 *) bss_desc->bcn_ht_cap +
-                      sizeof(struct ieee_types_header),
+                      (u8 *)bss_desc->bcn_ht_cap,
                       le16_to_cpu(ht_cap->header.len));
 
                mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
index 668a91cd115434703e896cd5a1d49495c77f70b9..77db0886c6e2e9fa764f2a0add8876b477972915 100644 (file)
@@ -749,7 +749,7 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
 
 static u16
 mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb,
-                               void *accel_priv)
+                               void *accel_priv, select_queue_fallback_t fallback)
 {
        skb->priority = cfg80211_classify8021d(skb, NULL);
        return mwifiex_1d_to_wmm_queue[skb->priority];
index e496497a7af04d5890a5eaea003f79c238509c44..7b3af3d29ded478ad658eed5a3836403d6dd7542 100644 (file)
@@ -2324,12 +2324,12 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv)
                         curr_bss->ht_info_offset);
 
        if (curr_bss->bcn_vht_cap)
-               curr_bss->bcn_ht_cap = (void *)(curr_bss->beacon_buf +
-                                               curr_bss->vht_cap_offset);
+               curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
+                                                curr_bss->vht_cap_offset);
 
        if (curr_bss->bcn_vht_oper)
-               curr_bss->bcn_ht_oper = (void *)(curr_bss->beacon_buf +
-                                                curr_bss->vht_info_offset);
+               curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
+                                                 curr_bss->vht_info_offset);
 
        if (curr_bss->bcn_bss_co_2040)
                curr_bss->bcn_bss_co_2040 =
index 7f8b5d156c8c91dde72791d439aa5bbc9e66b7cc..41d4a8167dc32f368a8fdf061bea4fe9944fd0f1 100644 (file)
@@ -5460,14 +5460,15 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
 
        rt2800_bbp_write(rt2x00dev, 68, 0x0b);
 
-       rt2800_bbp_write(rt2x00dev, 69, 0x0d);
-       rt2800_bbp_write(rt2x00dev, 70, 0x06);
+       rt2800_bbp_write(rt2x00dev, 69, 0x12);
        rt2800_bbp_write(rt2x00dev, 73, 0x13);
        rt2800_bbp_write(rt2x00dev, 75, 0x46);
        rt2800_bbp_write(rt2x00dev, 76, 0x28);
 
        rt2800_bbp_write(rt2x00dev, 77, 0x59);
 
+       rt2800_bbp_write(rt2x00dev, 70, 0x0a);
+
        rt2800_bbp_write(rt2x00dev, 79, 0x13);
        rt2800_bbp_write(rt2x00dev, 80, 0x05);
        rt2800_bbp_write(rt2x00dev, 81, 0x33);
@@ -5510,7 +5511,6 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt(rt2x00dev, RT5392)) {
                rt2800_bbp_write(rt2x00dev, 134, 0xd0);
                rt2800_bbp_write(rt2x00dev, 135, 0xf6);
-               rt2800_bbp_write(rt2x00dev, 148, 0x84);
        }
 
        rt2800_disable_unused_dac_adc(rt2x00dev);
index 4c76bcb9a879d23ad98aae968d529450606db6f8..89b2d429c4405ff6c54c8f6fca3bd7e8825bc623 100644 (file)
 typedef unsigned int pending_ring_idx_t;
 #define INVALID_PENDING_RING_IDX (~0U)
 
-/* For the head field in pending_tx_info: it is used to indicate
- * whether this tx info is the head of one or more coalesced requests.
- *
- * When head != INVALID_PENDING_RING_IDX, it means the start of a new
- * tx requests queue and the end of previous queue.
- *
- * An example sequence of head fields (I = INVALID_PENDING_RING_IDX):
- *
- * ...|0 I I I|5 I|9 I I I|...
- * -->|<-INUSE----------------
- *
- * After consuming the first slot(s) we have:
- *
- * ...|V V V V|5 I|9 I I I|...
- * -----FREE->|<-INUSE--------
- *
- * where V stands for "valid pending ring index". Any number other
- * than INVALID_PENDING_RING_IDX is OK. These entries are considered
- * free and can contain any number other than
- * INVALID_PENDING_RING_IDX. In practice we use 0.
- *
- * The in use non-INVALID_PENDING_RING_IDX (say 0, 5 and 9 in the
- * above example) number is the index into pending_tx_info and
- * mmap_pages arrays.
- */
 struct pending_tx_info {
-       struct xen_netif_tx_request req; /* coalesced tx request */
-       pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX
-                                 * if it is head of one or more tx
-                                 * reqs
-                                 */
+       struct xen_netif_tx_request req; /* tx request */
+       /* Callback data for released SKBs. The callback is always
+        * xenvif_zerocopy_callback, desc contains the pending_idx, which is
+        * also an index in pending_tx_info array. It is initialized in
+        * xenvif_alloc and it never changes.
+        * skb_shinfo(skb)->destructor_arg points to the first mapped slot's
+        * callback_struct in this array of struct pending_tx_info's, then ctx
+        * to the next, or NULL if there is no more slot for this skb.
+        * ubuf_to_vif is a helper which finds the struct xenvif from a pointer
+        * to this field.
+        */
+       struct ubuf_info callback_struct;
 };
 
 #define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
@@ -99,7 +81,7 @@ struct xenvif_rx_meta {
 
 #define MAX_BUFFER_OFFSET PAGE_SIZE
 
-#define MAX_PENDING_REQS 256
+#define MAX_PENDING_REQS XEN_NETIF_TX_RING_SIZE
 
 /* It's possible for an skb to have a maximal number of frags
  * but still be less than MAX_BUFFER_OFFSET in size. Thus the
@@ -108,6 +90,15 @@ struct xenvif_rx_meta {
  */
 #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE)
 
+#define NETBACK_INVALID_HANDLE -1
+
+/* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating
+ * the maximum slots a valid packet can use. Now this value is defined
+ * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by
+ * all backend.
+ */
+#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN
+
 struct xenvif {
        /* Unique identifier for this interface. */
        domid_t          domid;
@@ -126,13 +117,26 @@ struct xenvif {
        pending_ring_idx_t pending_cons;
        u16 pending_ring[MAX_PENDING_REQS];
        struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
-
-       /* Coalescing tx requests before copying makes number of grant
-        * copy ops greater or equal to number of slots required. In
-        * worst case a tx request consumes 2 gnttab_copy.
+       grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
+
+       struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
+       struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
+       /* passed to gnttab_[un]map_refs with pages under (un)mapping */
+       struct page *pages_to_map[MAX_PENDING_REQS];
+       struct page *pages_to_unmap[MAX_PENDING_REQS];
+
+       /* This prevents zerocopy callbacks  to race over dealloc_ring */
+       spinlock_t callback_lock;
+       /* This prevents dealloc thread and NAPI instance to race over response
+        * creation and pending_ring in xenvif_idx_release. In xenvif_tx_err
+        * it only protect response creation
         */
-       struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS];
-
+       spinlock_t response_lock;
+       pending_ring_idx_t dealloc_prod;
+       pending_ring_idx_t dealloc_cons;
+       u16 dealloc_ring[MAX_PENDING_REQS];
+       struct task_struct *dealloc_task;
+       wait_queue_head_t dealloc_wq;
 
        /* Use kthread for guest RX */
        struct task_struct *task;
@@ -143,11 +147,10 @@ struct xenvif {
        char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */
        struct xen_netif_rx_back_ring rx;
        struct sk_buff_head rx_queue;
-       bool rx_queue_stopped;
-       /* Set when the RX interrupt is triggered by the frontend.
-        * The worker thread may need to wake the queue.
-        */
-       bool rx_event;
+       RING_IDX rx_last_skb_slots;
+       bool rx_queue_purge;
+
+       struct timer_list wake_queue;
 
        /* This array is allocated seperately as it is large */
        struct gnttab_copy *grant_copy_op;
@@ -179,6 +182,10 @@ struct xenvif {
 
        /* Statistics */
        unsigned long rx_gso_checksum_fixup;
+       unsigned long tx_zerocopy_sent;
+       unsigned long tx_zerocopy_success;
+       unsigned long tx_zerocopy_fail;
+       unsigned long tx_frag_overflow;
 
        /* Miscellaneous private stuff. */
        struct net_device *dev;
@@ -220,9 +227,11 @@ void xenvif_carrier_off(struct xenvif *vif);
 
 int xenvif_tx_action(struct xenvif *vif, int budget);
 
-int xenvif_kthread(void *data);
+int xenvif_kthread_guest_rx(void *data);
 void xenvif_kick_thread(struct xenvif *vif);
 
+int xenvif_dealloc_kthread(void *data);
+
 /* Determine whether the needed number of slots (req) are available,
  * and set req_event if not.
  */
@@ -230,6 +239,24 @@ bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed);
 
 void xenvif_stop_queue(struct xenvif *vif);
 
+/* Callback from stack when TX packet can be released */
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success);
+
+/* Unmap a pending page and release it back to the guest */
+void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx);
+
+static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
+{
+       return MAX_PENDING_REQS -
+               vif->pending_prod + vif->pending_cons;
+}
+
+/* Callback from stack when TX packet can be released */
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success);
+
 extern bool separate_tx_rx_irq;
 
+extern unsigned int rx_drain_timeout_msecs;
+extern unsigned int rx_drain_timeout_jiffies;
+
 #endif /* __XEN_NETBACK__COMMON_H__ */
index b9de31ea7fc48ac333f30dfa17041fdef893895a..cdc298e3b747b71a58c625f5e1aefe7dc9d8cb7c 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <xen/events.h>
 #include <asm/xen/hypercall.h>
+#include <xen/balloon.h>
 
 #define XENVIF_QUEUE_LENGTH 32
 #define XENVIF_NAPI_WEIGHT  64
@@ -100,7 +101,6 @@ static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id)
 {
        struct xenvif *vif = dev_id;
 
-       vif->rx_event = true;
        xenvif_kick_thread(vif);
 
        return IRQ_HANDLED;
@@ -114,6 +114,18 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void xenvif_wake_queue(unsigned long data)
+{
+       struct xenvif *vif = (struct xenvif *)data;
+
+       if (netif_queue_stopped(vif->dev)) {
+               netdev_err(vif->dev, "draining TX queue\n");
+               vif->rx_queue_purge = true;
+               xenvif_kick_thread(vif);
+               netif_wake_queue(vif->dev);
+       }
+}
+
 static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct xenvif *vif = netdev_priv(dev);
@@ -122,7 +134,9 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
        BUG_ON(skb->dev != dev);
 
        /* Drop the packet if vif is not ready */
-       if (vif->task == NULL || !xenvif_schedulable(vif))
+       if (vif->task == NULL ||
+           vif->dealloc_task == NULL ||
+           !xenvif_schedulable(vif))
                goto drop;
 
        /* At best we'll need one slot for the header and one for each
@@ -133,16 +147,20 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev)
        /* If the skb is GSO then we'll also need an extra slot for the
         * metadata.
         */
-       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
-           skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+       if (skb_is_gso(skb))
                min_slots_needed++;
 
        /* If the skb can't possibly fit in the remaining slots
         * then turn off the queue to give the ring a chance to
         * drain.
         */
-       if (!xenvif_rx_ring_slots_available(vif, min_slots_needed))
+       if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) {
+               vif->wake_queue.function = xenvif_wake_queue;
+               vif->wake_queue.data = (unsigned long)vif;
                xenvif_stop_queue(vif);
+               mod_timer(&vif->wake_queue,
+                       jiffies + rx_drain_timeout_jiffies);
+       }
 
        skb_queue_tail(&vif->rx_queue, skb);
        xenvif_kick_thread(vif);
@@ -235,6 +253,28 @@ static const struct xenvif_stat {
                "rx_gso_checksum_fixup",
                offsetof(struct xenvif, rx_gso_checksum_fixup)
        },
+       /* If (sent != success + fail), there are probably packets never
+        * freed up properly!
+        */
+       {
+               "tx_zerocopy_sent",
+               offsetof(struct xenvif, tx_zerocopy_sent),
+       },
+       {
+               "tx_zerocopy_success",
+               offsetof(struct xenvif, tx_zerocopy_success),
+       },
+       {
+               "tx_zerocopy_fail",
+               offsetof(struct xenvif, tx_zerocopy_fail)
+       },
+       /* Number of packets exceeding MAX_SKB_FRAG slots. You should use
+        * a guest with the same MAX_SKB_FRAG
+        */
+       {
+               "tx_frag_overflow",
+               offsetof(struct xenvif, tx_frag_overflow)
+       },
 };
 
 static int xenvif_get_sset_count(struct net_device *dev, int string_set)
@@ -328,6 +368,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
        init_timer(&vif->credit_timeout);
        vif->credit_window_start = get_jiffies_64();
 
+       init_timer(&vif->wake_queue);
+
        dev->netdev_ops = &xenvif_netdev_ops;
        dev->hw_features = NETIF_F_SG |
                NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
@@ -344,8 +386,26 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
        vif->pending_prod = MAX_PENDING_REQS;
        for (i = 0; i < MAX_PENDING_REQS; i++)
                vif->pending_ring[i] = i;
-       for (i = 0; i < MAX_PENDING_REQS; i++)
-               vif->mmap_pages[i] = NULL;
+       spin_lock_init(&vif->callback_lock);
+       spin_lock_init(&vif->response_lock);
+       /* If ballooning is disabled, this will consume real memory, so you
+        * better enable it. The long term solution would be to use just a
+        * bunch of valid page descriptors, without dependency on ballooning
+        */
+       err = alloc_xenballooned_pages(MAX_PENDING_REQS,
+                                      vif->mmap_pages,
+                                      false);
+       if (err) {
+               netdev_err(dev, "Could not reserve mmap_pages\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       for (i = 0; i < MAX_PENDING_REQS; i++) {
+               vif->pending_tx_info[i].callback_struct = (struct ubuf_info)
+                       { .callback = xenvif_zerocopy_callback,
+                         .ctx = NULL,
+                         .desc = i };
+               vif->grant_tx_handle[i] = NETBACK_INVALID_HANDLE;
+       }
 
        /*
         * Initialise a dummy MAC address. We choose the numerically
@@ -383,12 +443,14 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
 
        BUG_ON(vif->tx_irq);
        BUG_ON(vif->task);
+       BUG_ON(vif->dealloc_task);
 
        err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
        if (err < 0)
                goto err;
 
        init_waitqueue_head(&vif->wq);
+       init_waitqueue_head(&vif->dealloc_wq);
 
        if (tx_evtchn == rx_evtchn) {
                /* feature-split-event-channels == 0 */
@@ -422,8 +484,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
                disable_irq(vif->rx_irq);
        }
 
-       task = kthread_create(xenvif_kthread,
-                             (void *)vif, "%s", vif->dev->name);
+       task = kthread_create(xenvif_kthread_guest_rx,
+                             (void *)vif, "%s-guest-rx", vif->dev->name);
        if (IS_ERR(task)) {
                pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
                err = PTR_ERR(task);
@@ -432,6 +494,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
 
        vif->task = task;
 
+       task = kthread_create(xenvif_dealloc_kthread,
+                             (void *)vif, "%s-dealloc", vif->dev->name);
+       if (IS_ERR(task)) {
+               pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
+               err = PTR_ERR(task);
+               goto err_rx_unbind;
+       }
+
+       vif->dealloc_task = task;
+
        rtnl_lock();
        if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
                dev_set_mtu(vif->dev, ETH_DATA_LEN);
@@ -442,6 +514,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
        rtnl_unlock();
 
        wake_up_process(vif->task);
+       wake_up_process(vif->dealloc_task);
 
        return 0;
 
@@ -475,10 +548,16 @@ void xenvif_disconnect(struct xenvif *vif)
                xenvif_carrier_off(vif);
 
        if (vif->task) {
+               del_timer_sync(&vif->wake_queue);
                kthread_stop(vif->task);
                vif->task = NULL;
        }
 
+       if (vif->dealloc_task) {
+               kthread_stop(vif->dealloc_task);
+               vif->dealloc_task = NULL;
+       }
+
        if (vif->tx_irq) {
                if (vif->tx_irq == vif->rx_irq)
                        unbind_from_irqhandler(vif->tx_irq, vif);
@@ -494,6 +573,43 @@ void xenvif_disconnect(struct xenvif *vif)
 
 void xenvif_free(struct xenvif *vif)
 {
+       int i, unmap_timeout = 0;
+       /* Here we want to avoid timeout messages if an skb can be legitimately
+        * stuck somewhere else. Realistically this could be an another vif's
+        * internal or QDisc queue. That another vif also has this
+        * rx_drain_timeout_msecs timeout, but the timer only ditches the
+        * internal queue. After that, the QDisc queue can put in worst case
+        * XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS skbs into that another vif's
+        * internal queue, so we need several rounds of such timeouts until we
+        * can be sure that no another vif should have skb's from us. We are
+        * not sending more skb's, so newly stuck packets are not interesting
+        * for us here.
+        */
+       unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000) *
+               DIV_ROUND_UP(XENVIF_QUEUE_LENGTH, (XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS));
+
+       for (i = 0; i < MAX_PENDING_REQS; ++i) {
+               if (vif->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) {
+                       unmap_timeout++;
+                       schedule_timeout(msecs_to_jiffies(1000));
+                       if (unmap_timeout > worst_case_skb_lifetime &&
+                           net_ratelimit())
+                               netdev_err(vif->dev,
+                                          "Page still granted! Index: %x\n",
+                                          i);
+                       /* If there are still unmapped pages, reset the loop to
+                        * start checking again. We shouldn't exit here until
+                        * dealloc thread and NAPI instance release all the
+                        * pages. If a kernel bug causes the skbs to stall
+                        * somewhere, the interface cannot be brought down
+                        * properly.
+                        */
+                       i = -1;
+               }
+       }
+
+       free_xenballooned_pages(MAX_PENDING_REQS, vif->mmap_pages);
+
        netif_napi_del(&vif->napi);
 
        unregister_netdev(vif->dev);
index 6b62c3eb8e181411ab8508828ab1bacbb465d26a..cb784fe5220cccbed4a62c33452d3c53655fa80d 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kthread.h>
 #include <linux/if_vlan.h>
 #include <linux/udp.h>
+#include <linux/highmem.h>
 
 #include <net/tcp.h>
 
 bool separate_tx_rx_irq = 1;
 module_param(separate_tx_rx_irq, bool, 0644);
 
+/* When guest ring is filled up, qdisc queues the packets for us, but we have
+ * to timeout them, otherwise other guests' packets can get stuck there
+ */
+unsigned int rx_drain_timeout_msecs = 10000;
+module_param(rx_drain_timeout_msecs, uint, 0444);
+unsigned int rx_drain_timeout_jiffies;
+
 /*
  * This is the maximum slots a skb can have. If a guest sends a skb
  * which exceeds this limit it is considered malicious.
@@ -62,24 +70,6 @@ module_param(separate_tx_rx_irq, bool, 0644);
 static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT;
 module_param(fatal_skb_slots, uint, 0444);
 
-/*
- * To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating
- * the maximum slots a valid packet can use. Now this value is defined
- * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by
- * all backend.
- */
-#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN
-
-/*
- * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of
- * one or more merged tx requests, otherwise it is the continuation of
- * previous tx request.
- */
-static inline int pending_tx_is_head(struct xenvif *vif, RING_IDX idx)
-{
-       return vif->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX;
-}
-
 static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
                               u8 status);
 
@@ -109,6 +99,21 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif,
        return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx));
 }
 
+#define callback_param(vif, pending_idx) \
+       (vif->pending_tx_info[pending_idx].callback_struct)
+
+/* Find the containing VIF's structure from a pointer in pending_tx_info array
+ */
+static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf)
+{
+       u16 pending_idx = ubuf->desc;
+       struct pending_tx_info *temp =
+               container_of(ubuf, struct pending_tx_info, callback_struct);
+       return container_of(temp - pending_idx,
+                           struct xenvif,
+                           pending_tx_info[0]);
+}
+
 /* This is a miniumum size for the linear area to avoid lots of
  * calls to __pskb_pull_tail() as we set up checksum offsets. The
  * value 128 was chosen as it covers all IPv4 and most likely
@@ -131,12 +136,6 @@ static inline pending_ring_idx_t pending_index(unsigned i)
        return i & (MAX_PENDING_REQS-1);
 }
 
-static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif)
-{
-       return MAX_PENDING_REQS -
-               vif->pending_prod + vif->pending_cons;
-}
-
 bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed)
 {
        RING_IDX prod, cons;
@@ -235,12 +234,14 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif,
 static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                                 struct netrx_pending_operations *npo,
                                 struct page *page, unsigned long size,
-                                unsigned long offset, int *head)
+                                unsigned long offset, int *head,
+                                struct xenvif *foreign_vif,
+                                grant_ref_t foreign_gref)
 {
        struct gnttab_copy *copy_gop;
        struct xenvif_rx_meta *meta;
        unsigned long bytes;
-       int gso_type;
+       int gso_type = XEN_NETIF_GSO_TYPE_NONE;
 
        /* Data must not cross a page boundary. */
        BUG_ON(size + offset > PAGE_SIZE<<compound_order(page));
@@ -277,8 +278,15 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                copy_gop->flags = GNTCOPY_dest_gref;
                copy_gop->len = bytes;
 
-               copy_gop->source.domid = DOMID_SELF;
-               copy_gop->source.u.gmfn = virt_to_mfn(page_address(page));
+               if (foreign_vif) {
+                       copy_gop->source.domid = foreign_vif->domid;
+                       copy_gop->source.u.ref = foreign_gref;
+                       copy_gop->flags |= GNTCOPY_source_gref;
+               } else {
+                       copy_gop->source.domid = DOMID_SELF;
+                       copy_gop->source.u.gmfn =
+                               virt_to_mfn(page_address(page));
+               }
                copy_gop->source.offset = offset;
 
                copy_gop->dest.domid = vif->domid;
@@ -299,12 +307,12 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb,
                }
 
                /* Leave a gap for the GSO descriptor. */
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
-                       gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
-               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
-                       gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
-               else
-                       gso_type = XEN_NETIF_GSO_TYPE_NONE;
+               if (skb_is_gso(skb)) {
+                       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                               gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+                       else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                               gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
+               }
 
                if (*head && ((1 << gso_type) & vif->gso_mask))
                        vif->rx.req_cons++;
@@ -338,19 +346,18 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        int head = 1;
        int old_meta_prod;
        int gso_type;
-       int gso_size;
+       struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg;
+       grant_ref_t foreign_grefs[MAX_SKB_FRAGS];
+       struct xenvif *foreign_vif = NULL;
 
        old_meta_prod = npo->meta_prod;
 
-       if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
-               gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
-               gso_size = skb_shinfo(skb)->gso_size;
-       } else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
-               gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
-               gso_size = skb_shinfo(skb)->gso_size;
-       } else {
-               gso_type = XEN_NETIF_GSO_TYPE_NONE;
-               gso_size = 0;
+       gso_type = XEN_NETIF_GSO_TYPE_NONE;
+       if (skb_is_gso(skb)) {
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
+                       gso_type = XEN_NETIF_GSO_TYPE_TCPV4;
+               else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                       gso_type = XEN_NETIF_GSO_TYPE_TCPV6;
        }
 
        /* Set up a GSO prefix descriptor, if necessary */
@@ -358,7 +365,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                req = RING_GET_REQUEST(&vif->rx, vif->rx.req_cons++);
                meta = npo->meta + npo->meta_prod++;
                meta->gso_type = gso_type;
-               meta->gso_size = gso_size;
+               meta->gso_size = skb_shinfo(skb)->gso_size;
                meta->size = 0;
                meta->id = req->id;
        }
@@ -368,7 +375,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
 
        if ((1 << gso_type) & vif->gso_mask) {
                meta->gso_type = gso_type;
-               meta->gso_size = gso_size;
+               meta->gso_size = skb_shinfo(skb)->gso_size;
        } else {
                meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
                meta->gso_size = 0;
@@ -379,6 +386,19 @@ static int xenvif_gop_skb(struct sk_buff *skb,
        npo->copy_off = 0;
        npo->copy_gref = req->gref;
 
+       if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) &&
+                (ubuf->callback == &xenvif_zerocopy_callback)) {
+               int i = 0;
+               foreign_vif = ubuf_to_vif(ubuf);
+
+               do {
+                       u16 pending_idx = ubuf->desc;
+                       foreign_grefs[i++] =
+                               foreign_vif->pending_tx_info[pending_idx].req.gref;
+                       ubuf = (struct ubuf_info *) ubuf->ctx;
+               } while (ubuf);
+       }
+
        data = skb->data;
        while (data < skb_tail_pointer(skb)) {
                unsigned int offset = offset_in_page(data);
@@ -388,7 +408,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                        len = skb_tail_pointer(skb) - data;
 
                xenvif_gop_frag_copy(vif, skb, npo,
-                                    virt_to_page(data), len, offset, &head);
+                                    virt_to_page(data), len, offset, &head,
+                                    NULL,
+                                    0);
                data += len;
        }
 
@@ -397,7 +419,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
                                     skb_frag_page(&skb_shinfo(skb)->frags[i]),
                                     skb_frag_size(&skb_shinfo(skb)->frags[i]),
                                     skb_shinfo(skb)->frags[i].page_offset,
-                                    &head);
+                                    &head,
+                                    foreign_vif,
+                                    foreign_grefs[i]);
        }
 
        return npo->meta_prod - old_meta_prod;
@@ -455,10 +479,12 @@ static void xenvif_add_frag_responses(struct xenvif *vif, int status,
        }
 }
 
-struct skb_cb_overlay {
+struct xenvif_rx_cb {
        int meta_slots_used;
 };
 
+#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
+
 void xenvif_kick_thread(struct xenvif *vif)
 {
        wake_up(&vif->wq);
@@ -474,9 +500,7 @@ static void xenvif_rx_action(struct xenvif *vif)
        LIST_HEAD(notify);
        int ret;
        unsigned long offset;
-       struct skb_cb_overlay *sco;
        bool need_to_notify = false;
-       bool ring_full = false;
 
        struct netrx_pending_operations npo = {
                .copy  = vif->grant_copy_op,
@@ -486,7 +510,7 @@ static void xenvif_rx_action(struct xenvif *vif)
        skb_queue_head_init(&rxq);
 
        while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) {
-               int max_slots_needed;
+               RING_IDX max_slots_needed;
                int i;
 
                /* We need a cheap worse case estimate for the number of
@@ -501,29 +525,28 @@ static void xenvif_rx_action(struct xenvif *vif)
                        size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
                        max_slots_needed += DIV_ROUND_UP(size, PAGE_SIZE);
                }
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
-                   skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+               if (skb_is_gso(skb) &&
+                  (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
+                   skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
                        max_slots_needed++;
 
                /* If the skb may not fit then bail out now */
                if (!xenvif_rx_ring_slots_available(vif, max_slots_needed)) {
                        skb_queue_head(&vif->rx_queue, skb);
                        need_to_notify = true;
-                       ring_full = true;
+                       vif->rx_last_skb_slots = max_slots_needed;
                        break;
-               }
+               } else
+                       vif->rx_last_skb_slots = 0;
 
-               sco = (struct skb_cb_overlay *)skb->cb;
-               sco->meta_slots_used = xenvif_gop_skb(skb, &npo);
-               BUG_ON(sco->meta_slots_used > max_slots_needed);
+               XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo);
+               BUG_ON(XENVIF_RX_CB(skb)->meta_slots_used > max_slots_needed);
 
                __skb_queue_tail(&rxq, skb);
        }
 
        BUG_ON(npo.meta_prod > ARRAY_SIZE(vif->meta));
 
-       vif->rx_queue_stopped = !npo.copy_prod && ring_full;
-
        if (!npo.copy_prod)
                goto done;
 
@@ -531,7 +554,6 @@ static void xenvif_rx_action(struct xenvif *vif)
        gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod);
 
        while ((skb = __skb_dequeue(&rxq)) != NULL) {
-               sco = (struct skb_cb_overlay *)skb->cb;
 
                if ((1 << vif->meta[npo.meta_cons].gso_type) &
                    vif->gso_prefix_mask) {
@@ -542,19 +564,21 @@ static void xenvif_rx_action(struct xenvif *vif)
 
                        resp->offset = vif->meta[npo.meta_cons].gso_size;
                        resp->id = vif->meta[npo.meta_cons].id;
-                       resp->status = sco->meta_slots_used;
+                       resp->status = XENVIF_RX_CB(skb)->meta_slots_used;
 
                        npo.meta_cons++;
-                       sco->meta_slots_used--;
+                       XENVIF_RX_CB(skb)->meta_slots_used--;
                }
 
 
                vif->dev->stats.tx_bytes += skb->len;
                vif->dev->stats.tx_packets++;
 
-               status = xenvif_check_gop(vif, sco->meta_slots_used, &npo);
+               status = xenvif_check_gop(vif,
+                                         XENVIF_RX_CB(skb)->meta_slots_used,
+                                         &npo);
 
-               if (sco->meta_slots_used == 1)
+               if (XENVIF_RX_CB(skb)->meta_slots_used == 1)
                        flags = 0;
                else
                        flags = XEN_NETRXF_more_data;
@@ -591,13 +615,13 @@ static void xenvif_rx_action(struct xenvif *vif)
 
                xenvif_add_frag_responses(vif, status,
                                          vif->meta + npo.meta_cons + 1,
-                                         sco->meta_slots_used);
+                                         XENVIF_RX_CB(skb)->meta_slots_used);
 
                RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret);
 
                need_to_notify |= !!ret;
 
-               npo.meta_cons += sco->meta_slots_used;
+               npo.meta_cons += XENVIF_RX_CB(skb)->meta_slots_used;
                dev_kfree_skb(skb);
        }
 
@@ -647,9 +671,12 @@ static void xenvif_tx_err(struct xenvif *vif,
                          struct xen_netif_tx_request *txp, RING_IDX end)
 {
        RING_IDX cons = vif->tx.req_cons;
+       unsigned long flags;
 
        do {
+               spin_lock_irqsave(&vif->response_lock, flags);
                make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR);
+               spin_unlock_irqrestore(&vif->response_lock, flags);
                if (cons == end)
                        break;
                txp = RING_GET_REQUEST(&vif->tx, cons++);
@@ -761,180 +788,168 @@ static int xenvif_count_requests(struct xenvif *vif,
        return slots;
 }
 
-static struct page *xenvif_alloc_page(struct xenvif *vif,
-                                     u16 pending_idx)
+
+struct xenvif_tx_cb {
+       u16 pending_idx;
+};
+
+#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
+
+static inline void xenvif_tx_create_gop(struct xenvif *vif,
+                                       u16 pending_idx,
+                                       struct xen_netif_tx_request *txp,
+                                       struct gnttab_map_grant_ref *gop)
 {
-       struct page *page;
+       vif->pages_to_map[gop-vif->tx_map_ops] = vif->mmap_pages[pending_idx];
+       gnttab_set_map_op(gop, idx_to_kaddr(vif, pending_idx),
+                         GNTMAP_host_map | GNTMAP_readonly,
+                         txp->gref, vif->domid);
+
+       memcpy(&vif->pending_tx_info[pending_idx].req, txp,
+              sizeof(*txp));
+}
 
-       page = alloc_page(GFP_ATOMIC|__GFP_COLD);
-       if (!page)
+static inline struct sk_buff *xenvif_alloc_skb(unsigned int size)
+{
+       struct sk_buff *skb =
+               alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN,
+                         GFP_ATOMIC | __GFP_NOWARN);
+       if (unlikely(skb == NULL))
                return NULL;
-       vif->mmap_pages[pending_idx] = page;
 
-       return page;
+       /* Packets passed to netif_rx() must have some headroom. */
+       skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+
+       /* Initialize it here to avoid later surprises */
+       skb_shinfo(skb)->destructor_arg = NULL;
+
+       return skb;
 }
 
-static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif,
-                                              struct sk_buff *skb,
-                                              struct xen_netif_tx_request *txp,
-                                              struct gnttab_copy *gop)
+static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif,
+                                                       struct sk_buff *skb,
+                                                       struct xen_netif_tx_request *txp,
+                                                       struct gnttab_map_grant_ref *gop)
 {
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        skb_frag_t *frags = shinfo->frags;
-       u16 pending_idx = *((u16 *)skb->data);
-       u16 head_idx = 0;
-       int slot, start;
-       struct page *page;
-       pending_ring_idx_t index, start_idx = 0;
-       uint16_t dst_offset;
-       unsigned int nr_slots;
-       struct pending_tx_info *first = NULL;
+       u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+       int start;
+       pending_ring_idx_t index;
+       unsigned int nr_slots, frag_overflow = 0;
 
        /* At this point shinfo->nr_frags is in fact the number of
         * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX.
         */
+       if (shinfo->nr_frags > MAX_SKB_FRAGS) {
+               frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS;
+               BUG_ON(frag_overflow > MAX_SKB_FRAGS);
+               shinfo->nr_frags = MAX_SKB_FRAGS;
+       }
        nr_slots = shinfo->nr_frags;
 
        /* Skip first skb fragment if it is on same page as header fragment. */
        start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
 
-       /* Coalesce tx requests, at this point the packet passed in
-        * should be <= 64K. Any packets larger than 64K have been
-        * handled in xenvif_count_requests().
-        */
-       for (shinfo->nr_frags = slot = start; slot < nr_slots;
-            shinfo->nr_frags++) {
-               struct pending_tx_info *pending_tx_info =
-                       vif->pending_tx_info;
+       for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots;
+            shinfo->nr_frags++, txp++, gop++) {
+               index = pending_index(vif->pending_cons++);
+               pending_idx = vif->pending_ring[index];
+               xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+               frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
+       }
 
-               page = alloc_page(GFP_ATOMIC|__GFP_COLD);
-               if (!page)
-                       goto err;
-
-               dst_offset = 0;
-               first = NULL;
-               while (dst_offset < PAGE_SIZE && slot < nr_slots) {
-                       gop->flags = GNTCOPY_source_gref;
-
-                       gop->source.u.ref = txp->gref;
-                       gop->source.domid = vif->domid;
-                       gop->source.offset = txp->offset;
-
-                       gop->dest.domid = DOMID_SELF;
-
-                       gop->dest.offset = dst_offset;
-                       gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-
-                       if (dst_offset + txp->size > PAGE_SIZE) {
-                               /* This page can only merge a portion
-                                * of tx request. Do not increment any
-                                * pointer / counter here. The txp
-                                * will be dealt with in future
-                                * rounds, eventually hitting the
-                                * `else` branch.
-                                */
-                               gop->len = PAGE_SIZE - dst_offset;
-                               txp->offset += gop->len;
-                               txp->size -= gop->len;
-                               dst_offset += gop->len; /* quit loop */
-                       } else {
-                               /* This tx request can be merged in the page */
-                               gop->len = txp->size;
-                               dst_offset += gop->len;
-
-                               index = pending_index(vif->pending_cons++);
-
-                               pending_idx = vif->pending_ring[index];
-
-                               memcpy(&pending_tx_info[pending_idx].req, txp,
-                                      sizeof(*txp));
-
-                               /* Poison these fields, corresponding
-                                * fields for head tx req will be set
-                                * to correct values after the loop.
-                                */
-                               vif->mmap_pages[pending_idx] = (void *)(~0UL);
-                               pending_tx_info[pending_idx].head =
-                                       INVALID_PENDING_RING_IDX;
-
-                               if (!first) {
-                                       first = &pending_tx_info[pending_idx];
-                                       start_idx = index;
-                                       head_idx = pending_idx;
-                               }
-
-                               txp++;
-                               slot++;
-                       }
+       if (frag_overflow) {
+               struct sk_buff *nskb = xenvif_alloc_skb(0);
+               if (unlikely(nskb == NULL)) {
+                       if (net_ratelimit())
+                               netdev_err(vif->dev,
+                                          "Can't allocate the frag_list skb.\n");
+                       return NULL;
+               }
+
+               shinfo = skb_shinfo(nskb);
+               frags = shinfo->frags;
 
-                       gop++;
+               for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow;
+                    shinfo->nr_frags++, txp++, gop++) {
+                       index = pending_index(vif->pending_cons++);
+                       pending_idx = vif->pending_ring[index];
+                       xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+                       frag_set_pending_idx(&frags[shinfo->nr_frags],
+                                            pending_idx);
                }
 
-               first->req.offset = 0;
-               first->req.size = dst_offset;
-               first->head = start_idx;
-               vif->mmap_pages[head_idx] = page;
-               frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx);
+               skb_shinfo(skb)->frag_list = nskb;
        }
 
-       BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS);
-
        return gop;
-err:
-       /* Unwind, freeing all pages and sending error responses. */
-       while (shinfo->nr_frags-- > start) {
-               xenvif_idx_release(vif,
-                               frag_get_pending_idx(&frags[shinfo->nr_frags]),
-                               XEN_NETIF_RSP_ERROR);
+}
+
+static inline void xenvif_grant_handle_set(struct xenvif *vif,
+                                          u16 pending_idx,
+                                          grant_handle_t handle)
+{
+       if (unlikely(vif->grant_tx_handle[pending_idx] !=
+                    NETBACK_INVALID_HANDLE)) {
+               netdev_err(vif->dev,
+                          "Trying to overwrite active handle! pending_idx: %x\n",
+                          pending_idx);
+               BUG();
        }
-       /* The head too, if necessary. */
-       if (start)
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+       vif->grant_tx_handle[pending_idx] = handle;
+}
 
-       return NULL;
+static inline void xenvif_grant_handle_reset(struct xenvif *vif,
+                                            u16 pending_idx)
+{
+       if (unlikely(vif->grant_tx_handle[pending_idx] ==
+                    NETBACK_INVALID_HANDLE)) {
+               netdev_err(vif->dev,
+                          "Trying to unmap invalid handle! pending_idx: %x\n",
+                          pending_idx);
+               BUG();
+       }
+       vif->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE;
 }
 
 static int xenvif_tx_check_gop(struct xenvif *vif,
                               struct sk_buff *skb,
-                              struct gnttab_copy **gopp)
+                              struct gnttab_map_grant_ref **gopp)
 {
-       struct gnttab_copy *gop = *gopp;
-       u16 pending_idx = *((u16 *)skb->data);
+       struct gnttab_map_grant_ref *gop = *gopp;
+       u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        struct pending_tx_info *tx_info;
        int nr_frags = shinfo->nr_frags;
        int i, err, start;
-       u16 peek; /* peek into next tx request */
+       struct sk_buff *first_skb = NULL;
 
        /* Check status of header. */
        err = gop->status;
        if (unlikely(err))
                xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
+       else
+               xenvif_grant_handle_set(vif, pending_idx , gop->handle);
 
        /* Skip first skb fragment if it is on same page as header fragment. */
        start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
 
+check_frags:
        for (i = start; i < nr_frags; i++) {
                int j, newerr;
-               pending_ring_idx_t head;
 
                pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
                tx_info = &vif->pending_tx_info[pending_idx];
-               head = tx_info->head;
 
                /* Check error status: if okay then remember grant handle. */
-               do {
-                       newerr = (++gop)->status;
-                       if (newerr)
-                               break;
-                       peek = vif->pending_ring[pending_index(++head)];
-               } while (!pending_tx_is_head(vif, peek));
+               newerr = (++gop)->status;
 
                if (likely(!newerr)) {
+                       xenvif_grant_handle_set(vif, pending_idx , gop->handle);
                        /* Had a previous error? Invalidate this fragment. */
                        if (unlikely(err))
-                               xenvif_idx_release(vif, pending_idx,
-                                                  XEN_NETIF_RSP_OKAY);
+                               xenvif_idx_unmap(vif, pending_idx);
                        continue;
                }
 
@@ -944,20 +959,45 @@ static int xenvif_tx_check_gop(struct xenvif *vif,
                /* Not the first error? Preceding frags already invalidated. */
                if (err)
                        continue;
-
                /* First error: invalidate header and preceding fragments. */
-               pending_idx = *((u16 *)skb->data);
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+               if (!first_skb)
+                       pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+               else
+                       pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+               xenvif_idx_unmap(vif, pending_idx);
                for (j = start; j < i; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
-                       xenvif_idx_release(vif, pending_idx,
-                                          XEN_NETIF_RSP_OKAY);
+                       xenvif_idx_unmap(vif, pending_idx);
                }
 
                /* Remember the error: invalidate all subsequent fragments. */
                err = newerr;
        }
 
+       if (skb_has_frag_list(skb)) {
+               first_skb = skb;
+               skb = shinfo->frag_list;
+               shinfo = skb_shinfo(skb);
+               nr_frags = shinfo->nr_frags;
+               start = 0;
+
+               goto check_frags;
+       }
+
+       /* There was a mapping error in the frag_list skb. We have to unmap
+        * the first skb's frags
+        */
+       if (first_skb && err) {
+               int j;
+               shinfo = skb_shinfo(first_skb);
+               pending_idx = XENVIF_TX_CB(skb)->pending_idx;
+               start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+               for (j = start; j < shinfo->nr_frags; j++) {
+                       pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
+                       xenvif_idx_unmap(vif, pending_idx);
+               }
+       }
+
        *gopp = gop + 1;
        return err;
 }
@@ -967,6 +1007,10 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        int nr_frags = shinfo->nr_frags;
        int i;
+       u16 prev_pending_idx = INVALID_PENDING_IDX;
+
+       if (skb_shinfo(skb)->destructor_arg)
+               prev_pending_idx = XENVIF_TX_CB(skb)->pending_idx;
 
        for (i = 0; i < nr_frags; i++) {
                skb_frag_t *frag = shinfo->frags + i;
@@ -976,6 +1020,17 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
 
                pending_idx = frag_get_pending_idx(frag);
 
+               /* If this is not the first frag, chain it to the previous*/
+               if (unlikely(prev_pending_idx == INVALID_PENDING_IDX))
+                       skb_shinfo(skb)->destructor_arg =
+                               &callback_param(vif, pending_idx);
+               else if (likely(pending_idx != prev_pending_idx))
+                       callback_param(vif, prev_pending_idx).ctx =
+                               &callback_param(vif, pending_idx);
+
+               callback_param(vif, pending_idx).ctx = NULL;
+               prev_pending_idx = pending_idx;
+
                txp = &vif->pending_tx_info[pending_idx].req;
                page = virt_to_page(idx_to_kaddr(vif, pending_idx));
                __skb_fill_page_desc(skb, i, page, txp->offset, txp->size);
@@ -983,10 +1038,15 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
                skb->data_len += txp->size;
                skb->truesize += txp->size;
 
-               /* Take an extra reference to offset xenvif_idx_release */
+               /* Take an extra reference to offset network stack's put_page */
                get_page(vif->mmap_pages[pending_idx]);
-               xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
        }
+       /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc
+        * overlaps with "index", and "mapping" is not set. I think mapping
+        * should be set. If delivered to local stack, it would drop this
+        * skb in sk_filter unless the socket has the right to use it.
+        */
+       skb->pfmemalloc = false;
 }
 
 static int xenvif_get_extras(struct xenvif *vif,
@@ -1106,16 +1166,13 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
 
 static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
 {
-       struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop;
+       struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop;
        struct sk_buff *skb;
        int ret;
 
-       while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
-               < MAX_PENDING_REQS) &&
-              (skb_queue_len(&vif->tx_queue) < budget)) {
+       while (skb_queue_len(&vif->tx_queue) < budget) {
                struct xen_netif_tx_request txreq;
                struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX];
-               struct page *page;
                struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1];
                u16 pending_idx;
                RING_IDX idx;
@@ -1191,8 +1248,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                            ret < XEN_NETBK_LEGACY_SLOTS_MAX) ?
                        PKT_PROT_LEN : txreq.size;
 
-               skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN,
-                               GFP_ATOMIC | __GFP_NOWARN);
+               skb = xenvif_alloc_skb(data_len);
                if (unlikely(skb == NULL)) {
                        netdev_dbg(vif->dev,
                                   "Can't allocate a skb in start_xmit.\n");
@@ -1200,9 +1256,6 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                        break;
                }
 
-               /* Packets passed to netif_rx() must have some headroom. */
-               skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
-
                if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
                        struct xen_netif_extra_info *gso;
                        gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
@@ -1214,31 +1267,11 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                        }
                }
 
-               /* XXX could copy straight to head */
-               page = xenvif_alloc_page(vif, pending_idx);
-               if (!page) {
-                       kfree_skb(skb);
-                       xenvif_tx_err(vif, &txreq, idx);
-                       break;
-               }
-
-               gop->source.u.ref = txreq.gref;
-               gop->source.domid = vif->domid;
-               gop->source.offset = txreq.offset;
-
-               gop->dest.u.gmfn = virt_to_mfn(page_address(page));
-               gop->dest.domid = DOMID_SELF;
-               gop->dest.offset = txreq.offset;
-
-               gop->len = txreq.size;
-               gop->flags = GNTCOPY_source_gref;
+               xenvif_tx_create_gop(vif, pending_idx, &txreq, gop);
 
                gop++;
 
-               memcpy(&vif->pending_tx_info[pending_idx].req,
-                      &txreq, sizeof(txreq));
-               vif->pending_tx_info[pending_idx].head = index;
-               *((u16 *)skb->data) = pending_idx;
+               XENVIF_TX_CB(skb)->pending_idx = pending_idx;
 
                __skb_put(skb, data_len);
 
@@ -1266,17 +1299,82 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
 
                vif->tx.req_cons = idx;
 
-               if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops))
+               if ((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops))
                        break;
        }
 
-       return gop - vif->tx_copy_ops;
+       return gop - vif->tx_map_ops;
 }
 
+/* Consolidate skb with a frag_list into a brand new one with local pages on
+ * frags. Returns 0 or -ENOMEM if can't allocate new pages.
+ */
+static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb)
+{
+       unsigned int offset = skb_headlen(skb);
+       skb_frag_t frags[MAX_SKB_FRAGS];
+       int i;
+       struct ubuf_info *uarg;
+       struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
+
+       vif->tx_zerocopy_sent += 2;
+       vif->tx_frag_overflow++;
+
+       xenvif_fill_frags(vif, nskb);
+       /* Subtract frags size, we will correct it later */
+       skb->truesize -= skb->data_len;
+       skb->len += nskb->len;
+       skb->data_len += nskb->len;
+
+       /* create a brand new frags array and coalesce there */
+       for (i = 0; offset < skb->len; i++) {
+               struct page *page;
+               unsigned int len;
+
+               BUG_ON(i >= MAX_SKB_FRAGS);
+               page = alloc_page(GFP_ATOMIC|__GFP_COLD);
+               if (!page) {
+                       int j;
+                       skb->truesize += skb->data_len;
+                       for (j = 0; j < i; j++)
+                               put_page(frags[j].page.p);
+                       return -ENOMEM;
+               }
+
+               if (offset + PAGE_SIZE < skb->len)
+                       len = PAGE_SIZE;
+               else
+                       len = skb->len - offset;
+               if (skb_copy_bits(skb, offset, page_address(page), len))
+                       BUG();
+
+               offset += len;
+               frags[i].page.p = page;
+               frags[i].page_offset = 0;
+               skb_frag_size_set(&frags[i], len);
+       }
+       /* swap out with old one */
+       memcpy(skb_shinfo(skb)->frags,
+              frags,
+              i * sizeof(skb_frag_t));
+       skb_shinfo(skb)->nr_frags = i;
+       skb->truesize += i * PAGE_SIZE;
+
+       /* remove traces of mapped pages and frag_list */
+       skb_frag_list_init(skb);
+       uarg = skb_shinfo(skb)->destructor_arg;
+       uarg->callback(uarg, true);
+       skb_shinfo(skb)->destructor_arg = NULL;
+
+       skb_shinfo(nskb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+       kfree_skb(nskb);
+
+       return 0;
+}
 
 static int xenvif_tx_submit(struct xenvif *vif)
 {
-       struct gnttab_copy *gop = vif->tx_copy_ops;
+       struct gnttab_map_grant_ref *gop = vif->tx_map_ops;
        struct sk_buff *skb;
        int work_done = 0;
 
@@ -1285,7 +1383,7 @@ static int xenvif_tx_submit(struct xenvif *vif)
                u16 pending_idx;
                unsigned data_len;
 
-               pending_idx = *((u16 *)skb->data);
+               pending_idx = XENVIF_TX_CB(skb)->pending_idx;
                txp = &vif->pending_tx_info[pending_idx].req;
 
                /* Check the remap error code. */
@@ -1300,14 +1398,16 @@ static int xenvif_tx_submit(struct xenvif *vif)
                memcpy(skb->data,
                       (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset),
                       data_len);
+               callback_param(vif, pending_idx).ctx = NULL;
                if (data_len < txp->size) {
                        /* Append the packet payload as a fragment. */
                        txp->offset += data_len;
                        txp->size -= data_len;
+                       skb_shinfo(skb)->destructor_arg =
+                               &callback_param(vif, pending_idx);
                } else {
                        /* Schedule a response immediately. */
-                       xenvif_idx_release(vif, pending_idx,
-                                          XEN_NETIF_RSP_OKAY);
+                       xenvif_idx_unmap(vif, pending_idx);
                }
 
                if (txp->flags & XEN_NETTXF_csum_blank)
@@ -1317,6 +1417,17 @@ static int xenvif_tx_submit(struct xenvif *vif)
 
                xenvif_fill_frags(vif, skb);
 
+               if (unlikely(skb_has_frag_list(skb))) {
+                       if (xenvif_handle_frag_list(vif, skb)) {
+                               if (net_ratelimit())
+                                       netdev_err(vif->dev,
+                                                  "Not enough memory to consolidate frag_list!\n");
+                               skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+                               kfree_skb(skb);
+                               continue;
+                       }
+               }
+
                if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) {
                        int target = min_t(int, skb->len, PKT_PROT_LEN);
                        __pskb_pull_tail(skb, target - skb_headlen(skb));
@@ -1329,6 +1440,9 @@ static int xenvif_tx_submit(struct xenvif *vif)
                if (checksum_setup(vif, skb)) {
                        netdev_dbg(vif->dev,
                                   "Can't setup checksum in net_tx_action\n");
+                       /* We have to set this flag to trigger the callback */
+                       if (skb_shinfo(skb)->destructor_arg)
+                               skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
                        kfree_skb(skb);
                        continue;
                }
@@ -1354,17 +1468,126 @@ static int xenvif_tx_submit(struct xenvif *vif)
 
                work_done++;
 
+               /* Set this flag right before netif_receive_skb, otherwise
+                * someone might think this packet already left netback, and
+                * do a skb_copy_ubufs while we are still in control of the
+                * skb. E.g. the __pskb_pull_tail earlier can do such thing.
+                */
+               if (skb_shinfo(skb)->destructor_arg) {
+                       skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
+                       vif->tx_zerocopy_sent++;
+               }
+
                netif_receive_skb(skb);
        }
 
        return work_done;
 }
 
+void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success)
+{
+       unsigned long flags;
+       pending_ring_idx_t index;
+       struct xenvif *vif = ubuf_to_vif(ubuf);
+
+       /* This is the only place where we grab this lock, to protect callbacks
+        * from each other.
+        */
+       spin_lock_irqsave(&vif->callback_lock, flags);
+       do {
+               u16 pending_idx = ubuf->desc;
+               ubuf = (struct ubuf_info *) ubuf->ctx;
+               BUG_ON(vif->dealloc_prod - vif->dealloc_cons >=
+                       MAX_PENDING_REQS);
+               index = pending_index(vif->dealloc_prod);
+               vif->dealloc_ring[index] = pending_idx;
+               /* Sync with xenvif_tx_dealloc_action:
+                * insert idx then incr producer.
+                */
+               smp_wmb();
+               vif->dealloc_prod++;
+       } while (ubuf);
+       wake_up(&vif->dealloc_wq);
+       spin_unlock_irqrestore(&vif->callback_lock, flags);
+
+       if (likely(zerocopy_success))
+               vif->tx_zerocopy_success++;
+       else
+               vif->tx_zerocopy_fail++;
+}
+
+static inline void xenvif_tx_dealloc_action(struct xenvif *vif)
+{
+       struct gnttab_unmap_grant_ref *gop;
+       pending_ring_idx_t dc, dp;
+       u16 pending_idx, pending_idx_release[MAX_PENDING_REQS];
+       unsigned int i = 0;
+
+       dc = vif->dealloc_cons;
+       gop = vif->tx_unmap_ops;
+
+       /* Free up any grants we have finished using */
+       do {
+               dp = vif->dealloc_prod;
+
+               /* Ensure we see all indices enqueued by all
+                * xenvif_zerocopy_callback().
+                */
+               smp_rmb();
+
+               while (dc != dp) {
+                       BUG_ON(gop - vif->tx_unmap_ops > MAX_PENDING_REQS);
+                       pending_idx =
+                               vif->dealloc_ring[pending_index(dc++)];
+
+                       pending_idx_release[gop-vif->tx_unmap_ops] =
+                               pending_idx;
+                       vif->pages_to_unmap[gop-vif->tx_unmap_ops] =
+                               vif->mmap_pages[pending_idx];
+                       gnttab_set_unmap_op(gop,
+                                           idx_to_kaddr(vif, pending_idx),
+                                           GNTMAP_host_map,
+                                           vif->grant_tx_handle[pending_idx]);
+                       xenvif_grant_handle_reset(vif, pending_idx);
+                       ++gop;
+               }
+
+       } while (dp != vif->dealloc_prod);
+
+       vif->dealloc_cons = dc;
+
+       if (gop - vif->tx_unmap_ops > 0) {
+               int ret;
+               ret = gnttab_unmap_refs(vif->tx_unmap_ops,
+                                       NULL,
+                                       vif->pages_to_unmap,
+                                       gop - vif->tx_unmap_ops);
+               if (ret) {
+                       netdev_err(vif->dev, "Unmap fail: nr_ops %tx ret %d\n",
+                                  gop - vif->tx_unmap_ops, ret);
+                       for (i = 0; i < gop - vif->tx_unmap_ops; ++i) {
+                               if (gop[i].status != GNTST_okay)
+                                       netdev_err(vif->dev,
+                                                  " host_addr: %llx handle: %x status: %d\n",
+                                                  gop[i].host_addr,
+                                                  gop[i].handle,
+                                                  gop[i].status);
+                       }
+                       BUG();
+               }
+       }
+
+       for (i = 0; i < gop - vif->tx_unmap_ops; ++i)
+               xenvif_idx_release(vif, pending_idx_release[i],
+                                  XEN_NETIF_RSP_OKAY);
+}
+
+
 /* Called after netfront has transmitted */
 int xenvif_tx_action(struct xenvif *vif, int budget)
 {
        unsigned nr_gops;
-       int work_done;
+       int work_done, ret;
 
        if (unlikely(!tx_work_todo(vif)))
                return 0;
@@ -1374,7 +1597,11 @@ int xenvif_tx_action(struct xenvif *vif, int budget)
        if (nr_gops == 0)
                return 0;
 
-       gnttab_batch_copy(vif->tx_copy_ops, nr_gops);
+       ret = gnttab_map_refs(vif->tx_map_ops,
+                             NULL,
+                             vif->pages_to_map,
+                             nr_gops);
+       BUG_ON(ret);
 
        work_done = xenvif_tx_submit(vif);
 
@@ -1385,45 +1612,18 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx,
                               u8 status)
 {
        struct pending_tx_info *pending_tx_info;
-       pending_ring_idx_t head;
-       u16 peek; /* peek into next tx request */
-
-       BUG_ON(vif->mmap_pages[pending_idx] == (void *)(~0UL));
-
-       /* Already complete? */
-       if (vif->mmap_pages[pending_idx] == NULL)
-               return;
+       pending_ring_idx_t index;
+       unsigned long flags;
 
        pending_tx_info = &vif->pending_tx_info[pending_idx];
-
-       head = pending_tx_info->head;
-
-       BUG_ON(!pending_tx_is_head(vif, head));
-       BUG_ON(vif->pending_ring[pending_index(head)] != pending_idx);
-
-       do {
-               pending_ring_idx_t index;
-               pending_ring_idx_t idx = pending_index(head);
-               u16 info_idx = vif->pending_ring[idx];
-
-               pending_tx_info = &vif->pending_tx_info[info_idx];
-               make_tx_response(vif, &pending_tx_info->req, status);
-
-               /* Setting any number other than
-                * INVALID_PENDING_RING_IDX indicates this slot is
-                * starting a new packet / ending a previous packet.
-                */
-               pending_tx_info->head = 0;
-
-               index = pending_index(vif->pending_prod++);
-               vif->pending_ring[index] = vif->pending_ring[info_idx];
-
-               peek = vif->pending_ring[pending_index(++head)];
-
-       } while (!pending_tx_is_head(vif, peek));
-
-       put_page(vif->mmap_pages[pending_idx]);
-       vif->mmap_pages[pending_idx] = NULL;
+       spin_lock_irqsave(&vif->response_lock, flags);
+       make_tx_response(vif, &pending_tx_info->req, status);
+       index = pending_index(vif->pending_prod);
+       vif->pending_ring[index] = pending_idx;
+       /* TX shouldn't use the index before we give it back here */
+       mb();
+       vif->pending_prod++;
+       spin_unlock_irqrestore(&vif->response_lock, flags);
 }
 
 
@@ -1471,23 +1671,54 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif,
        return resp;
 }
 
+void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx)
+{
+       int ret;
+       struct gnttab_unmap_grant_ref tx_unmap_op;
+
+       gnttab_set_unmap_op(&tx_unmap_op,
+                           idx_to_kaddr(vif, pending_idx),
+                           GNTMAP_host_map,
+                           vif->grant_tx_handle[pending_idx]);
+       xenvif_grant_handle_reset(vif, pending_idx);
+
+       ret = gnttab_unmap_refs(&tx_unmap_op, NULL,
+                               &vif->mmap_pages[pending_idx], 1);
+       if (ret) {
+               netdev_err(vif->dev,
+                          "Unmap fail: ret: %d pending_idx: %d host_addr: %llx handle: %x status: %d\n",
+                          ret,
+                          pending_idx,
+                          tx_unmap_op.host_addr,
+                          tx_unmap_op.handle,
+                          tx_unmap_op.status);
+               BUG();
+       }
+
+       xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY);
+}
+
 static inline int rx_work_todo(struct xenvif *vif)
 {
-       return (!skb_queue_empty(&vif->rx_queue) && !vif->rx_queue_stopped) ||
-               vif->rx_event;
+       return (!skb_queue_empty(&vif->rx_queue) &&
+              xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots)) ||
+              vif->rx_queue_purge;
 }
 
 static inline int tx_work_todo(struct xenvif *vif)
 {
 
-       if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) &&
-           (nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX
-            < MAX_PENDING_REQS))
+       if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)))
                return 1;
 
        return 0;
 }
 
+static inline bool tx_dealloc_work_todo(struct xenvif *vif)
+{
+       return vif->dealloc_cons != vif->dealloc_prod;
+}
+
 void xenvif_unmap_frontend_rings(struct xenvif *vif)
 {
        if (vif->tx.sring)
@@ -1545,7 +1776,7 @@ static void xenvif_start_queue(struct xenvif *vif)
                netif_wake_queue(vif->dev);
 }
 
-int xenvif_kthread(void *data)
+int xenvif_kthread_guest_rx(void *data)
 {
        struct xenvif *vif = data;
        struct sk_buff *skb;
@@ -1557,14 +1788,19 @@ int xenvif_kthread(void *data)
                if (kthread_should_stop())
                        break;
 
+               if (vif->rx_queue_purge) {
+                       skb_queue_purge(&vif->rx_queue);
+                       vif->rx_queue_purge = false;
+               }
+
                if (!skb_queue_empty(&vif->rx_queue))
                        xenvif_rx_action(vif);
 
-               vif->rx_event = false;
-
                if (skb_queue_empty(&vif->rx_queue) &&
-                   netif_queue_stopped(vif->dev))
+                   netif_queue_stopped(vif->dev)) {
+                       del_timer_sync(&vif->wake_queue);
                        xenvif_start_queue(vif);
+               }
 
                cond_resched();
        }
@@ -1576,6 +1812,28 @@ int xenvif_kthread(void *data)
        return 0;
 }
 
+int xenvif_dealloc_kthread(void *data)
+{
+       struct xenvif *vif = data;
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(vif->dealloc_wq,
+                                        tx_dealloc_work_todo(vif) ||
+                                        kthread_should_stop());
+               if (kthread_should_stop())
+                       break;
+
+               xenvif_tx_dealloc_action(vif);
+               cond_resched();
+       }
+
+       /* Unmap anything remaining*/
+       if (tx_dealloc_work_todo(vif))
+               xenvif_tx_dealloc_action(vif);
+
+       return 0;
+}
+
 static int __init netback_init(void)
 {
        int rc = 0;
@@ -1593,6 +1851,8 @@ static int __init netback_init(void)
        if (rc)
                goto failed_init;
 
+       rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs);
+
        return 0;
 
 failed_init:
index ff04d4f95baa3561fbf42899bf95f69eab28412f..057b05700f8baa081014d80b1142e7b2a7808489 100644 (file)
@@ -658,7 +658,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
  drop:
        dev->stats.tx_dropped++;
-       dev_kfree_skb(skb);
+       dev_kfree_skb_any(skb);
        return NETDEV_TX_OK;
 }
 
@@ -907,6 +907,7 @@ static int handle_incoming_queue(struct net_device *dev,
 
                /* Ethernet work: Delayed to here as it peeks the header. */
                skb->protocol = eth_type_trans(skb, dev);
+               skb_reset_network_header(skb);
 
                if (checksum_setup(dev, skb)) {
                        kfree_skb(skb);
@@ -1059,13 +1060,13 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev,
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&stats->syncp);
 
                        rx_packets = stats->rx_packets;
                        tx_packets = stats->tx_packets;
                        rx_bytes = stats->rx_bytes;
                        tx_bytes = stats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
 
                tot->rx_packets += rx_packets;
                tot->tx_packets += tx_packets;
@@ -1281,16 +1282,10 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        np->rx_refill_timer.function = rx_refill_timeout;
 
        err = -ENOMEM;
-       np->stats = alloc_percpu(struct netfront_stats);
+       np->stats = netdev_alloc_pcpu_stats(struct netfront_stats);
        if (np->stats == NULL)
                goto exit;
 
-       for_each_possible_cpu(i) {
-               struct netfront_stats *xen_nf_stats;
-               xen_nf_stats = per_cpu_ptr(np->stats, i);
-               u64_stats_init(&xen_nf_stats->syncp);
-       }
-
        /* Initialise tx_skbs as a free chain containing every entry. */
        np->tx_skb_freelist = 0;
        for (i = 0; i < NET_TX_RING_SIZE; i++) {
@@ -1832,7 +1827,6 @@ static void netback_changed(struct xenbus_device *dev,
        case XenbusStateReconfiguring:
        case XenbusStateReconfigured:
        case XenbusStateUnknown:
-       case XenbusStateClosed:
                break;
 
        case XenbusStateInitWait:
@@ -1847,6 +1841,10 @@ static void netback_changed(struct xenbus_device *dev,
                netdev_notify_peers(netdev);
                break;
 
+       case XenbusStateClosed:
+               if (dev->state == XenbusStateClosed)
+                       break;
+               /* Missed the backend's CLOSING state -- fallthrough */
        case XenbusStateClosing:
                xenbus_frontend_closed(dev);
                break;
index d3dd41c840f1cd8d6784e4a61382cb3e4987ad1a..1a54f1ffaadb65d6a2d1d0735eea6e8eefbf09da 100644 (file)
@@ -99,11 +99,12 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr)
 static int of_bus_pci_match(struct device_node *np)
 {
        /*
+        * "pciex" is PCI Express
         * "vci" is for the /chaos bridge on 1st-gen PCI powermacs
         * "ht" is hypertransport
         */
-       return !strcmp(np->type, "pci") || !strcmp(np->type, "vci") ||
-               !strcmp(np->type, "ht");
+       return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex") ||
+               !strcmp(np->type, "vci") || !strcmp(np->type, "ht");
 }
 
 static void of_bus_pci_count_cells(struct device_node *np,
index ff85450d568399b1dec3fe6bf892c974ca28bedd..89e888a78899e2b61281f7007406e5f937cc28a0 100644 (file)
@@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
 }
 EXPORT_SYMBOL(of_get_cpu_node);
 
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
+/**
+ * __of_device_is_compatible() - Check if the node matches given constraints
+ * @device: pointer to node
+ * @compat: required compatible string, NULL or "" for any match
+ * @type: required device_type value, NULL or "" for any match
+ * @name: required node name, NULL or "" for any match
+ *
+ * Checks if the given @compat, @type and @name strings match the
+ * properties of the given @device. A constraints can be skipped by
+ * passing NULL or an empty string as the constraint.
+ *
+ * Returns 0 for no match, and a positive integer on match. The return
+ * value is a relative score with larger values indicating better
+ * matches. The score is weighted for the most specific compatible value
+ * to get the highest score. Matching type is next, followed by matching
+ * name. Practically speaking, this results in the following priority
+ * order for matches:
+ *
+ * 1. specific compatible && type && name
+ * 2. specific compatible && type
+ * 3. specific compatible && name
+ * 4. specific compatible
+ * 5. general compatible && type && name
+ * 6. general compatible && type
+ * 7. general compatible && name
+ * 8. general compatible
+ * 9. type && name
+ * 10. type
+ * 11. name
  */
 static int __of_device_is_compatible(const struct device_node *device,
-                                    const char *compat)
+                                    const char *compat, const char *type, const char *name)
 {
-       const char* cp;
-       int cplen, l;
+       struct property *prop;
+       const char *cp;
+       int index = 0, score = 0;
+
+       /* Compatible match has highest priority */
+       if (compat && compat[0]) {
+               prop = __of_find_property(device, "compatible", NULL);
+               for (cp = of_prop_next_string(prop, NULL); cp;
+                    cp = of_prop_next_string(prop, cp), index++) {
+                       if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
+                               score = INT_MAX/2 - (index << 2);
+                               break;
+                       }
+               }
+               if (!score)
+                       return 0;
+       }
 
-       cp = __of_get_property(device, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               l = strlen(cp) + 1;
-               cp += l;
-               cplen -= l;
+       /* Matching type is better than matching name */
+       if (type && type[0]) {
+               if (!device->type || of_node_cmp(type, device->type))
+                       return 0;
+               score += 2;
        }
 
-       return 0;
+       /* Matching name is a bit better than not */
+       if (name && name[0]) {
+               if (!device->name || of_node_cmp(name, device->name))
+                       return 0;
+               score++;
+       }
+
+       return score;
 }
 
 /** Checks if the given "compat" string matches one of the strings in
@@ -375,7 +420,7 @@ int of_device_is_compatible(const struct device_node *device,
        int res;
 
        raw_spin_lock_irqsave(&devtree_lock, flags);
-       res = __of_device_is_compatible(device, compat);
+       res = __of_device_is_compatible(device, compat, NULL, NULL);
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return res;
 }
@@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
        raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext) {
-               if (type
-                   && !(np->type && (of_node_cmp(np->type, type) == 0)))
-                       continue;
-               if (__of_device_is_compatible(np, compatible) &&
+               if (__of_device_is_compatible(np, compatible, type, NULL) &&
                    of_node_get(np))
                        break;
        }
@@ -734,43 +776,22 @@ static
 const struct of_device_id *__of_match_node(const struct of_device_id *matches,
                                           const struct device_node *node)
 {
-       const char *cp;
-       int cplen, l;
+       const struct of_device_id *best_match = NULL;
+       int score, best_score = 0;
 
        if (!matches)
                return NULL;
 
-       cp = __of_get_property(node, "compatible", &cplen);
-       do {
-               const struct of_device_id *m = matches;
-
-               /* Check against matches with current compatible string */
-               while (m->name[0] || m->type[0] || m->compatible[0]) {
-                       int match = 1;
-                       if (m->name[0])
-                               match &= node->name
-                                       && !strcmp(m->name, node->name);
-                       if (m->type[0])
-                               match &= node->type
-                                       && !strcmp(m->type, node->type);
-                       if (m->compatible[0])
-                               match &= cp
-                                       && !of_compat_cmp(m->compatible, cp,
-                                                       strlen(m->compatible));
-                       if (match)
-                               return m;
-                       m++;
-               }
-
-               /* Get node's next compatible string */ 
-               if (cp) {
-                       l = strlen(cp) + 1;
-                       cp += l;
-                       cplen -= l;
+       for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
+               score = __of_device_is_compatible(node, matches->compatible,
+                                                 matches->type, matches->name);
+               if (score > best_score) {
+                       best_match = matches;
+                       best_score = score;
                }
-       } while (cp && (cplen > 0));
+       }
 
-       return NULL;
+       return best_match;
 }
 
 /**
@@ -778,10 +799,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
  *     @matches:       array of of device match structures to search in
  *     @node:          the of device structure to match against
  *
- *     Low level utility function used by device matching. Matching order
- *     is to compare each of the node's compatibles with all given matches
- *     first. This implies node's compatible is sorted from specific to
- *     generic while matches can be in any order.
+ *     Low level utility function used by device matching.
  */
 const struct of_device_id *of_match_node(const struct of_device_id *matches,
                                         const struct device_node *node)
index 875b7b6f0d2a48bfdac42f40d6927cf59e6cf552..9a95831bd065c2ba1c5af83f6a73927a3b9d8181 100644 (file)
@@ -24,7 +24,11 @@ MODULE_LICENSE("GPL");
 
 static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed)
 {
-       phydev->supported |= PHY_DEFAULT_FEATURES;
+       /* The default values for phydev->supported are provided by the PHY
+        * driver "features" member, we want to reset to sane defaults fist
+        * before supporting higher speeds.
+        */
+       phydev->supported &= PHY_DEFAULT_FEATURES;
 
        switch (max_speed) {
        default:
@@ -39,27 +43,50 @@ static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed)
        }
 }
 
+/* Extract the clause 22 phy ID from the compatible string of the form
+ * ethernet-phy-idAAAA.BBBB */
+static int of_get_phy_id(struct device_node *device, u32 *phy_id)
+{
+       struct property *prop;
+       const char *cp;
+       unsigned int upper, lower;
+
+       of_property_for_each_string(device, "compatible", prop, cp) {
+               if (sscanf(cp, "ethernet-phy-id%4x.%4x", &upper, &lower) == 2) {
+                       *phy_id = ((upper & 0xFFFF) << 16) | (lower & 0xFFFF);
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
 static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *child,
                                   u32 addr)
 {
        struct phy_device *phy;
        bool is_c45;
-       int rc, prev_irq;
+       int rc;
        u32 max_speed = 0;
+       u32 phy_id;
 
        is_c45 = of_device_is_compatible(child,
                                         "ethernet-phy-ieee802.3-c45");
 
-       phy = get_phy_device(mdio, addr, is_c45);
+       if (!is_c45 && !of_get_phy_id(child, &phy_id))
+               phy = phy_device_create(mdio, addr, phy_id, 0, NULL);
+       else
+               phy = get_phy_device(mdio, addr, is_c45);
        if (!phy || IS_ERR(phy))
                return 1;
 
-       if (mdio->irq) {
-               prev_irq = mdio->irq[addr];
-               mdio->irq[addr] =
-                       irq_of_parse_and_map(child, 0);
-               if (!mdio->irq[addr])
-                       mdio->irq[addr] = prev_irq;
+       rc = irq_of_parse_and_map(child, 0);
+       if (rc > 0) {
+               phy->irq = rc;
+               if (mdio->irq)
+                       mdio->irq[addr] = rc;
+       } else {
+               if (mdio->irq)
+                       phy->irq = mdio->irq[addr];
        }
 
        /* Associate the OF node with the device structure so it
index a208a457558c758a47ac7c0a2c43ca6e6426c85c..84215c1929c400d53af1ce0c1938fedd87d045b5 100644 (file)
 #include <linux/phy.h>
 #include <linux/export.h>
 
-/**
- * It maps 'enum phy_interface_t' found in include/linux/phy.h
- * into the device tree binding of 'phy-mode', so that Ethernet
- * device driver can get phy interface from device tree.
- */
-static const char *phy_modes[] = {
-       [PHY_INTERFACE_MODE_NA]         = "",
-       [PHY_INTERFACE_MODE_MII]        = "mii",
-       [PHY_INTERFACE_MODE_GMII]       = "gmii",
-       [PHY_INTERFACE_MODE_SGMII]      = "sgmii",
-       [PHY_INTERFACE_MODE_TBI]        = "tbi",
-       [PHY_INTERFACE_MODE_REVMII]     = "rev-mii",
-       [PHY_INTERFACE_MODE_RMII]       = "rmii",
-       [PHY_INTERFACE_MODE_RGMII]      = "rgmii",
-       [PHY_INTERFACE_MODE_RGMII_ID]   = "rgmii-id",
-       [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid",
-       [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid",
-       [PHY_INTERFACE_MODE_RTBI]       = "rtbi",
-       [PHY_INTERFACE_MODE_SMII]       = "smii",
-       [PHY_INTERFACE_MODE_XGMII]      = "xgmii",
-};
-
 /**
  * of_get_phy_mode - Get phy mode for given device_node
  * @np:        Pointer to the given device_node
@@ -49,8 +27,8 @@ int of_get_phy_mode(struct device_node *np)
        if (err < 0)
                return err;
 
-       for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
-               if (!strcasecmp(pm, phy_modes[i]))
+       for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
+               if (!strcasecmp(pm, phy_modes(i)))
                        return i;
 
        return -ENODEV;
index e21012bde639cde305a8c14aab011fad020a7da2..6643d19209857dae4f6d2d1f9a3033280e2cc25e 100644 (file)
@@ -300,6 +300,72 @@ static void __init of_selftest_parse_interrupts_extended(void)
        of_node_put(np);
 }
 
+static struct of_device_id match_node_table[] = {
+       { .data = "A", .name = "name0", }, /* Name alone is lowest priority */
+       { .data = "B", .type = "type1", }, /* followed by type alone */
+
+       { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */
+       { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */
+       { .data = "Cc", .name = "name2", .type = "type2", },
+
+       { .data = "E", .compatible = "compat3" },
+       { .data = "G", .compatible = "compat2", },
+       { .data = "H", .compatible = "compat2", .name = "name5", },
+       { .data = "I", .compatible = "compat2", .type = "type1", },
+       { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", },
+       { .data = "K", .compatible = "compat2", .name = "name9", },
+       {}
+};
+
+static struct {
+       const char *path;
+       const char *data;
+} match_node_tests[] = {
+       { .path = "/testcase-data/match-node/name0", .data = "A", },
+       { .path = "/testcase-data/match-node/name1", .data = "B", },
+       { .path = "/testcase-data/match-node/a/name2", .data = "Ca", },
+       { .path = "/testcase-data/match-node/b/name2", .data = "Cb", },
+       { .path = "/testcase-data/match-node/c/name2", .data = "Cc", },
+       { .path = "/testcase-data/match-node/name3", .data = "E", },
+       { .path = "/testcase-data/match-node/name4", .data = "G", },
+       { .path = "/testcase-data/match-node/name5", .data = "H", },
+       { .path = "/testcase-data/match-node/name6", .data = "G", },
+       { .path = "/testcase-data/match-node/name7", .data = "I", },
+       { .path = "/testcase-data/match-node/name8", .data = "J", },
+       { .path = "/testcase-data/match-node/name9", .data = "K", },
+};
+
+static void __init of_selftest_match_node(void)
+{
+       struct device_node *np;
+       const struct of_device_id *match;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) {
+               np = of_find_node_by_path(match_node_tests[i].path);
+               if (!np) {
+                       selftest(0, "missing testcase node %s\n",
+                               match_node_tests[i].path);
+                       continue;
+               }
+
+               match = of_match_node(match_node_table, np);
+               if (!match) {
+                       selftest(0, "%s didn't match anything\n",
+                               match_node_tests[i].path);
+                       continue;
+               }
+
+               if (strcmp(match->data, match_node_tests[i].data) != 0) {
+                       selftest(0, "%s got wrong match. expected %s, got %s\n",
+                               match_node_tests[i].path, match_node_tests[i].data,
+                               (const char *)match->data);
+                       continue;
+               }
+               selftest(1, "passed");
+       }
+}
+
 static int __init of_selftest(void)
 {
        struct device_node *np;
@@ -316,6 +382,7 @@ static int __init of_selftest(void)
        of_selftest_property_match_string();
        of_selftest_parse_interrupts();
        of_selftest_parse_interrupts_extended();
+       of_selftest_match_node();
        pr_info("end of selftest - %i passed, %i failed\n",
                selftest_results.passed, selftest_results.failed);
        return 0;
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
new file mode 100644 (file)
index 0000000..3a5b75a
--- /dev/null
@@ -0,0 +1,3 @@
+#include "tests-phandle.dtsi"
+#include "tests-interrupts.dtsi"
+#include "tests-match.dtsi"
diff --git a/drivers/of/testcase-data/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi
new file mode 100644 (file)
index 0000000..c843720
--- /dev/null
@@ -0,0 +1,58 @@
+
+/ {
+       testcase-data {
+               interrupts {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       test_intc0: intc0 {
+                               interrupt-controller;
+                               #interrupt-cells = <1>;
+                       };
+
+                       test_intc1: intc1 {
+                               interrupt-controller;
+                               #interrupt-cells = <3>;
+                       };
+
+                       test_intc2: intc2 {
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       test_intmap0: intmap0 {
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               interrupt-map = <1 &test_intc0 9>,
+                                               <2 &test_intc1 10 11 12>,
+                                               <3 &test_intc2 13 14>,
+                                               <4 &test_intc2 15 16>;
+                       };
+
+                       test_intmap1: intmap1 {
+                               #interrupt-cells = <2>;
+                               interrupt-map = <0x5000 1 2 &test_intc0 15>;
+                       };
+
+                       interrupts0 {
+                               interrupt-parent = <&test_intc0>;
+                               interrupts = <1>, <2>, <3>, <4>;
+                       };
+
+                       interrupts1 {
+                               interrupt-parent = <&test_intmap0>;
+                               interrupts = <1>, <2>, <3>, <4>;
+                       };
+
+                       interrupts-extended0 {
+                               reg = <0x5000 0x100>;
+                               interrupts-extended = <&test_intc0 1>,
+                                                     <&test_intc1 2 3 4>,
+                                                     <&test_intc2 5 6>,
+                                                     <&test_intmap0 1>,
+                                                     <&test_intmap0 2>,
+                                                     <&test_intmap0 3>,
+                                                     <&test_intmap1 1 2>;
+                       };
+               };
+       };
+};
diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/testcase-data/tests-match.dtsi
new file mode 100644 (file)
index 0000000..c9e5411
--- /dev/null
@@ -0,0 +1,19 @@
+
+/ {
+       testcase-data {
+               match-node {
+                       name0 { };
+                       name1 { device_type = "type1"; };
+                       a { name2 { device_type = "type1"; }; };
+                       b { name2 { }; };
+                       c { name2 { device_type = "type2"; }; };
+                       name3 { compatible = "compat3"; };
+                       name4 { compatible = "compat2", "compat3"; };
+                       name5 { compatible = "compat2", "compat3"; };
+                       name6 { compatible = "compat1", "compat2", "compat3"; };
+                       name7 { compatible = "compat2"; device_type = "type1"; };
+                       name8 { compatible = "compat2"; device_type = "type1"; };
+                       name9 { compatible = "compat2"; };
+               };
+       };
+};
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi
new file mode 100644 (file)
index 0000000..0007d3c
--- /dev/null
@@ -0,0 +1,39 @@
+
+/ {
+       testcase-data {
+               phandle-tests {
+                       provider0: provider0 {
+                               #phandle-cells = <0>;
+                       };
+
+                       provider1: provider1 {
+                               #phandle-cells = <1>;
+                       };
+
+                       provider2: provider2 {
+                               #phandle-cells = <2>;
+                       };
+
+                       provider3: provider3 {
+                               #phandle-cells = <3>;
+                       };
+
+                       consumer-a {
+                               phandle-list =  <&provider1 1>,
+                                               <&provider2 2 0>,
+                                               <0>,
+                                               <&provider3 4 4 3>,
+                                               <&provider2 5 100>,
+                                               <&provider0>,
+                                               <&provider1 7>;
+                               phandle-list-names = "first", "second", "third";
+
+                               phandle-list-bad-phandle = <12345678 0 0>;
+                               phandle-list-bad-args = <&provider2 1 0>,
+                                                       <&provider3 0>;
+                               empty-property;
+                               unterminated-string = [40 41 42 43];
+                       };
+               };
+       };
+};
index 00660cc502c5e0df1da9946281ba2b6fa6d08afc..38901665c77086a20a6bd1cd087f24971c0d172b 100644 (file)
@@ -162,8 +162,6 @@ static int pci_bus_alloc_from_region(struct pci_bus *bus, struct resource *res,
 
                avail = *r;
                pci_clip_resource_to_region(bus, &avail, region);
-               if (!resource_size(&avail))
-                       continue;
 
                /*
                 * "min" is typically PCIBIOS_MIN_IO or PCIBIOS_MIN_MEM to
index 13478ecd411306115b666a9e344754966ce3012b..0e79665afd445ebb8e6198a274960978c58c619e 100644 (file)
 #define PCIE_DEBUG_CTRL         0x1a60
 #define  PCIE_DEBUG_SOFT_RESET         BIT(20)
 
-/*
- * This product ID is registered by Marvell, and used when the Marvell
- * SoC is not the root complex, but an endpoint on the PCIe bus. It is
- * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI
- * bridge.
- */
-#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846
-
 /* PCI configuration space of a PCI-to-PCI bridge */
 struct mvebu_sw_pci_bridge {
        u16 vendor;
@@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
 
        bridge->class = PCI_CLASS_BRIDGE_PCI;
        bridge->vendor = PCI_VENDOR_ID_MARVELL;
-       bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID;
+       bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16;
+       bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff;
        bridge->header_type = PCI_HEADER_TYPE_BRIDGE;
        bridge->cache_line_size = 0x10;
 
index e2a783fdb98fdc6be6cb24f52a9a828ba48f2ba6..7c7a388c85ab3679732f7971552790057abec4f5 100644 (file)
@@ -730,6 +730,17 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
        return (unsigned int)sta;
 }
 
+static inline bool device_status_valid(unsigned int sta)
+{
+       /*
+        * ACPI spec says that _STA may return bit 0 clear with bit 3 set
+        * if the device is valid but does not require a device driver to be
+        * loaded (Section 6.3.7 of ACPI 5.0A).
+        */
+       unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING;
+       return (sta & mask) == mask;
+}
+
 /**
  * trim_stale_devices - remove PCI devices that are not responding.
  * @dev: PCI device to start walking the hierarchy from.
@@ -745,7 +756,7 @@ static void trim_stale_devices(struct pci_dev *dev)
                unsigned long long sta;
 
                status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-               alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL)
+               alive = (ACPI_SUCCESS(status) && device_status_valid(sta))
                        || acpiphp_no_hotplug(handle);
        }
        if (!alive) {
@@ -792,7 +803,7 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
                mutex_lock(&slot->crit_sect);
                if (slot_no_hotplug(slot)) {
                        ; /* do nothing */
-               } else if (get_slot_status(slot) == ACPI_STA_ALL) {
+               } else if (device_status_valid(get_slot_status(slot))) {
                        /* remove stale devices if any */
                        list_for_each_entry_safe_reverse(dev, tmp,
                                                         &bus->devices, bus_list)
index 7a0fec6ce5717baac5ef564c743d129cbc03a892..955ab7990c5bd7045f2bf896e6d4c65989176089 100644 (file)
@@ -545,9 +545,15 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
                return -ENOMEM;
        list_for_each_entry(entry, &pdev->msi_list, list) {
                char *name = kmalloc(20, GFP_KERNEL);
+               if (!name)
+                       goto error_attrs;
+
                msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL);
-               if (!msi_dev_attr)
+               if (!msi_dev_attr) {
+                       kfree(name);
                        goto error_attrs;
+               }
+
                sprintf(name, "%d", entry->irq);
                sysfs_attr_init(&msi_dev_attr->attr);
                msi_dev_attr->attr.name = name;
@@ -589,6 +595,7 @@ error_attrs:
                ++count;
                msi_attr = msi_attrs[count];
        }
+       kfree(msi_attrs);
        return ret;
 }
 
@@ -959,7 +966,6 @@ EXPORT_SYMBOL(pci_disable_msi);
 /**
  * pci_msix_vec_count - return the number of device's MSI-X table entries
  * @dev: pointer to the pci_dev data structure of MSI-X device function
-
  * This function returns the number of device's MSI-X table entries and
  * therefore the number of MSI-X vectors device is capable of sending.
  * It returns a negative errno if the device is not capable of sending MSI-X
index 1febe90831b442303b7414faec770d4850ca53ed..fdbc294821e6468d55ca7d5fd68162b407607e97 100644 (file)
@@ -1181,6 +1181,8 @@ EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
 static int do_pci_enable_device(struct pci_dev *dev, int bars)
 {
        int err;
+       u16 cmd;
+       u8 pin;
 
        err = pci_set_power_state(dev, PCI_D0);
        if (err < 0 && err != -EIO)
@@ -1190,6 +1192,17 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
                return err;
        pci_fixup_device(pci_fixup_enable, dev);
 
+       if (dev->msi_enabled || dev->msix_enabled)
+               return 0;
+
+       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+       if (pin) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (cmd & PCI_COMMAND_INTX_DISABLE)
+                       pci_write_config_word(dev, PCI_COMMAND,
+                                             cmd & ~PCI_COMMAND_INTX_DISABLE);
+       }
+
        return 0;
 }
 
index afa2354f6600e72d904ea907ee92f775010ae8a9..c7a551c2d5f1b4d39b982d85222537ec3fbfb804 100644 (file)
@@ -5,7 +5,7 @@
 menu "PHY Subsystem"
 
 config GENERIC_PHY
-       tristate "PHY Core"
+       bool "PHY Core"
        help
          Generic PHY support.
 
@@ -61,6 +61,7 @@ config PHY_EXYNOS_DP_VIDEO
 config BCM_KONA_USB2_PHY
        tristate "Broadcom Kona USB2 PHY Driver"
        depends on GENERIC_PHY
+       depends on HAS_IOMEM
        help
          Enable this to support the Broadcom Kona USB 2.0 PHY.
 
index 645c867c12573e554d43e3700155db5469841caa..6c738376daff5110a791c3c3f6492ab818971165 100644 (file)
@@ -162,6 +162,9 @@ int phy_init(struct phy *phy)
 {
        int ret;
 
+       if (!phy)
+               return 0;
+
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
@@ -173,6 +176,8 @@ int phy_init(struct phy *phy)
                        dev_err(&phy->dev, "phy init failed --> %d\n", ret);
                        goto out;
                }
+       } else {
+               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->init_count;
 
@@ -187,6 +192,9 @@ int phy_exit(struct phy *phy)
 {
        int ret;
 
+       if (!phy)
+               return 0;
+
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
@@ -212,6 +220,9 @@ int phy_power_on(struct phy *phy)
 {
        int ret;
 
+       if (!phy)
+               return 0;
+
        ret = phy_pm_runtime_get_sync(phy);
        if (ret < 0 && ret != -ENOTSUPP)
                return ret;
@@ -223,6 +234,8 @@ int phy_power_on(struct phy *phy)
                        dev_err(&phy->dev, "phy poweron failed --> %d\n", ret);
                        goto out;
                }
+       } else {
+               ret = 0; /* Override possible ret == -ENOTSUPP */
        }
        ++phy->power_count;
        mutex_unlock(&phy->mutex);
@@ -240,6 +253,9 @@ int phy_power_off(struct phy *phy)
 {
        int ret;
 
+       if (!phy)
+               return 0;
+
        mutex_lock(&phy->mutex);
        if (phy->power_count == 1 && phy->ops->power_off) {
                ret =  phy->ops->power_off(phy);
@@ -308,7 +324,7 @@ err0:
  */
 void phy_put(struct phy *phy)
 {
-       if (IS_ERR(phy))
+       if (!phy || IS_ERR(phy))
                return;
 
        module_put(phy->ops->owner);
@@ -328,6 +344,9 @@ void devm_phy_put(struct device *dev, struct phy *phy)
 {
        int r;
 
+       if (!phy)
+               return;
+
        r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy);
        dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n");
 }
@@ -389,17 +408,11 @@ struct phy *phy_get(struct device *dev, const char *string)
                index = of_property_match_string(dev->of_node, "phy-names",
                        string);
                phy = of_phy_get(dev, index);
-               if (IS_ERR(phy)) {
-                       dev_err(dev, "unable to find phy\n");
-                       return phy;
-               }
        } else {
                phy = phy_lookup(dev, string);
-               if (IS_ERR(phy)) {
-                       dev_err(dev, "unable to find phy\n");
-                       return phy;
-               }
        }
+       if (IS_ERR(phy))
+               return phy;
 
        if (!try_module_get(phy->ops->owner))
                return ERR_PTR(-EPROBE_DEFER);
@@ -410,6 +423,27 @@ struct phy *phy_get(struct device *dev, const char *string)
 }
 EXPORT_SYMBOL_GPL(phy_get);
 
+/**
+ * phy_optional_get() - lookup and obtain a reference to an optional phy.
+ * @dev: device that requests this phy
+ * @string: the phy name as given in the dt data or the name of the controller
+ * port for non-dt case
+ *
+ * Returns the phy driver, after getting a refcount to it; or
+ * NULL if there is no such phy.  The caller is responsible for
+ * calling phy_put() to release that count.
+ */
+struct phy *phy_optional_get(struct device *dev, const char *string)
+{
+       struct phy *phy = phy_get(dev, string);
+
+       if (PTR_ERR(phy) == -ENODEV)
+               phy = NULL;
+
+       return phy;
+}
+EXPORT_SYMBOL_GPL(phy_optional_get);
+
 /**
  * devm_phy_get() - lookup and obtain a reference to a phy.
  * @dev: device that requests this phy
@@ -440,6 +474,30 @@ struct phy *devm_phy_get(struct device *dev, const char *string)
 }
 EXPORT_SYMBOL_GPL(devm_phy_get);
 
+/**
+ * devm_phy_optional_get() - lookup and obtain a reference to an optional phy.
+ * @dev: device that requests this phy
+ * @string: the phy name as given in the dt data or phy device name
+ * for non-dt case
+ *
+ * Gets the phy using phy_get(), and associates a device with it using
+ * devres. On driver detach, release function is invoked on the devres
+ * data, then, devres data is freed. This differs to devm_phy_get() in
+ * that if the phy does not exist, it is not considered an error and
+ * -ENODEV will not be returned. Instead the NULL phy is returned,
+ * which can be passed to all other phy consumer calls.
+ */
+struct phy *devm_phy_optional_get(struct device *dev, const char *string)
+{
+       struct phy *phy = devm_phy_get(dev, string);
+
+       if (PTR_ERR(phy) == -ENODEV)
+               phy = NULL;
+
+       return phy;
+}
+EXPORT_SYMBOL_GPL(devm_phy_optional_get);
+
 /**
  * phy_create() - create a new phy
  * @dev: device that is creating the new phy
index 1dbe6ce7b2ce795e0a81ec3a632a8b6d6927f2bc..0786fef842e7fd878507d4342074db65b942c47b 100644 (file)
@@ -76,10 +76,6 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
        if (IS_ERR(state->regs))
                return PTR_ERR(state->regs);
 
-       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL);
        if (IS_ERR(phy)) {
                dev_err(dev, "failed to create Display Port PHY\n");
@@ -87,6 +83,10 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
        }
        phy_set_drvdata(phy, state);
 
+       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        return 0;
 }
 
index 0c5efab11af18a5b2b7367014747e0b34984b585..7f139326a6424e8b38d5fdd9049f26d85e679e6c 100644 (file)
@@ -134,11 +134,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
        dev_set_drvdata(dev, state);
        spin_lock_init(&state->slock);
 
-       phy_provider = devm_of_phy_provider_register(dev,
-                                       exynos_mipi_video_phy_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
                struct phy *phy = devm_phy_create(dev,
                                        &exynos_mipi_video_phy_ops, NULL);
@@ -152,6 +147,11 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
                phy_set_drvdata(phy, &state->phys[i]);
        }
 
+       phy_provider = devm_of_phy_provider_register(dev,
+                                       exynos_mipi_video_phy_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        return 0;
 }
 
index d43786f6243742ed378fb1b7d3c6756fd111381d..d70ecd6a1b3f51e60077559159912e2564e6b1a1 100644 (file)
@@ -99,17 +99,17 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
        if (IS_ERR(priv->clk))
                return PTR_ERR(priv->clk);
 
-       phy_provider = devm_of_phy_provider_register(&pdev->dev,
-                                                    of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL);
        if (IS_ERR(phy))
                return PTR_ERR(phy);
 
        phy_set_drvdata(phy, priv);
 
+       phy_provider = devm_of_phy_provider_register(&pdev->dev,
+                                                    of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        /* The boot loader may of left it on. Turn it off. */
        phy_mvebu_sata_power_off(phy);
 
index bfc5c337f99a8178278d9aa8f0b9b7be74f41889..7699752fba11bfbfa8acff589d794262d2882cc4 100644 (file)
@@ -177,11 +177,6 @@ static int omap_usb2_probe(struct platform_device *pdev)
        phy->phy.otg            = otg;
        phy->phy.type           = USB_PHY_TYPE_USB2;
 
-       phy_provider = devm_of_phy_provider_register(phy->dev,
-                       of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        control_node = of_parse_phandle(node, "ctrl-module", 0);
        if (!control_node) {
                dev_err(&pdev->dev, "Failed to get control device phandle\n");
@@ -214,6 +209,11 @@ static int omap_usb2_probe(struct platform_device *pdev)
 
        phy_set_drvdata(generic_phy, phy);
 
+       phy_provider = devm_of_phy_provider_register(phy->dev,
+                       of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
        if (IS_ERR(phy->wkupclk)) {
                dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
index daf65e68aaab53c663847e05d2dcf1fbdb035544..c3ace1db8136eedef379691bc6fa532b4ff5d67c 100644 (file)
@@ -695,11 +695,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
        otg->set_host           = twl4030_set_host;
        otg->set_peripheral     = twl4030_set_peripheral;
 
-       phy_provider = devm_of_phy_provider_register(twl->dev,
-               of_phy_simple_xlate);
-       if (IS_ERR(phy_provider))
-               return PTR_ERR(phy_provider);
-
        phy = devm_phy_create(twl->dev, &ops, init_data);
        if (IS_ERR(phy)) {
                dev_dbg(&pdev->dev, "Failed to create PHY\n");
@@ -708,6 +703,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
 
        phy_set_drvdata(phy, twl);
 
+       phy_provider = devm_of_phy_provider_register(twl->dev,
+               of_phy_simple_xlate);
+       if (IS_ERR(phy_provider))
+               return PTR_ERR(phy_provider);
+
        /* init spinlock for workqueue */
        spin_lock_init(&twl->lock);
 
index be361b7cd30f240e4b1a78abbb3acd253620b035..1e4e69384baaed11ae859ce6a784eef0d8fa0f9c 100644 (file)
@@ -217,7 +217,7 @@ config PINCTRL_IMX28
        select PINCTRL_MXS
 
 config PINCTRL_MSM
-       tristate
+       bool
        select PINMUX
        select PINCONF
        select GENERIC_PINCONF
index 4669c53f99b0a4fc8e30ab4678263be292f014fd..eb2500212147bdc72177f3e67c31ed23f7e6ea6a 100644 (file)
@@ -1435,7 +1435,7 @@ int __init capri_pinctrl_probe(struct platform_device *pdev)
 }
 
 static struct of_device_id capri_pinctrl_of_match[] = {
-       { .compatible = "brcm,capri-pinctrl", },
+       { .compatible = "brcm,bcm11351-pinctrl", },
        { },
 };
 
index 9ccf681dad2f4993cdf3ef20a9099a17ae62dcb9..f9fabe9bf47d433b9152cd438e259e568b3b9ff5 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
@@ -584,7 +585,7 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
        spin_lock_irqsave(&pctl->lock, flags);
 
        regval = readl(pctl->membase + reg);
-       regval &= ~IRQ_CFG_IRQ_MASK;
+       regval &= ~(IRQ_CFG_IRQ_MASK << index);
        writel(regval | (mode << index), pctl->membase + reg);
 
        spin_unlock_irqrestore(&pctl->lock, flags);
@@ -665,6 +666,7 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
 
 static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
 {
+       struct irq_chip *chip = irq_get_chip(irq);
        struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
        const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
 
@@ -674,10 +676,12 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
        if (reg) {
                int irqoffset;
 
+               chained_irq_enter(chip, desc);
                for_each_set_bit(irqoffset, &reg, SUNXI_IRQ_NUMBER) {
                        int pin_irq = irq_find_mapping(pctl->domain, irqoffset);
                        generic_handle_irq(pin_irq);
                }
+               chained_irq_exit(chip, desc);
        }
 }
 
index 01c494f8a14f0119493d783624b86831549ccdb0..552b0e97077a858b0c1aeda6d9f1a83e4803ae35 100644 (file)
@@ -511,7 +511,7 @@ static inline u32 sunxi_pull_offset(u16 pin)
 
 static inline u32 sunxi_irq_cfg_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
+       u8 reg = irq / IRQ_CFG_IRQ_PER_REG * 0x04;
        return reg + IRQ_CFG_REG;
 }
 
@@ -523,7 +523,7 @@ static inline u32 sunxi_irq_cfg_offset(u16 irq)
 
 static inline u32 sunxi_irq_ctrl_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
+       u8 reg = irq / IRQ_CTRL_IRQ_PER_REG * 0x04;
        return reg + IRQ_CTRL_REG;
 }
 
@@ -535,7 +535,7 @@ static inline u32 sunxi_irq_ctrl_offset(u16 irq)
 
 static inline u32 sunxi_irq_status_reg(u16 irq)
 {
-       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
+       u8 reg = irq / IRQ_STATUS_IRQ_PER_REG * 0x04;
        return reg + IRQ_STATUS_REG;
 }
 
index 77d103fe39d90c8ad0bb82485ec1896dd1b5889a..567d6918d50b226b7841c84a98b2343ad552a03e 100644 (file)
@@ -89,7 +89,8 @@ enum {
 
        /* GPSR6 */
        FN_IP13_10, FN_IP13_11, FN_IP13_12, FN_IP13_13, FN_IP13_14,
-       FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19, FN_IP13_22, FN_IP13_24_23,
+       FN_IP13_15, FN_IP13_18_16, FN_IP13_21_19,
+       FN_IP13_22, FN_IP13_24_23, FN_SD1_CLK,
        FN_IP13_25, FN_IP13_26, FN_IP13_27, FN_IP13_30_28, FN_IP14_1_0,
        FN_IP14_2, FN_IP14_3, FN_IP14_4, FN_IP14_5, FN_IP14_6, FN_IP14_7,
        FN_IP14_10_8, FN_IP14_13_11, FN_IP14_16_14, FN_IP14_19_17,
@@ -788,6 +789,7 @@ static const u16 pinmux_data[] = {
        PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
        PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
        PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
+       PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
 
        /* IPSR0 */
        PINMUX_IPSR_DATA(IP0_0, D0),
@@ -3825,7 +3827,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
                GP_6_11_FN, FN_IP13_25,
                GP_6_10_FN, FN_IP13_24_23,
                GP_6_9_FN, FN_IP13_22,
-               0, 0,
+               GP_6_8_FN, FN_SD1_CLK,
                GP_6_7_FN, FN_IP13_21_19,
                GP_6_6_FN, FN_IP13_18_16,
                GP_6_5_FN, FN_IP13_15,
index a0d6152701cdf3d3aa5a64bbb435f93526d0a324..617a4916b50fc1d8fec129e001f717c00de13880 100644 (file)
@@ -598,7 +598,7 @@ static unsigned int sirfsoc_gpio_irq_startup(struct irq_data *d)
 {
        struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 
-       if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq))
+       if (gpio_lock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE))
                dev_err(bank->chip.gc.dev,
                        "unable to lock HW IRQ %lu for IRQ\n",
                        d->hwirq);
@@ -611,7 +611,7 @@ static void sirfsoc_gpio_irq_shutdown(struct irq_data *d)
        struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
 
        sirfsoc_gpio_irq_mask(d);
-       gpio_unlock_as_irq(&bank->chip.gc, d->hwirq);
+       gpio_unlock_as_irq(&bank->chip.gc, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
 }
 
 static struct irq_chip sirfsoc_irq_chip = {
index 167f3d00c916d2e30a63dcc31d260a45d1e5cada..66977ebf13b30cba09b6bb1b7c06eeb07e2e5bd0 100644 (file)
@@ -183,9 +183,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        struct resource r = {0};
        int i, flags;
 
-       if (acpi_dev_resource_memory(res, &r)
-           || acpi_dev_resource_io(res, &r)
-           || acpi_dev_resource_address_space(res, &r)
+       if (acpi_dev_resource_address_space(res, &r)
            || acpi_dev_resource_ext_address_space(res, &r)) {
                pnp_add_resource(dev, &r);
                return AE_OK;
@@ -217,6 +215,17 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
        }
 
        switch (res->type) {
+       case ACPI_RESOURCE_TYPE_MEMORY24:
+       case ACPI_RESOURCE_TYPE_MEMORY32:
+       case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+               if (acpi_dev_resource_memory(res, &r))
+                       pnp_add_resource(dev, &r);
+               break;
+       case ACPI_RESOURCE_TYPE_IO:
+       case ACPI_RESOURCE_TYPE_FIXED_IO:
+               if (acpi_dev_resource_io(res, &r))
+                       pnp_add_resource(dev, &r);
+               break;
        case ACPI_RESOURCE_TYPE_DMA:
                dma = &res->data.dma;
                if (dma->channel_count > 0 && dma->channels[0] != (u8) -1)
index 563174891c90d07b7c9cc5c711588fd249695dd1..041f9b638d28c5f788ee2c828d29b853728f67b4 100644 (file)
@@ -192,7 +192,7 @@ static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV)
 
        /*
         * Voltage is measured in units of 1.22mV. The voltage is stored as
-        * a 10-bit number plus sign, in the upper bits of a 16-bit register
+        * a 12-bit number plus sign, in the upper bits of a 16-bit register
         */
        err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw);
        if (err)
index 80edb7d8cb547702df7b364f087f25aade3729d8..0b4cf9d63291d0e152197c0eeffb1eb128818dd3 100644 (file)
@@ -444,8 +444,6 @@ static int isp1704_charger_probe(struct platform_device *pdev)
                ret = PTR_ERR(isp->phy);
                goto fail0;
        }
-       if (!isp->phy)
-               goto fail0;
 
        isp->dev = &pdev->dev;
        platform_set_drvdata(pdev, isp);
index c7ff6d67f158179aa891a1d41b8a10952191f240..0fbac861080dac5cd6c4f62dc59338444205a60a 100644 (file)
@@ -148,7 +148,7 @@ static void max17040_get_online(struct i2c_client *client)
 {
        struct max17040_chip *chip = i2c_get_clientdata(client);
 
-       if (chip->pdata->battery_online)
+       if (chip->pdata && chip->pdata->battery_online)
                chip->online = chip->pdata->battery_online();
        else
                chip->online = 1;
@@ -158,7 +158,8 @@ static void max17040_get_status(struct i2c_client *client)
 {
        struct max17040_chip *chip = i2c_get_clientdata(client);
 
-       if (!chip->pdata->charger_online || !chip->pdata->charger_enable) {
+       if (!chip->pdata || !chip->pdata->charger_online
+                       || !chip->pdata->charger_enable) {
                chip->status = POWER_SUPPLY_STATUS_UNKNOWN;
                return;
        }
index 34a0c607318eb2173e4d1e44cb16aff2c889164d..419056d7887ec9f516e46699bdc0f46dfe85eeb7 100644 (file)
 
 #include "ptp_private.h"
 
+static int ptp_disable_pinfunc(struct ptp_clock_info *ops,
+                              enum ptp_pin_function func, unsigned int chan)
+{
+       struct ptp_clock_request rq;
+       int err = 0;
+
+       memset(&rq, 0, sizeof(rq));
+
+       switch (func) {
+       case PTP_PF_NONE:
+               break;
+       case PTP_PF_EXTTS:
+               rq.type = PTP_CLK_REQ_EXTTS;
+               rq.extts.index = chan;
+               err = ops->enable(ops, &rq, 0);
+               break;
+       case PTP_PF_PEROUT:
+               rq.type = PTP_CLK_REQ_PEROUT;
+               rq.perout.index = chan;
+               err = ops->enable(ops, &rq, 0);
+               break;
+       case PTP_PF_PHYSYNC:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
+                   enum ptp_pin_function func, unsigned int chan)
+{
+       struct ptp_clock_info *info = ptp->info;
+       struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin];
+       unsigned int i;
+
+       /* Check to see if any other pin previously had this function. */
+       for (i = 0; i < info->n_pins; i++) {
+               if (info->pin_config[i].func == func &&
+                   info->pin_config[i].chan == chan) {
+                       pin1 = &info->pin_config[i];
+                       break;
+               }
+       }
+       if (pin1 && i == pin)
+               return 0;
+
+       /* Check the desired function and channel. */
+       switch (func) {
+       case PTP_PF_NONE:
+               break;
+       case PTP_PF_EXTTS:
+               if (chan >= info->n_ext_ts)
+                       return -EINVAL;
+               break;
+       case PTP_PF_PEROUT:
+               if (chan >= info->n_per_out)
+                       return -EINVAL;
+               break;
+       case PTP_PF_PHYSYNC:
+               pr_err("sorry, cannot reassign the calibration pin\n");
+               return -EINVAL;
+       default:
+               return -EINVAL;
+       }
+
+       if (pin2->func == PTP_PF_PHYSYNC) {
+               pr_err("sorry, cannot reprogram the calibration pin\n");
+               return -EINVAL;
+       }
+
+       if (info->verify(info, pin, func, chan)) {
+               pr_err("driver cannot use function %u on pin %u\n", func, chan);
+               return -EOPNOTSUPP;
+       }
+
+       /* Disable whatever function was previously assigned. */
+       if (pin1) {
+               ptp_disable_pinfunc(info, func, chan);
+               pin1->func = PTP_PF_NONE;
+               pin1->chan = 0;
+       }
+       ptp_disable_pinfunc(info, pin2->func, pin2->chan);
+       pin2->func = func;
+       pin2->chan = chan;
+
+       return 0;
+}
+
 int ptp_open(struct posix_clock *pc, fmode_t fmode)
 {
        return 0;
@@ -35,12 +125,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
        struct ptp_clock_caps caps;
        struct ptp_clock_request req;
        struct ptp_sys_offset *sysoff = NULL;
+       struct ptp_pin_desc pd;
        struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
        struct ptp_clock_info *ops = ptp->info;
        struct ptp_clock_time *pct;
        struct timespec ts;
        int enable, err = 0;
-       unsigned int i;
+       unsigned int i, pin_index;
 
        switch (cmd) {
 
@@ -51,6 +142,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
                caps.n_ext_ts = ptp->info->n_ext_ts;
                caps.n_per_out = ptp->info->n_per_out;
                caps.pps = ptp->info->pps;
+               caps.n_pins = ptp->info->n_pins;
                if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
                        err = -EFAULT;
                break;
@@ -126,6 +218,40 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
                        err = -EFAULT;
                break;
 
+       case PTP_PIN_GETFUNC:
+               if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
+                       err = -EFAULT;
+                       break;
+               }
+               pin_index = pd.index;
+               if (pin_index >= ops->n_pins) {
+                       err = -EINVAL;
+                       break;
+               }
+               if (mutex_lock_interruptible(&ptp->pincfg_mux))
+                       return -ERESTARTSYS;
+               pd = ops->pin_config[pin_index];
+               mutex_unlock(&ptp->pincfg_mux);
+               if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd)))
+                       err = -EFAULT;
+               break;
+
+       case PTP_PIN_SETFUNC:
+               if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
+                       err = -EFAULT;
+                       break;
+               }
+               pin_index = pd.index;
+               if (pin_index >= ops->n_pins) {
+                       err = -EINVAL;
+                       break;
+               }
+               if (mutex_lock_interruptible(&ptp->pincfg_mux))
+                       return -ERESTARTSYS;
+               err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan);
+               mutex_unlock(&ptp->pincfg_mux);
+               break;
+
        default:
                err = -ENOTTY;
                break;
index a8319b26664312eed6ab4735fd3f437cc2186ddd..e25d2bc898e5b6e4eb7b43e6df87129a2a19781e 100644 (file)
@@ -169,6 +169,7 @@ static void delete_ptp_clock(struct posix_clock *pc)
        struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
 
        mutex_destroy(&ptp->tsevq_mux);
+       mutex_destroy(&ptp->pincfg_mux);
        ida_simple_remove(&ptp_clocks_map, ptp->index);
        kfree(ptp);
 }
@@ -203,6 +204,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
        ptp->index = index;
        spin_lock_init(&ptp->tsevq.lock);
        mutex_init(&ptp->tsevq_mux);
+       mutex_init(&ptp->pincfg_mux);
        init_waitqueue_head(&ptp->tsev_wq);
 
        /* Create a new device in our class. */
@@ -249,6 +251,7 @@ no_sysfs:
        device_destroy(ptp_class, ptp->devid);
 no_device:
        mutex_destroy(&ptp->tsevq_mux);
+       mutex_destroy(&ptp->pincfg_mux);
 no_slot:
        kfree(ptp);
 no_memory:
@@ -305,6 +308,26 @@ int ptp_clock_index(struct ptp_clock *ptp)
 }
 EXPORT_SYMBOL(ptp_clock_index);
 
+int ptp_find_pin(struct ptp_clock *ptp,
+                enum ptp_pin_function func, unsigned int chan)
+{
+       struct ptp_pin_desc *pin = NULL;
+       int i;
+
+       mutex_lock(&ptp->pincfg_mux);
+       for (i = 0; i < ptp->info->n_pins; i++) {
+               if (ptp->info->pin_config[i].func == func &&
+                   ptp->info->pin_config[i].chan == chan) {
+                       pin = &ptp->info->pin_config[i];
+                       break;
+               }
+       }
+       mutex_unlock(&ptp->pincfg_mux);
+
+       return pin ? i : -1;
+}
+EXPORT_SYMBOL(ptp_find_pin);
+
 /* module operations */
 
 static void __exit ptp_exit(void)
index 4a08727fcaf39b55f409c005863603215c9b27cb..604d340f20956bc1d0df55cc692d76d0f313df02 100644 (file)
@@ -244,6 +244,7 @@ static struct ptp_clock_info ptp_ixp_caps = {
        .name           = "IXP46X timer",
        .max_adj        = 66666655,
        .n_ext_ts       = N_EXT_TS,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = ptp_ixp_adjfreq,
        .adjtime        = ptp_ixp_adjtime,
index 71a2559278d7a0d41bf773edcf5219f35462ddb1..90a106308c4f7ee21fd12565cbc1ff429f2eebde 100644 (file)
@@ -514,6 +514,7 @@ static struct ptp_clock_info ptp_pch_caps = {
        .name           = "PCH timer",
        .max_adj        = 50000000,
        .n_ext_ts       = N_EXT_TS,
+       .n_pins         = 0,
        .pps            = 0,
        .adjfreq        = ptp_pch_adjfreq,
        .adjtime        = ptp_pch_adjtime,
index df03f2e30ad91068b0beb63d34e742eeff4f0404..9c5d41421b6510f55298b70020f33578e82e97e7 100644 (file)
@@ -48,8 +48,12 @@ struct ptp_clock {
        long dialed_frequency; /* remembers the frequency adjustment */
        struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
        struct mutex tsevq_mux; /* one process at a time reading the fifo */
+       struct mutex pincfg_mux; /* protect concurrent info->pin_config access */
        wait_queue_head_t tsev_wq;
        int defunct; /* tells readers to go away when clock is being removed */
+       struct device_attribute *pin_dev_attr;
+       struct attribute **pin_attr;
+       struct attribute_group pin_attr_group;
 };
 
 /*
@@ -69,6 +73,10 @@ static inline int queue_cnt(struct timestamp_event_queue *q)
  * see ptp_chardev.c
  */
 
+/* caller must hold pincfg_mux */
+int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin,
+                   enum ptp_pin_function func, unsigned int chan);
+
 long ptp_ioctl(struct posix_clock *pc,
               unsigned int cmd, unsigned long arg);
 
index 13ec5311746a01948e7c09dcf7c1db7bed421f47..302e626fe6b01777523c371e2760ee8f48acc68b 100644 (file)
@@ -18,6 +18,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include <linux/capability.h>
+#include <linux/slab.h>
 
 #include "ptp_private.h"
 
@@ -42,6 +43,7 @@ PTP_SHOW_INT(max_adjustment, max_adj);
 PTP_SHOW_INT(n_alarms, n_alarm);
 PTP_SHOW_INT(n_external_timestamps, n_ext_ts);
 PTP_SHOW_INT(n_periodic_outputs, n_per_out);
+PTP_SHOW_INT(n_programmable_pins, n_pins);
 PTP_SHOW_INT(pps_available, pps);
 
 static struct attribute *ptp_attrs[] = {
@@ -50,6 +52,7 @@ static struct attribute *ptp_attrs[] = {
        &dev_attr_n_alarms.attr,
        &dev_attr_n_external_timestamps.attr,
        &dev_attr_n_periodic_outputs.attr,
+       &dev_attr_n_programmable_pins.attr,
        &dev_attr_pps_available.attr,
        NULL,
 };
@@ -175,6 +178,63 @@ out:
        return err;
 }
 
+static int ptp_pin_name2index(struct ptp_clock *ptp, const char *name)
+{
+       int i;
+       for (i = 0; i < ptp->info->n_pins; i++) {
+               if (!strcmp(ptp->info->pin_config[i].name, name))
+                       return i;
+       }
+       return -1;
+}
+
+static ssize_t ptp_pin_show(struct device *dev, struct device_attribute *attr,
+                           char *page)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       unsigned int func, chan;
+       int index;
+
+       index = ptp_pin_name2index(ptp, attr->attr.name);
+       if (index < 0)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&ptp->pincfg_mux))
+               return -ERESTARTSYS;
+
+       func = ptp->info->pin_config[index].func;
+       chan = ptp->info->pin_config[index].chan;
+
+       mutex_unlock(&ptp->pincfg_mux);
+
+       return snprintf(page, PAGE_SIZE, "%u %u\n", func, chan);
+}
+
+static ssize_t ptp_pin_store(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct ptp_clock *ptp = dev_get_drvdata(dev);
+       unsigned int func, chan;
+       int cnt, err, index;
+
+       cnt = sscanf(buf, "%u %u", &func, &chan);
+       if (cnt != 2)
+               return -EINVAL;
+
+       index = ptp_pin_name2index(ptp, attr->attr.name);
+       if (index < 0)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&ptp->pincfg_mux))
+               return -ERESTARTSYS;
+       err = ptp_set_pinfunc(ptp, index, func, chan);
+       mutex_unlock(&ptp->pincfg_mux);
+       if (err)
+               return err;
+
+       return count;
+}
+
 static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
 static DEVICE_ATTR(fifo,         0444, extts_fifo_show, NULL);
 static DEVICE_ATTR(period,       0220, NULL, period_store);
@@ -195,9 +255,56 @@ int ptp_cleanup_sysfs(struct ptp_clock *ptp)
        if (info->pps)
                device_remove_file(dev, &dev_attr_pps_enable);
 
+       if (info->n_pins) {
+               sysfs_remove_group(&dev->kobj, &ptp->pin_attr_group);
+               kfree(ptp->pin_attr);
+               kfree(ptp->pin_dev_attr);
+       }
        return 0;
 }
 
+static int ptp_populate_pins(struct ptp_clock *ptp)
+{
+       struct device *dev = ptp->dev;
+       struct ptp_clock_info *info = ptp->info;
+       int err = -ENOMEM, i, n_pins = info->n_pins;
+
+       ptp->pin_dev_attr = kzalloc(n_pins * sizeof(*ptp->pin_dev_attr),
+                                   GFP_KERNEL);
+       if (!ptp->pin_dev_attr)
+               goto no_dev_attr;
+
+       ptp->pin_attr = kzalloc((1 + n_pins) * sizeof(struct attribute *),
+                               GFP_KERNEL);
+       if (!ptp->pin_attr)
+               goto no_pin_attr;
+
+       for (i = 0; i < n_pins; i++) {
+               struct device_attribute *da = &ptp->pin_dev_attr[i];
+               sysfs_attr_init(&da->attr);
+               da->attr.name = info->pin_config[i].name;
+               da->attr.mode = 0644;
+               da->show = ptp_pin_show;
+               da->store = ptp_pin_store;
+               ptp->pin_attr[i] = &da->attr;
+       }
+
+       ptp->pin_attr_group.name = "pins";
+       ptp->pin_attr_group.attrs = ptp->pin_attr;
+
+       err = sysfs_create_group(&dev->kobj, &ptp->pin_attr_group);
+       if (err)
+               goto no_group;
+       return 0;
+
+no_group:
+       kfree(ptp->pin_attr);
+no_pin_attr:
+       kfree(ptp->pin_dev_attr);
+no_dev_attr:
+       return err;
+}
+
 int ptp_populate_sysfs(struct ptp_clock *ptp)
 {
        struct device *dev = ptp->dev;
@@ -222,7 +329,15 @@ int ptp_populate_sysfs(struct ptp_clock *ptp)
                if (err)
                        goto out4;
        }
+       if (info->n_pins) {
+               err = ptp_populate_pins(ptp);
+               if (err)
+                       goto out5;
+       }
        return 0;
+out5:
+       if (info->pps)
+               device_remove_file(dev, &dev_attr_pps_enable);
 out4:
        if (info->n_per_out)
                device_remove_file(dev, &dev_attr_period);
index 8a843a04c22456bb5c9856a92aba876c03beeca9..a40b9c34e9fffcd2bce08169cd7a256de067027f 100644 (file)
@@ -52,8 +52,10 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm)
                offset = pwm_map->output[i];
 
                /* Return an error if the pin is already assigned */
-               if (test_and_set_bit(offset, &lp3943->pin_used))
+               if (test_and_set_bit(offset, &lp3943->pin_used)) {
+                       kfree(pwm_map);
                        return ERR_PTR(-EBUSY);
+               }
        }
 
        return pwm_map;
index b4b0d83f9ef6437dfb97f33037aaee1acf7bda59..7061ac0ad4287c0d84edb39058ef6abc295e43ce 100644 (file)
@@ -678,6 +678,7 @@ struct tsi721_bdma_chan {
        struct list_head        free_list;
        dma_cookie_t            completed_cookie;
        struct tasklet_struct   tasklet;
+       bool                    active;
 };
 
 #endif /* CONFIG_RAPIDIO_DMA_ENGINE */
index 502663f5f7c65a847f45881dcac4821081a314cf..91245f5dbe81a7d235f13a2dd2edbe741508d584 100644 (file)
@@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
 {
        /* Disable BDMA channel interrupts */
        iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
-
-       tasklet_schedule(&bdma_chan->tasklet);
+       if (bdma_chan->active)
+               tasklet_schedule(&bdma_chan->tasklet);
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -562,7 +562,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
        }
 #endif /* CONFIG_PCI_MSI */
 
-       tasklet_enable(&bdma_chan->tasklet);
+       bdma_chan->active = true;
        tsi721_bdma_interrupt_enable(bdma_chan, 1);
 
        return bdma_chan->bd_num - 1;
@@ -576,9 +576,7 @@ err_out:
 static void tsi721_free_chan_resources(struct dma_chan *dchan)
 {
        struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
-#ifdef CONFIG_PCI_MSI
        struct tsi721_device *priv = to_tsi721(dchan->device);
-#endif
        LIST_HEAD(list);
 
        dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
@@ -589,14 +587,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan)
        BUG_ON(!list_empty(&bdma_chan->active_list));
        BUG_ON(!list_empty(&bdma_chan->queue));
 
-       tasklet_disable(&bdma_chan->tasklet);
+       tsi721_bdma_interrupt_enable(bdma_chan, 0);
+       bdma_chan->active = false;
+
+#ifdef CONFIG_PCI_MSI
+       if (priv->flags & TSI721_USING_MSIX) {
+               synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE +
+                                          bdma_chan->id].vector);
+               synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT +
+                                          bdma_chan->id].vector);
+       } else
+#endif
+       synchronize_irq(priv->pdev->irq);
+
+       tasklet_kill(&bdma_chan->tasklet);
 
        spin_lock_bh(&bdma_chan->lock);
        list_splice_init(&bdma_chan->free_list, &list);
        spin_unlock_bh(&bdma_chan->lock);
 
-       tsi721_bdma_interrupt_enable(bdma_chan, 0);
-
 #ifdef CONFIG_PCI_MSI
        if (priv->flags & TSI721_USING_MSIX) {
                free_irq(priv->msix[TSI721_VECT_DMA0_DONE +
@@ -790,6 +799,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
                bdma_chan->dchan.cookie = 1;
                bdma_chan->dchan.chan_id = i;
                bdma_chan->id = i;
+               bdma_chan->active = false;
 
                spin_lock_init(&bdma_chan->lock);
 
@@ -799,7 +809,6 @@ int tsi721_register_dma(struct tsi721_device *priv)
 
                tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet,
                             (unsigned long)bdma_chan);
-               tasklet_disable(&bdma_chan->tasklet);
                list_add_tail(&bdma_chan->dchan.device_node,
                              &mport->dma.channels);
        }
index 16a309e5c024ed45b4276d13d1f8e14c2c0a131c..afca1bc24f262251abf3352d2e09d6452959805b 100644 (file)
@@ -953,6 +953,8 @@ static int machine_constraints_current(struct regulator_dev *rdev,
        return 0;
 }
 
+static int _regulator_do_enable(struct regulator_dev *rdev);
+
 /**
  * set_machine_constraints - sets regulator constraints
  * @rdev: regulator source
@@ -1013,10 +1015,9 @@ static int set_machine_constraints(struct regulator_dev *rdev,
        /* If the constraints say the regulator should be on at this point
         * and we have control then make sure it is enabled.
         */
-       if ((rdev->constraints->always_on || rdev->constraints->boot_on) &&
-           ops->enable) {
-               ret = ops->enable(rdev);
-               if (ret < 0) {
+       if (rdev->constraints->always_on || rdev->constraints->boot_on) {
+               ret = _regulator_do_enable(rdev);
+               if (ret < 0 && ret != -EINVAL) {
                        rdev_err(rdev, "failed to enable\n");
                        goto out;
                }
@@ -1359,7 +1360,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
                goto found;
        /* Don't log an error when called from regulator_get_optional() */
        } else if (!have_full_constraints() || exclusive) {
-               dev_err(dev, "dummy supplies not allowed\n");
+               dev_warn(dev, "dummy supplies not allowed\n");
        }
 
        mutex_unlock(&regulator_list_mutex);
@@ -1907,8 +1908,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
 
        trace_regulator_disable_complete(rdev_get_name(rdev));
 
-       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
-                            NULL);
        return 0;
 }
 
@@ -1932,6 +1931,8 @@ static int _regulator_disable(struct regulator_dev *rdev)
                                rdev_err(rdev, "failed to disable\n");
                                return ret;
                        }
+                       _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
+                                       NULL);
                }
 
                rdev->use_count = 0;
@@ -1984,20 +1985,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
 {
        int ret = 0;
 
-       /* force disable */
-       if (rdev->desc->ops->disable) {
-               /* ah well, who wants to live forever... */
-               ret = rdev->desc->ops->disable(rdev);
-               if (ret < 0) {
-                       rdev_err(rdev, "failed to force disable\n");
-                       return ret;
-               }
-               /* notify other consumers that power has been forced off */
-               _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
-                       REGULATOR_EVENT_DISABLE, NULL);
+       ret = _regulator_do_disable(rdev);
+       if (ret < 0) {
+               rdev_err(rdev, "failed to force disable\n");
+               return ret;
        }
 
-       return ret;
+       _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+                       REGULATOR_EVENT_DISABLE, NULL);
+
+       return 0;
 }
 
 /**
@@ -3630,23 +3627,18 @@ int regulator_suspend_finish(void)
 
        mutex_lock(&regulator_list_mutex);
        list_for_each_entry(rdev, &regulator_list, list) {
-               struct regulator_ops *ops = rdev->desc->ops;
-
                mutex_lock(&rdev->mutex);
-               if ((rdev->use_count > 0  || rdev->constraints->always_on) &&
-                               ops->enable) {
-                       error = ops->enable(rdev);
+               if (rdev->use_count > 0  || rdev->constraints->always_on) {
+                       error = _regulator_do_enable(rdev);
                        if (error)
                                ret = error;
                } else {
                        if (!have_full_constraints())
                                goto unlock;
-                       if (!ops->disable)
-                               goto unlock;
                        if (!_regulator_is_enabled(rdev))
                                goto unlock;
 
-                       error = ops->disable(rdev);
+                       error = _regulator_do_disable(rdev);
                        if (error)
                                ret = error;
                }
@@ -3820,7 +3812,7 @@ static int __init regulator_init_complete(void)
                ops = rdev->desc->ops;
                c = rdev->constraints;
 
-               if (!ops->disable || (c && c->always_on))
+               if (c && c->always_on)
                        continue;
 
                mutex_lock(&rdev->mutex);
@@ -3841,7 +3833,7 @@ static int __init regulator_init_complete(void)
                        /* We log since this may kill the system if it
                         * goes wrong. */
                        rdev_info(rdev, "disabling\n");
-                       ret = ops->disable(rdev);
+                       ret = _regulator_do_disable(rdev);
                        if (ret != 0)
                                rdev_err(rdev, "couldn't disable: %d\n", ret);
                } else {
index 7f340206d329d452710a319deba4869a2d6c603b..b14ebdad5dd2508f30854ac97e2b803cb5fa6e03 100644 (file)
@@ -576,7 +576,9 @@ static int da9055_regulator_probe(struct platform_device *pdev)
        /* Only LDO 5 and 6 has got the over current interrupt */
        if (pdev->id == DA9055_ID_LDO5 || pdev->id ==  DA9055_ID_LDO6) {
                irq = platform_get_irq_byname(pdev, "REGULATOR");
-               irq = regmap_irq_get_virq(da9055->irq_data, irq);
+               if (irq < 0)
+                       return irq;
+
                ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
                                                da9055_ldo5_6_oc_irq,
                                                IRQF_TRIGGER_HIGH |
index 56727eb745df69171d77fac8313e6ea3ab2499ef..91e99a2c8dc14354c4f60368f025fef15d78786e 100644 (file)
@@ -1,3 +1,4 @@
+
 /*
  * Regulator driver for DA9063 PMIC series
  *
@@ -60,7 +61,8 @@ struct da9063_regulator_info {
        .desc.ops = &da9063_ldo_ops, \
        .desc.min_uV = (min_mV) * 1000, \
        .desc.uV_step = (step_mV) * 1000, \
-       .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \
+       .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \
+               + (DA9063_V##regl_name##_BIAS)), \
        .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \
        .desc.enable_mask = DA9063_LDO_EN, \
        .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \
index b1078ba3f39381338f2691f7585961337cf536c1..e0619526708c88393069abf4411fa2ff9473e510 100644 (file)
@@ -166,12 +166,14 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev)
 
        ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches,
                        MAX14577_REG_MAX);
-       if (ret < 0) {
+       if (ret < 0)
                dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
-               return ret;
-       }
+       else
+               ret = 0;
 
-       return 0;
+       of_node_put(np);
+
+       return ret;
 }
 
 static inline struct regulator_init_data *match_init_data(int index)
index d7164bb75d3e0bf2a88a61c1a82e6c79072cd8b5..d958dfa051254866808fe6c36cf9db7184627b94 100644 (file)
@@ -535,7 +535,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                return -ENODEV;
        }
 
-       regulators_np = of_find_node_by_name(pmic_np, "regulators");
+       regulators_np = of_get_child_by_name(pmic_np, "regulators");
        if (!regulators_np) {
                dev_err(iodev->dev, "could not find regulators sub-node\n");
                return -EINVAL;
@@ -591,6 +591,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
                rmode++;
        }
 
+       of_node_put(regulators_np);
+
        if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) {
                pdata->buck2_gpiodvs = true;
 
index 7afd373b9595ff68b16238fc37688102dbaa04f4..c4cde9c08f1ffa9ed5c7c1d91a10b745ef7fdb3e 100644 (file)
@@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev)
 
        clk_enable(rtc_clk);
        /* save TICNT for anyone using periodic interrupts */
-       ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
        if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
                ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);
                ticnt_en_save &= S3C64XX_RTCCON_TICEN;
+               ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT);
+       } else {
+               ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
        }
        s3c_rtc_enable(pdev, 0);
 
@@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev)
 
        clk_enable(rtc_clk);
        s3c_rtc_enable(pdev, 1);
-       writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
-       if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) {
-               tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
-               writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON);
+       if (s3c_rtc_cpu_type == TYPE_S3C64XX) {
+               writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+               if (ticnt_en_save) {
+                       tmp = readw(s3c_rtc_base + S3C2410_RTCCON);
+                       writew(tmp | ticnt_en_save,
+                                       s3c_rtc_base + S3C2410_RTCCON);
+               }
+       } else {
+               writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
        }
 
        if (device_may_wakeup(dev) && wake_en) {
index f6b9188c5af581b8c0d587932c5de1af5d996951..9f0ea6cb6922619dfe04803c284002431110e11f 100644 (file)
@@ -610,6 +610,7 @@ void chsc_chp_online(struct chp_id chpid)
                css_wait_for_slow_path();
                for_each_subchannel_staged(__s390_process_res_acc, NULL,
                                           &link);
+               css_schedule_reprobe();
        }
 }
 
index 88e35d85d205f7c21de1f81860865386a7845289..8ee88c4ebd83e8dcdd78f45a2adc8500205e850b 100644 (file)
@@ -342,8 +342,9 @@ static int cio_check_config(struct subchannel *sch, struct schib *schib)
  */
 int cio_commit_config(struct subchannel *sch)
 {
-       struct schib schib;
        int ccode, retry, ret = 0;
+       struct schib schib;
+       struct irb irb;
 
        if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib))
                return -ENODEV;
@@ -367,7 +368,10 @@ int cio_commit_config(struct subchannel *sch)
                        ret = -EAGAIN;
                        break;
                case 1: /* status pending */
-                       return -EBUSY;
+                       ret = -EBUSY;
+                       if (tsch(sch->schid, &irb))
+                               return ret;
+                       break;
                case 2: /* busy */
                        udelay(100); /* allow for recovery */
                        ret = -EBUSY;
@@ -403,7 +407,6 @@ EXPORT_SYMBOL_GPL(cio_update_schib);
  */
 int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
 {
-       int retry;
        int ret;
 
        CIO_TRACE_EVENT(2, "ensch");
@@ -418,20 +421,14 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
        sch->config.isc = sch->isc;
        sch->config.intparm = intparm;
 
-       for (retry = 0; retry < 3; retry++) {
+       ret = cio_commit_config(sch);
+       if (ret == -EIO) {
+               /*
+                * Got a program check in msch. Try without
+                * the concurrent sense bit the next time.
+                */
+               sch->config.csense = 0;
                ret = cio_commit_config(sch);
-               if (ret == -EIO) {
-                       /*
-                        * Got a program check in msch. Try without
-                        * the concurrent sense bit the next time.
-                        */
-                       sch->config.csense = 0;
-               } else if (ret == -EBUSY) {
-                       struct irb irb;
-                       if (tsch(sch->schid, &irb) != 0)
-                               break;
-               } else
-                       break;
        }
        CIO_HEX_EVENT(2, &ret, sizeof(ret));
        return ret;
@@ -444,7 +441,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel);
  */
 int cio_disable_subchannel(struct subchannel *sch)
 {
-       int retry;
        int ret;
 
        CIO_TRACE_EVENT(2, "dissch");
@@ -456,16 +452,8 @@ int cio_disable_subchannel(struct subchannel *sch)
                return -ENODEV;
 
        sch->config.ena = 0;
+       ret = cio_commit_config(sch);
 
-       for (retry = 0; retry < 3; retry++) {
-               ret = cio_commit_config(sch);
-               if (ret == -EBUSY) {
-                       struct irb irb;
-                       if (tsch(sch->schid, &irb) != 0)
-                               break;
-               } else
-                       break;
-       }
        CIO_HEX_EVENT(2, &ret, sizeof(ret));
        return ret;
 }
index 8acaae18bd11c404d4b6a25e4771846c39e4c837..a563e4c00590d5737b50ad08ee654f0aba551dc7 100644 (file)
@@ -359,14 +359,12 @@ static inline int multicast_outbound(struct qdio_q *q)
 #define need_siga_sync_out_after_pci(q)        \
        (unlikely(q->irq_ptr->siga_flag.sync_out_after_pci))
 
-#define for_each_input_queue(irq_ptr, q, i)    \
-       for (i = 0, q = irq_ptr->input_qs[0];   \
-               i < irq_ptr->nr_input_qs;       \
-               q = irq_ptr->input_qs[++i])
-#define for_each_output_queue(irq_ptr, q, i)   \
-       for (i = 0, q = irq_ptr->output_qs[0];  \
-               i < irq_ptr->nr_output_qs;      \
-               q = irq_ptr->output_qs[++i])
+#define for_each_input_queue(irq_ptr, q, i)            \
+       for (i = 0; i < irq_ptr->nr_input_qs &&         \
+               ({ q = irq_ptr->input_qs[i]; 1; }); i++)
+#define for_each_output_queue(irq_ptr, q, i)           \
+       for (i = 0; i < irq_ptr->nr_output_qs &&        \
+               ({ q = irq_ptr->output_qs[i]; 1; }); i++)
 
 #define prev_buf(bufnr)        \
        ((bufnr + QDIO_MAX_BUFFERS_MASK) & QDIO_MAX_BUFFERS_MASK)
index c883a085c0591cd8a0673d495f36e74f9f6e0427..77466c4faabb67b96851fa22c8674d3f6cc4a4a0 100644 (file)
@@ -996,7 +996,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr)
                }
        }
 
-       if (!pci_out_supported(q))
+       if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED))
                return;
 
        for_each_output_queue(irq_ptr, q, i) {
index dc542e0a3055a6abb63314ee6dd20ecc451c7d2d..0bc91e46395a8d84ad8c989b6d2a7844593c3ba0 100644 (file)
@@ -311,7 +311,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
        } __packed * msg = ap_msg->message;
 
        int rcblen = CEIL4(xcRB->request_control_blk_length);
-       int replylen;
+       int replylen, req_sumlen, resp_sumlen;
        char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
        char *function_code;
 
@@ -321,12 +321,34 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
                xcRB->request_data_length;
        if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE)
                return -EINVAL;
+
+       /* Overflow check
+          sum must be greater (or equal) than the largest operand */
+       req_sumlen = CEIL4(xcRB->request_control_blk_length) +
+                       xcRB->request_data_length;
+       if ((CEIL4(xcRB->request_control_blk_length) <=
+                                               xcRB->request_data_length) ?
+               (req_sumlen < xcRB->request_data_length) :
+               (req_sumlen < CEIL4(xcRB->request_control_blk_length))) {
+               return -EINVAL;
+       }
+
        replylen = sizeof(struct type86_fmt2_msg) +
                CEIL4(xcRB->reply_control_blk_length) +
                xcRB->reply_data_length;
        if (replylen > MSGTYPE06_MAX_MSG_SIZE)
                return -EINVAL;
 
+       /* Overflow check
+          sum must be greater (or equal) than the largest operand */
+       resp_sumlen = CEIL4(xcRB->reply_control_blk_length) +
+                       xcRB->reply_data_length;
+       if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ?
+               (resp_sumlen < xcRB->reply_data_length) :
+               (resp_sumlen < CEIL4(xcRB->reply_control_blk_length))) {
+               return -EINVAL;
+       }
+
        /* prepare type6 header */
        msg->hdr = static_type6_hdrX;
        memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
index a0de045eb227d5eeb845bf9f6c925bbfcfe73634..5333b2c018e781541905e855c7cf3ff0a5d84a9e 100644 (file)
@@ -854,8 +854,11 @@ static inline int qeth_get_micros(void)
 
 static inline int qeth_get_ip_version(struct sk_buff *skb)
 {
-       struct ethhdr *ehdr = (struct ethhdr *)skb->data;
-       switch (ehdr->h_proto) {
+       __be16 *p = &((struct ethhdr *)skb->data)->h_proto;
+
+       if (*p == ETH_P_8021Q)
+               p += 2;
+       switch (*p) {
        case ETH_P_IPV6:
                return 6;
        case ETH_P_IP:
index c3a83df07894e51195d914111c15be2c615f09c1..e1c3a3828cb1f788118553b6bab9de5ab4aee14a 100644 (file)
@@ -1660,7 +1660,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
                                QDIO_FLAG_CLEANUP_USING_CLEAR);
                if (rc)
                        QETH_CARD_TEXT_(card, 3, "1err%d", rc);
-               qdio_free(CARD_DDEV(card));
                atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
                break;
        case QETH_QDIO_CLEANING:
@@ -2605,6 +2604,7 @@ static int qeth_mpc_initialize(struct qeth_card *card)
        return 0;
 out_qdio:
        qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
+       qdio_free(CARD_DDEV(card));
        return rc;
 }
 
@@ -4610,8 +4610,8 @@ out:
 }
 EXPORT_SYMBOL_GPL(qeth_query_oat_command);
 
-int qeth_query_card_info_cb(struct qeth_card *card,
-                       struct qeth_reply *reply, unsigned long data)
+static int qeth_query_card_info_cb(struct qeth_card *card,
+                                  struct qeth_reply *reply, unsigned long data)
 {
        struct qeth_ipa_cmd *cmd;
        struct qeth_query_card_info *card_info;
@@ -4906,9 +4906,11 @@ retry:
        if (retries < 3)
                QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n",
                        dev_name(&card->gdev->dev));
+       rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        rc = ccw_device_set_online(CARD_RDEV(card));
        if (rc)
                goto retriable;
@@ -4918,7 +4920,6 @@ retry:
        rc = ccw_device_set_online(CARD_DDEV(card));
        if (rc)
                goto retriable;
-       rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD);
 retriable:
        if (rc == -ERESTARTSYS) {
                QETH_DBF_TEXT(SETUP, 2, "break1");
index 0710550093ce6ac5fea8ddbf80f8409bbc1186f6..8dea3f12ccc1714defe7d4d65869817dd6b69135 100644 (file)
@@ -241,7 +241,7 @@ static inline int qeth_l2_get_cast_type(struct qeth_card *card,
 }
 
 static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
-                       struct sk_buff *skb, int ipv, int cast_type)
+                       struct sk_buff *skb, int cast_type)
 {
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb_mac_header(skb);
 
@@ -762,7 +762,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                                goto tx_drop;
                        elements_needed++;
                        skb_reset_mac_header(new_skb);
-                       qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+                       qeth_l2_fill_header(card, hdr, new_skb, cast_type);
                        hdr->hdr.l2.pkt_length = new_skb->len;
                        memcpy(((char *)hdr) + sizeof(struct qeth_hdr),
                                skb_mac_header(new_skb), ETH_HLEN);
@@ -775,7 +775,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        hdr = (struct qeth_hdr *)skb_push(new_skb,
                                                sizeof(struct qeth_hdr));
                        skb_set_mac_header(new_skb, sizeof(struct qeth_hdr));
-                       qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
+                       qeth_l2_fill_header(card, hdr, new_skb, cast_type);
                }
        }
 
@@ -1091,6 +1091,7 @@ out_remove:
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_RECOVER)
                card->state = CARD_STATE_RECOVER;
        else
@@ -1132,6 +1133,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
                rc = (rc2) ? rc2 : rc3;
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_UP)
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
@@ -1194,6 +1196,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
        qeth_qdio_clear_card(card, 0);
        qeth_clear_qdio_buffers(card);
+       qdio_free(CARD_DDEV(card));
 }
 
 static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
index 0f430424c3b8b0aec231c3e2ca69d739c0c29701..3524d34ff694c273afefc7d85bfa17b6bce38af9 100644 (file)
@@ -3447,6 +3447,7 @@ out_remove:
        ccw_device_set_offline(CARD_DDEV(card));
        ccw_device_set_offline(CARD_WDEV(card));
        ccw_device_set_offline(CARD_RDEV(card));
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_RECOVER)
                card->state = CARD_STATE_RECOVER;
        else
@@ -3493,6 +3494,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
                rc = (rc2) ? rc2 : rc3;
        if (rc)
                QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+       qdio_free(CARD_DDEV(card));
        if (recover_flag == CARD_STATE_UP)
                card->state = CARD_STATE_RECOVER;
        /* let user_space know that device is offline */
@@ -3545,6 +3547,7 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
                qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
        qeth_qdio_clear_card(card, 0);
        qeth_clear_qdio_buffers(card);
+       qdio_free(CARD_DDEV(card));
 }
 
 static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
index 6b4678a7900a086e711d4bf9a7f6004bc2efcb3c..4ccb5d869389e353113692d20f02f66d002046cd 100644 (file)
@@ -507,7 +507,6 @@ static int jsflash_init(void)
        }
 
        /* Let us be really paranoid for modifications to probing code. */
-       /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */
        if (sparc_cpu_model != sun4m) {
                /* We must be on sun4m because we use MMU Bypass ASI. */
                return -ENXIO;
index 1f375051483a428d24c63c206fb24a40cda06211..5642a9b250c2fe11201510460563ec576c70461c 100644 (file)
@@ -325,7 +325,7 @@ static int beiscsi_eh_device_reset(struct scsi_cmnd *sc)
                if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE)
                        continue;
 
-               if (abrt_task->sc->device->lun != abrt_task->sc->device->lun)
+               if (sc->device->lun != abrt_task->sc->device->lun)
                        continue;
 
                /* Invalidate WRB Posted for this Task */
index ed880891cb7c4b7c038ee73aac032b77108377d4..e9279a8c1e1c31ecb33daba06dceed4273eadd11 100644 (file)
@@ -594,13 +594,13 @@ static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req)
                mp_req->mp_resp_bd = NULL;
        }
        if (mp_req->req_buf) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                     mp_req->req_buf,
                                     mp_req->req_buf_dma);
                mp_req->req_buf = NULL;
        }
        if (mp_req->resp_buf) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                     mp_req->resp_buf,
                                     mp_req->resp_buf_dma);
                mp_req->resp_buf = NULL;
@@ -622,7 +622,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
 
        mp_req->req_len = sizeof(struct fcp_cmnd);
        io_req->data_xfer_len = mp_req->req_len;
-       mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                             &mp_req->req_buf_dma,
                                             GFP_ATOMIC);
        if (!mp_req->req_buf) {
@@ -631,7 +631,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
                return FAILED;
        }
 
-       mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                              &mp_req->resp_buf_dma,
                                              GFP_ATOMIC);
        if (!mp_req->resp_buf) {
@@ -639,8 +639,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
                bnx2fc_free_mp_resc(io_req);
                return FAILED;
        }
-       memset(mp_req->req_buf, 0, PAGE_SIZE);
-       memset(mp_req->resp_buf, 0, PAGE_SIZE);
+       memset(mp_req->req_buf, 0, CNIC_PAGE_SIZE);
+       memset(mp_req->resp_buf, 0, CNIC_PAGE_SIZE);
 
        /* Allocate and map mp_req_bd and mp_resp_bd */
        sz = sizeof(struct fcoe_bd_ctx);
@@ -665,7 +665,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
        mp_req_bd = mp_req->mp_req_bd;
        mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff;
        mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32);
-       mp_req_bd->buf_len = PAGE_SIZE;
+       mp_req_bd->buf_len = CNIC_PAGE_SIZE;
        mp_req_bd->flags = 0;
 
        /*
@@ -677,7 +677,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
        addr = mp_req->resp_buf_dma;
        mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff;
        mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32);
-       mp_resp_bd->buf_len = PAGE_SIZE;
+       mp_resp_bd->buf_len = CNIC_PAGE_SIZE;
        mp_resp_bd->flags = 0;
 
        return SUCCESS;
index 4d93177dfb530c4446d959bd97fb71cd5dee86d1..d9bae5672273762dba7d183b4bedcc5206c1f9fe 100644 (file)
@@ -673,7 +673,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map SQ */
        tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
-       tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->sq_mem_size = (tgt->sq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
                                     &tgt->sq_dma, GFP_KERNEL);
@@ -686,7 +687,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map CQ */
        tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
-       tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->cq_mem_size = (tgt->cq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
                                     &tgt->cq_dma, GFP_KERNEL);
@@ -699,7 +701,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map RQ and RQ PBL */
        tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
-       tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->rq_mem_size = (tgt->rq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
                                        &tgt->rq_dma, GFP_KERNEL);
@@ -710,8 +713,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        }
        memset(tgt->rq, 0, tgt->rq_mem_size);
 
-       tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
-       tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+       tgt->rq_pbl_size = (tgt->rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
+       tgt->rq_pbl_size = (tgt->rq_pbl_size + (CNIC_PAGE_SIZE - 1)) &
+                          CNIC_PAGE_MASK;
 
        tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
                                         &tgt->rq_pbl_dma, GFP_KERNEL);
@@ -722,7 +726,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        }
 
        memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
-       num_pages = tgt->rq_mem_size / PAGE_SIZE;
+       num_pages = tgt->rq_mem_size / CNIC_PAGE_SIZE;
        page = tgt->rq_dma;
        pbl = (u32 *)tgt->rq_pbl;
 
@@ -731,13 +735,13 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                pbl++;
                *pbl = (u32)((u64)page >> 32);
                pbl++;
-               page += PAGE_SIZE;
+               page += CNIC_PAGE_SIZE;
        }
 
        /* Allocate and map XFERQ */
        tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
-       tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) &
-                              PAGE_MASK;
+       tgt->xferq_mem_size = (tgt->xferq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                              CNIC_PAGE_MASK;
 
        tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
                                        &tgt->xferq_dma, GFP_KERNEL);
@@ -750,8 +754,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map CONFQ & CONFQ PBL */
        tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
-       tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) &
-                              PAGE_MASK;
+       tgt->confq_mem_size = (tgt->confq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                              CNIC_PAGE_MASK;
 
        tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
                                        &tgt->confq_dma, GFP_KERNEL);
@@ -763,9 +767,9 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        memset(tgt->confq, 0, tgt->confq_mem_size);
 
        tgt->confq_pbl_size =
-               (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (tgt->confq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        tgt->confq_pbl_size =
-               (tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (tgt->confq_pbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
                                            tgt->confq_pbl_size,
@@ -777,7 +781,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
        }
 
        memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
-       num_pages = tgt->confq_mem_size / PAGE_SIZE;
+       num_pages = tgt->confq_mem_size / CNIC_PAGE_SIZE;
        page = tgt->confq_dma;
        pbl = (u32 *)tgt->confq_pbl;
 
@@ -786,7 +790,7 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
                pbl++;
                *pbl = (u32)((u64)page >> 32);
                pbl++;
-               page += PAGE_SIZE;
+               page += CNIC_PAGE_SIZE;
        }
 
        /* Allocate and map ConnDB */
@@ -805,8 +809,8 @@ static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
 
        /* Allocate and map LCQ */
        tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
-       tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) &
-                            PAGE_MASK;
+       tgt->lcq_mem_size = (tgt->lcq_mem_size + (CNIC_PAGE_SIZE - 1)) &
+                            CNIC_PAGE_MASK;
 
        tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
                                      &tgt->lcq_dma, GFP_KERNEL);
index e4cf23df4b4f094d64a40332c81facd39da4097c..b87a1933f8809381d974392e6e7b3e7f208b86aa 100644 (file)
@@ -61,7 +61,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
         * yield integral num of page buffers
         */
        /* adjust SQ */
-       num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+       num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
        if (hba->max_sqes < num_elements_per_pg)
                hba->max_sqes = num_elements_per_pg;
        else if (hba->max_sqes % num_elements_per_pg)
@@ -69,7 +69,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
                                 ~(num_elements_per_pg - 1);
 
        /* adjust CQ */
-       num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE;
+       num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_CQE_SIZE;
        if (hba->max_cqes < num_elements_per_pg)
                hba->max_cqes = num_elements_per_pg;
        else if (hba->max_cqes % num_elements_per_pg)
@@ -77,7 +77,7 @@ static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba)
                                 ~(num_elements_per_pg - 1);
 
        /* adjust RQ */
-       num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
+       num_elements_per_pg = CNIC_PAGE_SIZE / BNX2I_RQ_WQE_SIZE;
        if (hba->max_rqes < num_elements_per_pg)
                hba->max_rqes = num_elements_per_pg;
        else if (hba->max_rqes % num_elements_per_pg)
@@ -959,7 +959,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
 
        /* SQ page table */
        memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size);
-       num_pages = ep->qp.sq_mem_size / PAGE_SIZE;
+       num_pages = ep->qp.sq_mem_size / CNIC_PAGE_SIZE;
        page = ep->qp.sq_phys;
 
        if (cnic_dev_10g)
@@ -973,7 +973,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) ((u64) page >> 32);
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                } else {
                        /* PTE is written in big endian format for
                         * 5706/5708/5709 devices */
@@ -981,13 +981,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) page;
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                }
        }
 
        /* RQ page table */
        memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size);
-       num_pages = ep->qp.rq_mem_size / PAGE_SIZE;
+       num_pages = ep->qp.rq_mem_size / CNIC_PAGE_SIZE;
        page = ep->qp.rq_phys;
 
        if (cnic_dev_10g)
@@ -1001,7 +1001,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) ((u64) page >> 32);
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                } else {
                        /* PTE is written in big endian format for
                         * 5706/5708/5709 devices */
@@ -1009,13 +1009,13 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) page;
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                }
        }
 
        /* CQ page table */
        memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size);
-       num_pages = ep->qp.cq_mem_size / PAGE_SIZE;
+       num_pages = ep->qp.cq_mem_size / CNIC_PAGE_SIZE;
        page = ep->qp.cq_phys;
 
        if (cnic_dev_10g)
@@ -1029,7 +1029,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) ((u64) page >> 32);
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                } else {
                        /* PTE is written in big endian format for
                         * 5706/5708/5709 devices */
@@ -1037,7 +1037,7 @@ static void setup_qp_page_tables(struct bnx2i_endpoint *ep)
                        ptbl++;
                        *ptbl = (u32) page;
                        ptbl++;
-                       page += PAGE_SIZE;
+                       page += CNIC_PAGE_SIZE;
                }
        }
 }
@@ -1064,11 +1064,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
        /* Allocate page table memory for SQ which is page aligned */
        ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE;
        ep->qp.sq_mem_size =
-               (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.sq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
        ep->qp.sq_pgtbl_size =
-               (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (ep->qp.sq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        ep->qp.sq_pgtbl_size =
-               (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.sq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        ep->qp.sq_pgtbl_virt =
                dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size,
@@ -1101,11 +1101,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
        /* Allocate page table memory for CQ which is page aligned */
        ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE;
        ep->qp.cq_mem_size =
-               (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.cq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
        ep->qp.cq_pgtbl_size =
-               (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (ep->qp.cq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        ep->qp.cq_pgtbl_size =
-               (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.cq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        ep->qp.cq_pgtbl_virt =
                dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size,
@@ -1144,11 +1144,11 @@ int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
        /* Allocate page table memory for RQ which is page aligned */
        ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE;
        ep->qp.rq_mem_size =
-               (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.rq_mem_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
        ep->qp.rq_pgtbl_size =
-               (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *);
+               (ep->qp.rq_mem_size / CNIC_PAGE_SIZE) * sizeof(void *);
        ep->qp.rq_pgtbl_size =
-               (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK;
+               (ep->qp.rq_pgtbl_size + (CNIC_PAGE_SIZE - 1)) & CNIC_PAGE_MASK;
 
        ep->qp.rq_pgtbl_virt =
                dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size,
@@ -1270,7 +1270,7 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
        bnx2i_adjust_qp_size(hba);
 
        iscsi_init.flags =
-               ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
+               (CNIC_PAGE_BITS - 8) << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT;
        if (en_tcp_dack)
                iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE;
        iscsi_init.reserved0 = 0;
@@ -1288,15 +1288,15 @@ int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba)
                        ((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16));
        iscsi_init.num_ccells_per_conn = hba->num_ccell;
        iscsi_init.num_tasks_per_conn = hba->max_sqes;
-       iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
+       iscsi_init.sq_wqes_per_page = CNIC_PAGE_SIZE / BNX2I_SQ_WQE_SIZE;
        iscsi_init.sq_num_wqes = hba->max_sqes;
        iscsi_init.cq_log_wqes_per_page =
-               (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE);
+               (u8) bnx2i_power_of2(CNIC_PAGE_SIZE / BNX2I_CQE_SIZE);
        iscsi_init.cq_num_wqes = hba->max_cqes;
        iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE +
-                                  (PAGE_SIZE - 1)) / PAGE_SIZE;
+                                  (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
        iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE +
-                                  (PAGE_SIZE - 1)) / PAGE_SIZE;
+                                  (CNIC_PAGE_SIZE - 1)) / CNIC_PAGE_SIZE;
        iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE;
        iscsi_init.rq_num_wqes = hba->max_rqes;
 
index 854dad7d5b03318d10077d2e367eeb6ca8242dc6..c8b0aff5bbd4aa86d79b64516acf87d97c8894bd 100644 (file)
@@ -525,7 +525,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
        struct iscsi_bd *mp_bdt;
        u64 addr;
 
-       hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                            &hba->mp_bd_dma, GFP_KERNEL);
        if (!hba->mp_bd_tbl) {
                printk(KERN_ERR "unable to allocate Middle Path BDT\n");
@@ -533,11 +533,12 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
                goto out;
        }
 
-       hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev,
+                                              CNIC_PAGE_SIZE,
                                               &hba->dummy_buf_dma, GFP_KERNEL);
        if (!hba->dummy_buffer) {
                printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n");
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  hba->mp_bd_tbl, hba->mp_bd_dma);
                hba->mp_bd_tbl = NULL;
                rc = -1;
@@ -548,7 +549,7 @@ static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba)
        addr = (unsigned long) hba->dummy_buf_dma;
        mp_bdt->buffer_addr_lo = addr & 0xffffffff;
        mp_bdt->buffer_addr_hi = addr >> 32;
-       mp_bdt->buffer_length = PAGE_SIZE;
+       mp_bdt->buffer_length = CNIC_PAGE_SIZE;
        mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN |
                        ISCSI_BD_FIRST_IN_BD_CHAIN;
 out:
@@ -565,12 +566,12 @@ out:
 static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
 {
        if (hba->mp_bd_tbl) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  hba->mp_bd_tbl, hba->mp_bd_dma);
                hba->mp_bd_tbl = NULL;
        }
        if (hba->dummy_buffer) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  hba->dummy_buffer, hba->dummy_buf_dma);
                hba->dummy_buffer = NULL;
        }
@@ -934,14 +935,14 @@ static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba,
                                            struct bnx2i_conn *bnx2i_conn)
 {
        if (bnx2i_conn->gen_pdu.resp_bd_tbl) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  bnx2i_conn->gen_pdu.resp_bd_tbl,
                                  bnx2i_conn->gen_pdu.resp_bd_dma);
                bnx2i_conn->gen_pdu.resp_bd_tbl = NULL;
        }
 
        if (bnx2i_conn->gen_pdu.req_bd_tbl) {
-               dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                  bnx2i_conn->gen_pdu.req_bd_tbl,
                                  bnx2i_conn->gen_pdu.req_bd_dma);
                bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
@@ -998,13 +999,13 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
        bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf;
 
        bnx2i_conn->gen_pdu.req_bd_tbl =
-               dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                   &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
        if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL)
                goto login_req_bd_tbl_failure;
 
        bnx2i_conn->gen_pdu.resp_bd_tbl =
-               dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE,
+               dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                                   &bnx2i_conn->gen_pdu.resp_bd_dma,
                                   GFP_KERNEL);
        if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL)
@@ -1013,7 +1014,7 @@ static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba,
        return 0;
 
 login_resp_bd_tbl_failure:
-       dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE,
+       dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
                          bnx2i_conn->gen_pdu.req_bd_tbl,
                          bnx2i_conn->gen_pdu.req_bd_dma);
        bnx2i_conn->gen_pdu.req_bd_tbl = NULL;
index 4911310a38f5e42fd9d292b89de93b57369c7419..22a9bb1abae1473062b06031494bb38b2cc11576 100644 (file)
@@ -311,9 +311,8 @@ static inline struct Scsi_Host *to_shost(struct isci_host *ihost)
 }
 
 #define for_each_isci_host(id, ihost, pdev) \
-       for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \
-            id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \
-            ihost = to_pci_info(pdev)->hosts[++id])
+       for (id = 0; id < SCI_MAX_CONTROLLERS && \
+            (ihost = to_pci_info(pdev)->hosts[id]); id++)
 
 static inline void wait_for_start(struct isci_host *ihost)
 {
index 85c77f6b802bdcba5795ced971a39e29f39ae8b9..ac879745ef8007ab2a4973aff26e3c950e8f1dba 100644 (file)
@@ -615,13 +615,6 @@ static void sci_apc_agent_link_up(struct isci_host *ihost,
                                          SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION);
        } else {
                /* the phy is already the part of the port */
-               u32 port_state = iport->sm.current_state_id;
-
-               /* if the PORT'S state is resetting then the link up is from
-                * port hard reset in this case, we need to tell the port
-                * that link up is recieved
-                */
-               BUG_ON(port_state != SCI_PORT_RESETTING);
                port_agent->phy_ready_mask |= 1 << phy_index;
                sci_port_link_up(iport, iphy);
        }
index 0d30ca849e8f71502c9ecddfa9aa539e4e59af0f..5d6fda72d659770d080e2c4201c4d3e6c7af1adc 100644 (file)
@@ -801,7 +801,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
                /* XXX: need to cleanup any ireqs targeting this
                 * domain_device
                 */
-               ret = TMF_RESP_FUNC_COMPLETE;
+               ret = -ENODEV;
                goto out;
        }
 
index e1fe95ef23e11353aed91a8da9dd1d1f8ef2a9c3..266724b6b8996d451c4bf81c2ff5f0dbee5c1de5 100644 (file)
@@ -2996,8 +2996,7 @@ struct qla_hw_data {
                                IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
                                IS_QLA8044(ha))
 #define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha))
-#define IS_NOPOLLING_TYPE(ha)  ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
-                       IS_QLA83XX(ha)) && (ha)->flags.msix_enabled)
+#define IS_NOPOLLING_TYPE(ha)  (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
 #define IS_FAC_REQUIRED(ha)    (IS_QLA81XX(ha) || IS_QLA83XX(ha))
 #define IS_NOCACHE_VPD_TYPE(ha)        (IS_QLA81XX(ha) || IS_QLA83XX(ha))
 #define IS_ALOGIO_CAPABLE(ha)  (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
index 9bc86b9e86b172145443d161e0715658df6acdc7..0a1dcb43d18bdb6b4c734e0ad38ac956ddeb5fe7 100644 (file)
@@ -2880,6 +2880,7 @@ static int
 qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
 #define MIN_MSIX_COUNT 2
+#define ATIO_VECTOR    2
        int i, ret;
        struct msix_entry *entries;
        struct qla_msix_entry *qentry;
@@ -2936,34 +2937,47 @@ msix_failed:
        }
 
        /* Enable MSI-X vectors for the base queue */
-       for (i = 0; i < ha->msix_count; i++) {
+       for (i = 0; i < 2; i++) {
                qentry = &ha->msix_entries[i];
-               if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
-                       ret = request_irq(qentry->vector,
-                               qla83xx_msix_entries[i].handler,
-                               0, qla83xx_msix_entries[i].name, rsp);
-               } else if (IS_P3P_TYPE(ha)) {
+               if (IS_P3P_TYPE(ha))
                        ret = request_irq(qentry->vector,
                                qla82xx_msix_entries[i].handler,
                                0, qla82xx_msix_entries[i].name, rsp);
-               } else {
+               else
                        ret = request_irq(qentry->vector,
                                msix_entries[i].handler,
                                0, msix_entries[i].name, rsp);
-               }
-               if (ret) {
-                       ql_log(ql_log_fatal, vha, 0x00cb,
-                           "MSI-X: unable to register handler -- %x/%d.\n",
-                           qentry->vector, ret);
-                       qla24xx_disable_msix(ha);
-                       ha->mqenable = 0;
-                       goto msix_out;
-               }
+               if (ret)
+                       goto msix_register_fail;
                qentry->have_irq = 1;
                qentry->rsp = rsp;
                rsp->msix = qentry;
        }
 
+       /*
+        * If target mode is enable, also request the vector for the ATIO
+        * queue.
+        */
+       if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
+               qentry = &ha->msix_entries[ATIO_VECTOR];
+               ret = request_irq(qentry->vector,
+                       qla83xx_msix_entries[ATIO_VECTOR].handler,
+                       0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
+               qentry->have_irq = 1;
+               qentry->rsp = rsp;
+               rsp->msix = qentry;
+       }
+
+msix_register_fail:
+       if (ret) {
+               ql_log(ql_log_fatal, vha, 0x00cb,
+                   "MSI-X: unable to register handler -- %x/%d.\n",
+                   qentry->vector, ret);
+               qla24xx_disable_msix(ha);
+               ha->mqenable = 0;
+               goto msix_out;
+       }
+
        /* Enable MSI-X vector for response queue update for queue 0 */
        if (IS_QLA83XX(ha)) {
                if (ha->msixbase && ha->mqiobase &&
index 9e80d61e5a3aa0f62e0dbc6d9aeae8632d81935c..0cb73074c1997409c4e63f6d39ac51e641eff088 100644 (file)
@@ -790,17 +790,32 @@ static inline int test_tgt_sess_count(struct qla_tgt *tgt)
 }
 
 /* Called by tcm_qla2xxx configfs code */
-void qlt_stop_phase1(struct qla_tgt *tgt)
+int qlt_stop_phase1(struct qla_tgt *tgt)
 {
        struct scsi_qla_host *vha = tgt->vha;
        struct qla_hw_data *ha = tgt->ha;
        unsigned long flags;
 
+       mutex_lock(&qla_tgt_mutex);
+       if (!vha->fc_vport) {
+               struct Scsi_Host *sh = vha->host;
+               struct fc_host_attrs *fc_host = shost_to_fc_host(sh);
+               bool npiv_vports;
+
+               spin_lock_irqsave(sh->host_lock, flags);
+               npiv_vports = (fc_host->npiv_vports_inuse);
+               spin_unlock_irqrestore(sh->host_lock, flags);
+
+               if (npiv_vports) {
+                       mutex_unlock(&qla_tgt_mutex);
+                       return -EPERM;
+               }
+       }
        if (tgt->tgt_stop || tgt->tgt_stopped) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e,
                    "Already in tgt->tgt_stop or tgt_stopped state\n");
-               dump_stack();
-               return;
+               mutex_unlock(&qla_tgt_mutex);
+               return -EPERM;
        }
 
        ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n",
@@ -815,6 +830,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
        qlt_clear_tgt_db(tgt, true);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
        mutex_unlock(&vha->vha_tgt.tgt_mutex);
+       mutex_unlock(&qla_tgt_mutex);
 
        flush_delayed_work(&tgt->sess_del_work);
 
@@ -841,6 +857,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
 
        /* Wait for sessions to clear out (just in case) */
        wait_event(tgt->waitQ, test_tgt_sess_count(tgt));
+       return 0;
 }
 EXPORT_SYMBOL(qlt_stop_phase1);
 
@@ -2595,8 +2612,6 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
                return -ENOMEM;
        }
 
-       INIT_LIST_HEAD(&cmd->cmd_list);
-
        memcpy(&cmd->atio, atio, sizeof(*atio));
        cmd->state = QLA_TGT_STATE_NEW;
        cmd->tgt = vha->vha_tgt.qla_tgt;
@@ -3187,7 +3202,8 @@ restart:
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c,
                    "SRR cmd %p (se_cmd %p, tag %d, op %x), "
                    "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag,
-                   se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset);
+                   se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0,
+                   cmd->sg_cnt, cmd->offset);
 
                qlt_handle_srr(vha, sctio, imm);
 
@@ -4183,6 +4199,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
        tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX;
        tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX;
 
+       if (base_vha->fc_vport)
+               return 0;
+
        mutex_lock(&qla_tgt_mutex);
        list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist);
        mutex_unlock(&qla_tgt_mutex);
@@ -4196,6 +4215,10 @@ int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha)
        if (!vha->vha_tgt.qla_tgt)
                return 0;
 
+       if (vha->fc_vport) {
+               qlt_release(vha->vha_tgt.qla_tgt);
+               return 0;
+       }
        mutex_lock(&qla_tgt_mutex);
        list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
        mutex_unlock(&qla_tgt_mutex);
@@ -4267,6 +4290,12 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
                        continue;
                }
+               if (tgt->tgt_stop) {
+                       pr_debug("MODE_TARGET in shutdown on qla2xxx(%d)\n",
+                                host->host_no);
+                       spin_unlock_irqrestore(&ha->hardware_lock, flags);
+                       continue;
+               }
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
                if (!scsi_host_get(host)) {
@@ -4281,12 +4310,11 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
                        scsi_host_put(host);
                        continue;
                }
-               mutex_unlock(&qla_tgt_mutex);
-
                rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn);
                if (rc != 0)
                        scsi_host_put(host);
 
+               mutex_unlock(&qla_tgt_mutex);
                return rc;
        }
        mutex_unlock(&qla_tgt_mutex);
index 1d10eecad499a3598dc3bbd1dc566416d210c54a..ce33d8c26406da00ccb67943093bae5f3fdec0b9 100644 (file)
@@ -855,7 +855,6 @@ struct qla_tgt_cmd {
        uint16_t loop_id;       /* to save extra sess dereferences */
        struct qla_tgt *tgt;    /* to save extra sess dereferences */
        struct scsi_qla_host *vha;
-       struct list_head cmd_list;
 
        struct atio_from_isp atio;
 };
@@ -1002,7 +1001,7 @@ extern void qlt_modify_vp_config(struct scsi_qla_host *,
 extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
 extern int qlt_mem_alloc(struct qla_hw_data *);
 extern void qlt_mem_free(struct qla_hw_data *);
-extern void qlt_stop_phase1(struct qla_tgt *);
+extern int qlt_stop_phase1(struct qla_tgt *);
 extern void qlt_stop_phase2(struct qla_tgt *);
 extern irqreturn_t qla83xx_msix_atio_q(int, void *);
 extern void qlt_83xx_iospace_config(struct qla_hw_data *);
index 75a141bbe74d178834a9f58c6fc723734e63758f..788c4fe2b0c9ec7a8113078c318421d7407ae855 100644 (file)
@@ -182,20 +182,6 @@ static int tcm_qla2xxx_npiv_parse_wwn(
        return 0;
 }
 
-static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len,
-                                       u64 wwpn, u64 wwnn)
-{
-       u8 b[8], b2[8];
-
-       put_unaligned_be64(wwpn, b);
-       put_unaligned_be64(wwnn, b2);
-       return snprintf(buf, len,
-               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x,"
-               "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
-               b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
-               b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]);
-}
-
 static char *tcm_qla2xxx_npiv_get_fabric_name(void)
 {
        return "qla2xxx_npiv";
@@ -227,15 +213,6 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
        return lport->lport_naa_name;
 }
 
-static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
-{
-       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
-                               struct tcm_qla2xxx_tpg, se_tpg);
-       struct tcm_qla2xxx_lport *lport = tpg->lport;
-
-       return &lport->lport_npiv_name[0];
-}
-
 static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg)
 {
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
@@ -941,15 +918,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable(
                        atomic_read(&tpg->lport_tpg_enabled));
 }
 
+static void tcm_qla2xxx_depend_tpg(struct work_struct *work)
+{
+       struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+                               struct tcm_qla2xxx_tpg, tpg_base_work);
+       struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+       struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+       if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                 &se_tpg->tpg_group.cg_item)) {
+               atomic_set(&base_tpg->lport_tpg_enabled, 1);
+               qlt_enable_vha(base_vha);
+       }
+       complete(&base_tpg->tpg_base_comp);
+}
+
+static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
+{
+       struct tcm_qla2xxx_tpg *base_tpg = container_of(work,
+                               struct tcm_qla2xxx_tpg, tpg_base_work);
+       struct se_portal_group *se_tpg = &base_tpg->se_tpg;
+       struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha;
+
+       if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) {
+               atomic_set(&base_tpg->lport_tpg_enabled, 0);
+               configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+                                      &se_tpg->tpg_group.cg_item);
+       }
+       complete(&base_tpg->tpg_base_comp);
+}
+
 static ssize_t tcm_qla2xxx_tpg_store_enable(
        struct se_portal_group *se_tpg,
        const char *page,
        size_t count)
 {
-       struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
-       struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
-                       struct tcm_qla2xxx_lport, lport_wwn);
-       struct scsi_qla_host *vha = lport->qla_vha;
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
                        struct tcm_qla2xxx_tpg, se_tpg);
        unsigned long op;
@@ -964,19 +967,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
                pr_err("Illegal value for tpg_enable: %lu\n", op);
                return -EINVAL;
        }
-
        if (op) {
-               atomic_set(&tpg->lport_tpg_enabled, 1);
-               qlt_enable_vha(vha);
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EEXIST;
+
+               INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg);
        } else {
-               if (!vha->vha_tgt.qla_tgt) {
-                       pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n");
-                       return -ENODEV;
-               }
-               atomic_set(&tpg->lport_tpg_enabled, 0);
-               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return count;
+
+               INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg);
        }
+       init_completion(&tpg->tpg_base_comp);
+       schedule_work(&tpg->tpg_base_work);
+       wait_for_completion(&tpg->tpg_base_comp);
 
+       if (op) {
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return -ENODEV;
+       } else {
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EPERM;
+       }
        return count;
 }
 
@@ -1053,11 +1065,64 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
        /*
         * Clear local TPG=1 pointer for non NPIV mode.
         */
-               lport->tpg_1 = NULL;
-
+       lport->tpg_1 = NULL;
        kfree(tpg);
 }
 
+static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+}
+
+static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
+       struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
+                       struct tcm_qla2xxx_lport, lport_wwn);
+       struct scsi_qla_host *vha = lport->qla_vha;
+       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+                       struct tcm_qla2xxx_tpg, se_tpg);
+       unsigned long op;
+       int rc;
+
+       rc = kstrtoul(page, 0, &op);
+       if (rc < 0) {
+               pr_err("kstrtoul() returned %d\n", rc);
+               return -EINVAL;
+       }
+       if ((op != 1) && (op != 0)) {
+               pr_err("Illegal value for tpg_enable: %lu\n", op);
+               return -EINVAL;
+       }
+       if (op) {
+               if (atomic_read(&tpg->lport_tpg_enabled))
+                       return -EEXIST;
+
+               atomic_set(&tpg->lport_tpg_enabled, 1);
+               qlt_enable_vha(vha);
+       } else {
+               if (!atomic_read(&tpg->lport_tpg_enabled))
+                       return count;
+
+               atomic_set(&tpg->lport_tpg_enabled, 0);
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
+       }
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
+        &tcm_qla2xxx_npiv_tpg_enable.attr,
+        NULL,
+};
+
 static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
        struct se_wwn *wwn,
        struct config_group *group,
@@ -1650,6 +1715,9 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
        struct scsi_qla_host *npiv_vha;
        struct tcm_qla2xxx_lport *lport =
                        (struct tcm_qla2xxx_lport *)target_lport_ptr;
+       struct tcm_qla2xxx_lport *base_lport =
+                       (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr;
+       struct tcm_qla2xxx_tpg *base_tpg;
        struct fc_vport_identifiers vport_id;
 
        if (!qla_tgt_mode_enabled(base_vha)) {
@@ -1657,6 +1725,13 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
                return -EPERM;
        }
 
+       if (!base_lport || !base_lport->tpg_1 ||
+           !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) {
+               pr_err("qla2xxx base_lport or tpg_1 not available\n");
+               return -EPERM;
+       }
+       base_tpg = base_lport->tpg_1;
+
        memset(&vport_id, 0, sizeof(vport_id));
        vport_id.port_name = npiv_wwpn;
        vport_id.node_name = npiv_wwnn;
@@ -1675,7 +1750,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
        npiv_vha = (struct scsi_qla_host *)vport->dd_data;
        npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr;
        lport->qla_vha = npiv_vha;
-
        scsi_host_get(npiv_vha->host);
        return 0;
 }
@@ -1714,8 +1788,6 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
        }
        lport->lport_npiv_wwpn = npiv_wwpn;
        lport->lport_npiv_wwnn = npiv_wwnn;
-       tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
-                       TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
        sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
 
        ret = tcm_qla2xxx_init_lport(lport);
@@ -1824,7 +1896,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
 static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .get_fabric_name                = tcm_qla2xxx_npiv_get_fabric_name,
        .get_fabric_proto_ident         = tcm_qla2xxx_get_fabric_proto_ident,
-       .tpg_get_wwn                    = tcm_qla2xxx_npiv_get_fabric_wwn,
+       .tpg_get_wwn                    = tcm_qla2xxx_get_fabric_wwn,
        .tpg_get_tag                    = tcm_qla2xxx_get_tag,
        .tpg_get_default_depth          = tcm_qla2xxx_get_default_depth,
        .tpg_get_pr_transport_id        = tcm_qla2xxx_get_pr_transport_id,
@@ -1935,7 +2007,7 @@ static int tcm_qla2xxx_register_configfs(void)
         */
        npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
-           tcm_qla2xxx_tpg_attrs;
+           tcm_qla2xxx_npiv_tpg_attrs;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
index 275d8b9a7a34121d4d7d356659bfe92816219a3f..33aaac8c7d5936bbdd3e2d9f934f2c92f2083331 100644 (file)
@@ -4,8 +4,6 @@
 #define TCM_QLA2XXX_VERSION    "v0.1"
 /* length of ASCII WWPNs including pad */
 #define TCM_QLA2XXX_NAMELEN    32
-/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */
-#define TCM_QLA2XXX_NPIV_NAMELEN 66
 
 #include "qla_target.h"
 
@@ -43,6 +41,9 @@ struct tcm_qla2xxx_tpg {
        struct tcm_qla2xxx_tpg_attrib tpg_attrib;
        /* Returned by tcm_qla2xxx_make_tpg() */
        struct se_portal_group se_tpg;
+       /* Items for dealing with configfs_depend_item */
+       struct completion tpg_base_comp;
+       struct work_struct tpg_base_work;
 };
 
 struct tcm_qla2xxx_fc_loopid {
@@ -62,8 +63,6 @@ struct tcm_qla2xxx_lport {
        char lport_name[TCM_QLA2XXX_NAMELEN];
        /* ASCII formatted naa WWPN for VPD page 83 etc */
        char lport_naa_name[TCM_QLA2XXX_NAMELEN];
-       /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
-       char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
        /* map for fc_port pointers in 24-bit FC Port ID space */
        struct btree_head32 lport_fcport_map;
        /* vmalloc-ed memory for fc_port pointers for 16-bit FC loop ID */
index 7bd7f0d5f050a2ece3f176b1f05ca2f8936270a3..62ec84b42e31cfb77f1aad4e040da30e3a104ef6 100644 (file)
@@ -1684,7 +1684,7 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
 
        host_dev = scsi_get_device(shost);
        if (host_dev && host_dev->dma_mask)
-               bounce_limit = dma_max_pfn(host_dev) << PAGE_SHIFT;
+               bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT;
 
        return bounce_limit;
 }
index 17d7404272400dd1a76989a3965e0c4b85343036..9969fa1ef7c4ef09ac4fc72c942c5ef72703ae49 100644 (file)
@@ -1419,6 +1419,9 @@ static void storvsc_device_destroy(struct scsi_device *sdevice)
 {
        struct stor_mem_pools *memp = sdevice->hostdata;
 
+       if (!memp)
+               return;
+
        mempool_destroy(memp->request_mempool);
        kmem_cache_destroy(memp->request_pool);
        kfree(memp);
index ba9310bc9acb7449a91ccb59b8f7de5c09c5801d..581ee2a8856b157641eb5a6b2c13389241b4ea90 100644 (file)
@@ -376,10 +376,10 @@ config SPI_PXA2XX_PCI
        def_tristate SPI_PXA2XX && PCI
 
 config SPI_RSPI
-       tristate "Renesas RSPI controller"
+       tristate "Renesas RSPI/QSPI controller"
        depends on (SUPERH && SH_DMAE_BASE) || ARCH_SHMOBILE
        help
-         SPI driver for Renesas RSPI blocks.
+         SPI driver for Renesas RSPI and QSPI blocks.
 
 config SPI_S3C24XX
        tristate "Samsung S3C24XX series SPI"
index 31534b51715aa95e29664cc80d44d71b5131d0ab..c3b2fb9b6713c997b1338d5df13470e0227a5d93 100644 (file)
@@ -132,9 +132,9 @@ static int ath79_spi_setup_cs(struct spi_device *spi)
 
                flags = GPIOF_DIR_OUT;
                if (spi->mode & SPI_CS_HIGH)
-                       flags |= GPIOF_INIT_HIGH;
-               else
                        flags |= GPIOF_INIT_LOW;
+               else
+                       flags |= GPIOF_INIT_HIGH;
 
                status = gpio_request_one(cdata->gpio, flags,
                                          dev_name(&spi->dev));
index b0842f75101647616ada3a3db4f545a57b519be0..5d7b07f083266e64ab0d91436c10ae89a9ec112c 100644 (file)
@@ -1455,6 +1455,14 @@ static int atmel_spi_suspend(struct device *dev)
 {
        struct spi_master       *master = dev_get_drvdata(dev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
+       int ret;
+
+       /* Stop the queue running */
+       ret = spi_master_suspend(master);
+       if (ret) {
+               dev_warn(dev, "cannot suspend master\n");
+               return ret;
+       }
 
        clk_disable_unprepare(as->clk);
        return 0;
@@ -1464,9 +1472,16 @@ static int atmel_spi_resume(struct device *dev)
 {
        struct spi_master       *master = dev_get_drvdata(dev);
        struct atmel_spi        *as = spi_master_get_devdata(master);
+       int ret;
 
        clk_prepare_enable(as->clk);
-       return 0;
+
+       /* Start the queue running */
+       ret = spi_master_resume(master);
+       if (ret)
+               dev_err(dev, "problem starting queue (%d)\n", ret);
+
+       return ret;
 }
 
 static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
index cabed8f9119e1af30d80766420d548b94567c91c..28ae470397a9e0a7c77c88f5370327e73df01a67 100644 (file)
@@ -514,7 +514,8 @@ static int mcfqspi_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int mcfqspi_runtime_suspend(struct device *dev)
 {
-       struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        clk_disable(mcfqspi->clk);
 
@@ -523,7 +524,8 @@ static int mcfqspi_runtime_suspend(struct device *dev)
 
 static int mcfqspi_runtime_resume(struct device *dev)
 {
-       struct mcfqspi *mcfqspi = dev_get_drvdata(dev);
+       struct spi_master *master = dev_get_drvdata(dev);
+       struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
 
        clk_enable(mcfqspi->clk);
 
index ec79f726672a14f7644810101afe59e82322976c..a25392065d9b838ef852e93d09e53d0d121ac485 100644 (file)
@@ -420,7 +420,6 @@ static int dspi_suspend(struct device *dev)
 
 static int dspi_resume(struct device *dev)
 {
-
        struct spi_master *master = dev_get_drvdata(dev);
        struct fsl_dspi *dspi = spi_master_get_devdata(master);
 
@@ -504,7 +503,7 @@ static int dspi_probe(struct platform_device *pdev)
        clk_prepare_enable(dspi->clk);
 
        init_waitqueue_head(&dspi->waitq);
-       platform_set_drvdata(pdev, dspi);
+       platform_set_drvdata(pdev, master);
 
        ret = spi_bitbang_start(&dspi->bitbang);
        if (ret != 0) {
@@ -525,7 +524,8 @@ out_master_put:
 
 static int dspi_remove(struct platform_device *pdev)
 {
-       struct fsl_dspi *dspi = platform_get_drvdata(pdev);
+       struct spi_master *master = platform_get_drvdata(pdev);
+       struct fsl_dspi *dspi = spi_master_get_devdata(master);
 
        /* Disconnect from the SPI framework */
        spi_bitbang_stop(&dspi->bitbang);
index a5474ef9d2a0cf4ad7367ee1e0399fae2e982145..47f15d97e7fa41efeede0bce941d4584a0c07be5 100644 (file)
@@ -948,8 +948,8 @@ static int spi_imx_remove(struct platform_device *pdev)
        spi_bitbang_stop(&spi_imx->bitbang);
 
        writel(0, spi_imx->base + MXC_CSPICTRL);
-       clk_disable_unprepare(spi_imx->clk_ipg);
-       clk_disable_unprepare(spi_imx->clk_per);
+       clk_unprepare(spi_imx->clk_ipg);
+       clk_unprepare(spi_imx->clk_per);
        spi_master_put(master);
 
        return 0;
index 50406306bc209493152eca0a5b636811e30593d6..bae97ffec4b9952f10a1affc3ca3741d537e91af 100644 (file)
@@ -361,6 +361,8 @@ static int nuc900_spi_probe(struct platform_device *pdev)
        init_completion(&hw->done);
 
        master->mode_bits          = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+       if (hw->pdata->lsb)
+               master->mode_bits |= SPI_LSB_FIRST;
        master->num_chipselect     = hw->pdata->num_cs;
        master->bus_num            = hw->pdata->bus_num;
        hw->bitbang.master         = hw->master;
index 2e7f38c7a9610b11f63fd36c816f311b3372d66d..88eb57e858b379ac258abad703bf532b60852669 100644 (file)
@@ -915,7 +915,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
        /* Set Tx DMA */
        param = &dma->param_tx;
        param->dma_dev = &dma_dev->dev;
-       param->chan_id = data->master->bus_num * 2; /* Tx = 0, 2 */
+       param->chan_id = data->ch * 2; /* Tx = 0, 2 */;
        param->tx_reg = data->io_base_addr + PCH_SPDWR;
        param->width = width;
        chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -930,7 +930,7 @@ static void pch_spi_request_dma(struct pch_spi_data *data, int bpw)
        /* Set Rx DMA */
        param = &dma->param_rx;
        param->dma_dev = &dma_dev->dev;
-       param->chan_id = data->master->bus_num * 2 + 1; /* Rx = Tx + 1 */
+       param->chan_id = data->ch * 2 + 1; /* Rx = Tx + 1 */;
        param->rx_reg = data->io_base_addr + PCH_SPDRR;
        param->width = width;
        chan = dma_request_channel(mask, pch_spi_filter, param);
@@ -1452,6 +1452,11 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
 
        pch_spi_set_master_mode(master);
 
+       if (use_dma) {
+               dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
+               pch_alloc_dma_buf(board_dat, data);
+       }
+
        ret = spi_register_master(master);
        if (ret != 0) {
                dev_err(&plat_dev->dev,
@@ -1459,14 +1464,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev)
                goto err_spi_register_master;
        }
 
-       if (use_dma) {
-               dev_info(&plat_dev->dev, "Use DMA for data transfers\n");
-               pch_alloc_dma_buf(board_dat, data);
-       }
-
        return 0;
 
 err_spi_register_master:
+       pch_free_dma_buf(board_dat, data);
        free_irq(board_dat->pdev->irq, data);
 err_request_irq:
        pch_spi_free_resources(board_dat, data);
index 23756b0f90363c2f776718925cf7fba84d13c4a3..d0b28bba38be6bfff2a420e9fc2850e5c84c690b 100644 (file)
@@ -755,9 +755,7 @@ static void spi_pump_messages(struct kthread_work *work)
        ret = master->transfer_one_message(master, master->cur_msg);
        if (ret) {
                dev_err(&master->dev,
-                       "failed to transfer one message from queue: %d\n", ret);
-               master->cur_msg->status = ret;
-               spi_finalize_current_message(master);
+                       "failed to transfer one message from queue\n");
                return;
        }
 }
index 23948f16701206926ec9a76ce347641316d692c5..713a9722678746f24363e3b9f3f4a0f89cc145ad 100644 (file)
@@ -295,21 +295,29 @@ static ssize_t ashmem_read(struct file *file, char __user *buf,
 
        /* If size is not set, or set to 0, always return EOF. */
        if (asma->size == 0)
-               goto out;
+               goto out_unlock;
 
        if (!asma->file) {
                ret = -EBADF;
-               goto out;
+               goto out_unlock;
        }
 
-       ret = asma->file->f_op->read(asma->file, buf, len, pos);
-       if (ret < 0)
-               goto out;
+       mutex_unlock(&ashmem_mutex);
 
-       /** Update backing file pos, since f_ops->read() doesn't */
-       asma->file->f_pos = *pos;
+       /*
+        * asma and asma->file are used outside the lock here.  We assume
+        * once asma->file is set it will never be changed, and will not
+        * be destroyed until all references to the file are dropped and
+        * ashmem_release is called.
+        */
+       ret = asma->file->f_op->read(asma->file, buf, len, pos);
+       if (ret >= 0) {
+               /** Update backing file pos, since f_ops->read() doesn't */
+               asma->file->f_pos = *pos;
+       }
+       return ret;
 
-out:
+out_unlock:
        mutex_unlock(&ashmem_mutex);
        return ret;
 }
@@ -498,6 +506,7 @@ out:
 
 static int set_name(struct ashmem_area *asma, void __user *name)
 {
+       int len;
        int ret = 0;
        char local_name[ASHMEM_NAME_LEN];
 
@@ -510,21 +519,19 @@ static int set_name(struct ashmem_area *asma, void __user *name)
         * variable that does not need protection and later copy the local
         * variable to the structure member with lock held.
         */
-       if (copy_from_user(local_name, name, ASHMEM_NAME_LEN))
-               return -EFAULT;
-
+       len = strncpy_from_user(local_name, name, ASHMEM_NAME_LEN);
+       if (len < 0)
+               return len;
+       if (len == ASHMEM_NAME_LEN)
+               local_name[ASHMEM_NAME_LEN - 1] = '\0';
        mutex_lock(&ashmem_mutex);
        /* cannot change an existing mapping's name */
-       if (unlikely(asma->file)) {
+       if (unlikely(asma->file))
                ret = -EINVAL;
-               goto out;
-       }
-       memcpy(asma->name + ASHMEM_NAME_PREFIX_LEN,
-               local_name, ASHMEM_NAME_LEN);
-       asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0';
-out:
-       mutex_unlock(&ashmem_mutex);
+       else
+               strcpy(asma->name + ASHMEM_NAME_PREFIX_LEN, local_name);
 
+       mutex_unlock(&ashmem_mutex);
        return ret;
 }
 
index eaec1dab7fe489fbbc9d171a4acdf5f78d765df6..1432d956769c2d5511716a5e8d3ea1eb5a667b68 100644 (file)
@@ -2904,7 +2904,7 @@ static int binder_node_release(struct binder_node *node, int refs)
                refs++;
 
                if (!ref->death)
-                       goto out;
+                       continue;
 
                death++;
 
@@ -2917,7 +2917,6 @@ static int binder_node_release(struct binder_node *node, int refs)
                        BUG();
        }
 
-out:
        binder_debug(BINDER_DEBUG_DEAD_BINDER,
                     "node %d now dead, refs %d, death %d\n",
                     node->debug_id, refs, death);
index af6cd370b30f3e890e5edc9bdec864efb4f8b9b8..ee3a7380e53b129ed04320940d6cae57cbbd4226 100644 (file)
@@ -35,9 +35,14 @@ struct compat_ion_custom_data {
        compat_ulong_t arg;
 };
 
+struct compat_ion_handle_data {
+       compat_int_t handle;
+};
+
 #define COMPAT_ION_IOC_ALLOC   _IOWR(ION_IOC_MAGIC, 0, \
                                      struct compat_ion_allocation_data)
-#define COMPAT_ION_IOC_FREE    _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data)
+#define COMPAT_ION_IOC_FREE    _IOWR(ION_IOC_MAGIC, 1, \
+                                     struct compat_ion_handle_data)
 #define COMPAT_ION_IOC_CUSTOM  _IOWR(ION_IOC_MAGIC, 6, \
                                      struct compat_ion_custom_data)
 
@@ -64,6 +69,19 @@ static int compat_get_ion_allocation_data(
        return err;
 }
 
+static int compat_get_ion_handle_data(
+                       struct compat_ion_handle_data __user *data32,
+                       struct ion_handle_data __user *data)
+{
+       compat_int_t i;
+       int err;
+
+       err = get_user(i, &data32->handle);
+       err |= put_user(i, &data->handle);
+
+       return err;
+}
+
 static int compat_put_ion_allocation_data(
                        struct compat_ion_allocation_data __user *data32,
                        struct ion_allocation_data __user *data)
@@ -132,8 +150,8 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        }
        case COMPAT_ION_IOC_FREE:
        {
-               struct compat_ion_allocation_data __user *data32;
-               struct ion_allocation_data __user *data;
+               struct compat_ion_handle_data __user *data32;
+               struct ion_handle_data __user *data;
                int err;
 
                data32 = compat_ptr(arg);
@@ -141,7 +159,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (data == NULL)
                        return -EFAULT;
 
-               err = compat_get_ion_allocation_data(data32, data);
+               err = compat_get_ion_handle_data(data32, data);
                if (err)
                        return err;
 
index 55b2002753f2251875fac6e9e66f5bf4c83efb42..01cdc8aee898a35cd98fc3437a31b1b066f6b92a 100644 (file)
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
 #include <linux/sizes.h>
+#include <linux/io.h>
 #include "ion.h"
 #include "ion_priv.h"
 
@@ -57,7 +59,7 @@ struct ion_platform_heap dummy_heaps[] = {
 };
 
 struct ion_platform_data dummy_ion_pdata = {
-       .nr = 4,
+       .nr = ARRAY_SIZE(dummy_heaps),
        .heaps = dummy_heaps,
 };
 
@@ -69,7 +71,7 @@ static int __init ion_dummy_init(void)
        heaps = kzalloc(sizeof(struct ion_heap *) * dummy_ion_pdata.nr,
                        GFP_KERNEL);
        if (!heaps)
-               return PTR_ERR(heaps);
+               return -ENOMEM;
 
 
        /* Allocate a dummy carveout heap */
@@ -128,6 +130,7 @@ err:
        }
        return err;
 }
+device_initcall(ion_dummy_init);
 
 static void __exit ion_dummy_exit(void)
 {
@@ -152,7 +155,4 @@ static void __exit ion_dummy_exit(void)
 
        return;
 }
-
-module_init(ion_dummy_init);
-module_exit(ion_dummy_exit);
-
+__exitcall(ion_dummy_exit);
index 296c74f98dc08c6cabbd8203fc4b535b59aedf30..37e64d51394ccecb90dde57bb6f6f84be123939b 100644 (file)
@@ -243,12 +243,12 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
        init_waitqueue_head(&heap->waitqueue);
        heap->task = kthread_run(ion_heap_deferred_free, heap,
                                 "%s", heap->name);
-       sched_setscheduler(heap->task, SCHED_IDLE, &param);
        if (IS_ERR(heap->task)) {
                pr_err("%s: creating thread for deferred free failed\n",
                       __func__);
                return PTR_RET(heap->task);
        }
+       sched_setscheduler(heap->task, SCHED_IDLE, &param);
        return 0;
 }
 
index d98673981cc40cc83b70db1b5aa9a49a99b4ad35..fc2e4fccf69d216d60761e67775df69f6fd5ea45 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef _ION_PRIV_H
 #define _ION_PRIV_H
 
+#include <linux/device.h>
 #include <linux/dma-direction.h>
 #include <linux/kref.h>
 #include <linux/mm_types.h>
index 7f0729130d6583d776734e9df7a89b234b150065..9849f3963e752f01b99450c7636132fba3aefda5 100644 (file)
@@ -124,6 +124,7 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap,
 
                info->page = page;
                info->order = orders[i];
+               INIT_LIST_HEAD(&info->list);
                return info;
        }
        kfree(info);
@@ -145,12 +146,15 @@ static int ion_system_heap_allocate(struct ion_heap *heap,
        struct list_head pages;
        struct page_info *info, *tmp_info;
        int i = 0;
-       long size_remaining = PAGE_ALIGN(size);
+       unsigned long size_remaining = PAGE_ALIGN(size);
        unsigned int max_order = orders[0];
 
        if (align > PAGE_SIZE)
                return -EINVAL;
 
+       if (size / PAGE_SIZE > totalram_pages / 2)
+               return -ENOMEM;
+
        INIT_LIST_HEAD(&pages);
        while (size_remaining > 0) {
                info = alloc_largest_available(sys_heap, buffer, size_remaining,
index 585040be5f1828916c648f46670b6be182ed2812..5aaf71d6974b16efed469637dcb1ca296b924ebf 100644 (file)
@@ -35,10 +35,27 @@ struct sw_sync_pt {
        u32                     value;
 };
 
+#if IS_ENABLED(CONFIG_SW_SYNC)
 struct sw_sync_timeline *sw_sync_timeline_create(const char *name);
 void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc);
 
 struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value);
+#else
+static inline struct sw_sync_timeline *sw_sync_timeline_create(const char *name)
+{
+       return NULL;
+}
+
+static inline void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc)
+{
+}
+
+static inline struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj,
+               u32 value)
+{
+       return NULL;
+}
+#endif /* IS_ENABLED(CONFIG_SW_SYNC) */
 
 #endif /* __KERNEL __ */
 
index 38e5d3b5ed9b605d7d8c5c6f017bb7d0cffa3ab8..3d05f662110bb0d0d4718ed9a9a8408964eee5b2 100644 (file)
@@ -79,27 +79,27 @@ static void sync_timeline_free(struct kref *kref)
                container_of(kref, struct sync_timeline, kref);
        unsigned long flags;
 
-       if (obj->ops->release_obj)
-               obj->ops->release_obj(obj);
-
        spin_lock_irqsave(&sync_timeline_list_lock, flags);
        list_del(&obj->sync_timeline_list);
        spin_unlock_irqrestore(&sync_timeline_list_lock, flags);
 
+       if (obj->ops->release_obj)
+               obj->ops->release_obj(obj);
+
        kfree(obj);
 }
 
 void sync_timeline_destroy(struct sync_timeline *obj)
 {
        obj->destroyed = true;
+       smp_wmb();
 
        /*
-        * If this is not the last reference, signal any children
-        * that their parent is going away.
+        * signal any children that their parent is going away.
         */
+       sync_timeline_signal(obj);
 
-       if (!kref_put(&obj->kref, sync_timeline_free))
-               sync_timeline_signal(obj);
+       kref_put(&obj->kref, sync_timeline_free);
 }
 EXPORT_SYMBOL(sync_timeline_destroy);
 
index 8dfdd2732bdc329b3865c010d0afdb8e1e248337..95a2358267bad3704d2500287e417735735cdb82 100644 (file)
@@ -40,7 +40,7 @@ static INT bcm_close(struct net_device *dev)
 }
 
 static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb,
-                           void *accel_priv)
+                           void *accel_priv, select_queue_fallback_t fallback)
 {
        return ClassifyPacket(netdev_priv(dev), skb);
 }
index 246080316c9014a91509da617551a20d7eddc4fa..5b15033a94bf6106cc5b26b9da157ba24be60613 100644 (file)
@@ -616,8 +616,6 @@ int comedi_auto_config(struct device *hardware_device,
        ret = driver->auto_attach(dev, context);
        if (ret >= 0)
                ret = comedi_device_postconfig(dev);
-       if (ret < 0)
-               comedi_device_detach(dev);
        mutex_unlock(&dev->mutex);
 
        if (ret < 0) {
index 593676cf706a2cc3a327b3b1ed0daeefb046a5b7..d9ad2c0fdda208bdcfc521e3b35c5e55f18ef971 100644 (file)
@@ -494,6 +494,7 @@ static int pci171x_insn_write_ao(struct comedi_device *dev,
                                 struct comedi_insn *insn, unsigned int *data)
 {
        struct pci1710_private *devpriv = dev->private;
+       unsigned int val;
        int n, chan, range, ofs;
 
        chan = CR_CHAN(insn->chanspec);
@@ -509,11 +510,14 @@ static int pci171x_insn_write_ao(struct comedi_device *dev,
                outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
                ofs = PCI171x_DA1;
        }
+       val = devpriv->ao_data[chan];
 
-       for (n = 0; n < insn->n; n++)
-               outw(data[n], dev->iobase + ofs);
+       for (n = 0; n < insn->n; n++) {
+               val = data[n];
+               outw(val, dev->iobase + ofs);
+       }
 
-       devpriv->ao_data[chan] = data[n];
+       devpriv->ao_data[chan] = val;
 
        return n;
 
@@ -679,6 +683,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev,
                                 struct comedi_insn *insn, unsigned int *data)
 {
        struct pci1710_private *devpriv = dev->private;
+       unsigned int val;
        int n, rangereg, chan;
 
        chan = CR_CHAN(insn->chanspec);
@@ -688,13 +693,15 @@ static int pci1720_insn_write_ao(struct comedi_device *dev,
                outb(rangereg, dev->iobase + PCI1720_RANGE);
                devpriv->da_ranges = rangereg;
        }
+       val = devpriv->ao_data[chan];
 
        for (n = 0; n < insn->n; n++) {
-               outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1));
+               val = data[n];
+               outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
                outb(0, dev->iobase + PCI1720_SYNCOUT); /*  update outputs */
        }
 
-       devpriv->ao_data[chan] = data[n];
+       devpriv->ao_data[chan] = val;
 
        return n;
 }
index 3beeb12541522b2bf8cd04bd898754d3f9365487..88c60b6020c48b971682f2d31700dd549ecdd1af 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/usb.h>
 #include <linux/fcntl.h>
 #include <linux/compiler.h>
+#include <asm/unaligned.h>
 
 #include "comedi_fc.h"
 #include "../comedidev.h"
@@ -792,7 +793,8 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev,
                }
 
                /* 32 bits big endian from the A/D converter */
-               val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf) + 1)));
+               val = be32_to_cpu(get_unaligned((uint32_t
+                                                *)(devpriv->insn_buf + 1)));
                val &= 0x00ffffff;      /* strip status byte */
                val ^= 0x00800000;      /* convert to unsigned */
 
@@ -1357,7 +1359,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan)
                return ret;
 
        /* 32 bits big endian from the A/D converter */
-       val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf)+1)));
+       val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1)));
        val &= 0x00ffffff;      /* strip status byte */
        val ^= 0x00800000;      /* convert to unsigned */
 
index 4a08e16e42f719470cd9a0b63de557d2b3ff704b..79206cb3fb946e785021607c7b12474bff9d73a5 100644 (file)
@@ -866,6 +866,8 @@ c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd)
             _IOC_SIZE (iocmd));
 #endif
     iolen = _IOC_SIZE (iocmd);
+    if (iolen > sizeof(arg))
+        return -EFAULT;
     data = ifr->ifr_data + sizeof (iocmd);
     if (copy_from_user (&arg, data, iolen))
         return -EFAULT;
index 1f61b89eca44c084cb714052d5eb3fb3a7ba2566..33ac7fb88cbd3b98b24b1eb50209e4a0b5c6100e 100644 (file)
@@ -2232,177 +2232,6 @@ done:
        return rtn;
 }
 
-/*
- * Common Packet Handling code
- */
-
-static void handle_data_in_packet(struct nd_struct *nd, struct ch_struct *ch,
-                                 long dlen, long plen, int n1, u8 *dbuf)
-{
-       char *error;
-       long n;
-       long remain;
-       u8 *buf;
-       u8 *b;
-
-       remain = nd->nd_remain;
-       nd->nd_tx_work = 1;
-
-       /*
-        *  Otherwise data should appear only when we are
-        *  in the CS_READY state.
-        */
-
-       if (ch->ch_state < CS_READY) {
-               error = "Data received before RWIN established";
-               nd->nd_remain = 0;
-               nd->nd_state = NS_SEND_ERROR;
-               nd->nd_error = error;
-       }
-
-       /*
-        *  Assure that the data received is within the
-        *  allowable window.
-        */
-
-       n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff;
-
-       if (dlen > n) {
-               error = "Receive data overrun";
-               nd->nd_remain = 0;
-               nd->nd_state = NS_SEND_ERROR;
-               nd->nd_error = error;
-       }
-
-       /*
-        *  If we received 3 or less characters,
-        *  assume it is a human typing, and set RTIME
-        *  to 10 milliseconds.
-        *
-        *  If we receive 10 or more characters,
-        *  assume its not a human typing, and set RTIME
-        *  to 100 milliseconds.
-        */
-
-       if (ch->ch_edelay != DGRP_RTIME) {
-               if (ch->ch_rtime != ch->ch_edelay) {
-                       ch->ch_rtime = ch->ch_edelay;
-                       ch->ch_flag |= CH_PARAM;
-               }
-       } else if (dlen <= 3) {
-               if (ch->ch_rtime != 10) {
-                       ch->ch_rtime = 10;
-                       ch->ch_flag |= CH_PARAM;
-               }
-       } else {
-               if (ch->ch_rtime != DGRP_RTIME) {
-                       ch->ch_rtime = DGRP_RTIME;
-                       ch->ch_flag |= CH_PARAM;
-               }
-       }
-
-       /*
-        *  If a portion of the packet is outside the
-        *  buffer, shorten the effective length of the
-        *  data packet to be the amount of data received.
-        */
-
-       if (remain < plen)
-               dlen -= plen - remain;
-
-       /*
-        *  Detect if receive flush is now complete.
-        */
-
-       if ((ch->ch_flag & CH_RX_FLUSH) != 0 &&
-                       ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >=
-                       ((nd->nd_seq_in    - nd->nd_seq_out) & SEQ_MASK)) {
-               ch->ch_flag &= ~CH_RX_FLUSH;
-       }
-
-       /*
-        *  If we are ready to receive, move the data into
-        *  the receive buffer.
-        */
-
-       ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff;
-
-       if (ch->ch_state == CS_READY &&
-                       (ch->ch_tun.un_open_count != 0) &&
-                       (ch->ch_tun.un_flag & UN_CLOSING) == 0 &&
-                       (ch->ch_cflag & CF_CREAD) != 0 &&
-                       (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 &&
-                       (ch->ch_send & RR_RX_FLUSH) == 0) {
-
-               if (ch->ch_rin + dlen >= RBUF_MAX) {
-                       n = RBUF_MAX - ch->ch_rin;
-
-                       memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n);
-
-                       ch->ch_rin = 0;
-                       dbuf += n;
-                       dlen -= n;
-               }
-
-               memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen);
-
-               ch->ch_rin += dlen;
-
-
-               /*
-                *  If we are not in fastcook mode, or
-                *  if there is a fastcook thread
-                *  waiting for data, send the data to
-                *  the line discipline.
-                */
-
-               if ((ch->ch_flag & CH_FAST_READ) == 0 ||
-                               ch->ch_inwait != 0) {
-                       dgrp_input(ch);
-               }
-
-               /*
-                *  If there is a read thread waiting
-                *  in select, and we are in fastcook
-                *  mode, wake him up.
-                */
-
-               if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) &&
-                               (ch->ch_flag & CH_FAST_READ) != 0)
-                       wake_up_interruptible(&ch->ch_tun.un_tty->read_wait);
-
-               /*
-                * Wake any thread waiting in the
-                * fastcook loop.
-                */
-
-               if ((ch->ch_flag & CH_INPUT) != 0) {
-                       ch->ch_flag &= ~CH_INPUT;
-                       wake_up_interruptible(&ch->ch_flag_wait);
-               }
-       }
-
-       /*
-        *  Fabricate and insert a data packet header to
-        *  preced the remaining data when it comes in.
-        */
-
-       if (remain < plen) {
-               dlen = plen - remain;
-               b = buf;
-
-               b[0] = 0x90 + n1;
-               put_unaligned_be16(dlen, b + 1);
-
-               remain = 3;
-               if (remain > 0 && b != buf)
-                       memcpy(buf, b, remain);
-
-               nd->nd_remain = remain;
-               return;
-       }
-}
-
 /**
  * dgrp_receive() -- decode data packets received from the remote PortServer.
  * @nd: pointer to a node structure
@@ -2477,8 +2306,7 @@ static void dgrp_receive(struct nd_struct *nd)
                        plen = dlen + 1;
 
                        dbuf = b + 1;
-                       handle_data_in_packet(nd, ch, dlen, plen, n1, dbuf);
-                       break;
+                       goto data;
 
                /*
                 *  Process 2-byte header data packet.
@@ -2492,8 +2320,7 @@ static void dgrp_receive(struct nd_struct *nd)
                        plen = dlen + 2;
 
                        dbuf = b + 2;
-                       handle_data_in_packet(nd, ch, dlen, plen, n1, dbuf);
-                       break;
+                       goto data;
 
                /*
                 *  Process 3-byte header data packet.
@@ -2508,6 +2335,159 @@ static void dgrp_receive(struct nd_struct *nd)
 
                        dbuf = b + 3;
 
+               /*
+                *  Common packet handling code.
+                */
+
+data:
+                       nd->nd_tx_work = 1;
+
+                       /*
+                        *  Otherwise data should appear only when we are
+                        *  in the CS_READY state.
+                        */
+
+                       if (ch->ch_state < CS_READY) {
+                               error = "Data received before RWIN established";
+                               goto prot_error;
+                       }
+
+                       /*
+                        *  Assure that the data received is within the
+                        *  allowable window.
+                        */
+
+                       n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff;
+
+                       if (dlen > n) {
+                               error = "Receive data overrun";
+                               goto prot_error;
+                       }
+
+                       /*
+                        *  If we received 3 or less characters,
+                        *  assume it is a human typing, and set RTIME
+                        *  to 10 milliseconds.
+                        *
+                        *  If we receive 10 or more characters,
+                        *  assume its not a human typing, and set RTIME
+                        *  to 100 milliseconds.
+                        */
+
+                       if (ch->ch_edelay != DGRP_RTIME) {
+                               if (ch->ch_rtime != ch->ch_edelay) {
+                                       ch->ch_rtime = ch->ch_edelay;
+                                       ch->ch_flag |= CH_PARAM;
+                               }
+                       } else if (dlen <= 3) {
+                               if (ch->ch_rtime != 10) {
+                                       ch->ch_rtime = 10;
+                                       ch->ch_flag |= CH_PARAM;
+                               }
+                       } else {
+                               if (ch->ch_rtime != DGRP_RTIME) {
+                                       ch->ch_rtime = DGRP_RTIME;
+                                       ch->ch_flag |= CH_PARAM;
+                               }
+                       }
+
+                       /*
+                        *  If a portion of the packet is outside the
+                        *  buffer, shorten the effective length of the
+                        *  data packet to be the amount of data received.
+                        */
+
+                       if (remain < plen)
+                               dlen -= plen - remain;
+
+                       /*
+                        *  Detect if receive flush is now complete.
+                        */
+
+                       if ((ch->ch_flag & CH_RX_FLUSH) != 0 &&
+                           ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >=
+                           ((nd->nd_seq_in    - nd->nd_seq_out) & SEQ_MASK)) {
+                               ch->ch_flag &= ~CH_RX_FLUSH;
+                       }
+
+                       /*
+                        *  If we are ready to receive, move the data into
+                        *  the receive buffer.
+                        */
+
+                       ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff;
+
+                       if (ch->ch_state == CS_READY &&
+                           (ch->ch_tun.un_open_count != 0) &&
+                           (ch->ch_tun.un_flag & UN_CLOSING) == 0 &&
+                           (ch->ch_cflag & CF_CREAD) != 0 &&
+                           (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 &&
+                           (ch->ch_send & RR_RX_FLUSH) == 0) {
+
+                               if (ch->ch_rin + dlen >= RBUF_MAX) {
+                                       n = RBUF_MAX - ch->ch_rin;
+
+                                       memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n);
+
+                                       ch->ch_rin = 0;
+                                       dbuf += n;
+                                       dlen -= n;
+                               }
+
+                               memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen);
+
+                               ch->ch_rin += dlen;
+
+
+                               /*
+                                *  If we are not in fastcook mode, or
+                                *  if there is a fastcook thread
+                                *  waiting for data, send the data to
+                                *  the line discipline.
+                                */
+
+                               if ((ch->ch_flag & CH_FAST_READ) == 0 ||
+                                   ch->ch_inwait != 0) {
+                                       dgrp_input(ch);
+                               }
+
+                               /*
+                                *  If there is a read thread waiting
+                                *  in select, and we are in fastcook
+                                *  mode, wake him up.
+                                */
+
+                               if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) &&
+                                   (ch->ch_flag & CH_FAST_READ) != 0)
+                                       wake_up_interruptible(&ch->ch_tun.un_tty->read_wait);
+
+                               /*
+                                * Wake any thread waiting in the
+                                * fastcook loop.
+                                */
+
+                               if ((ch->ch_flag & CH_INPUT) != 0) {
+                                       ch->ch_flag &= ~CH_INPUT;
+
+                                       wake_up_interruptible(&ch->ch_flag_wait);
+                               }
+                       }
+
+                       /*
+                        *  Fabricate and insert a data packet header to
+                        *  preced the remaining data when it comes in.
+                        */
+
+                       if (remain < plen) {
+                               dlen = plen - remain;
+                               b = buf;
+
+                               b[0] = 0x90 + n1;
+                               put_unaligned_be16(dlen, b + 1);
+
+                               remain = 3;
+                               goto done;
+                       }
                        break;
 
                /*
index f8788bf0a7d39ed02c284a4f5cb8ea51c8dbae98..cdeffe75496b2531f106c044105f686d5f1c2018 100644 (file)
@@ -635,11 +635,14 @@ static int gdm_usb_probe(struct usb_interface *intf,
 #endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
 
        ret = register_wimax_device(phy_dev, &intf->dev);
+       if (ret)
+               release_usb(udev);
 
 out:
        if (ret) {
                kfree(phy_dev);
                kfree(udev);
+               usb_put_dev(usbdev);
        } else {
                usb_set_intfdata(intf, phy_dev);
        }
index 35154d60faf6120813bb26bf2477994e66fd259f..c9fedb79e3a2d2cec92f04a7860c6e2c055bd0fc 100644 (file)
@@ -77,7 +77,6 @@ struct iio_channel_info {
        uint64_t mask;
        unsigned be;
        unsigned is_signed;
-       unsigned enabled;
        unsigned location;
 };
 
@@ -335,6 +334,7 @@ inline int build_channel_array(const char *device_dir,
        while (ent = readdir(dp), ent != NULL) {
                if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
                           "_en") == 0) {
+                       int current_enabled = 0;
                        current = &(*ci_array)[count++];
                        ret = asprintf(&filename,
                                       "%s/%s", scan_el_dir, ent->d_name);
@@ -350,10 +350,10 @@ inline int build_channel_array(const char *device_dir,
                                ret = -errno;
                                goto error_cleanup_array;
                        }
-                       fscanf(sysfsfp, "%u", &current->enabled);
+                       fscanf(sysfsfp, "%u", &current_enabled);
                        fclose(sysfsfp);
 
-                       if (!current->enabled) {
+                       if (!current_enabled) {
                                free(filename);
                                count--;
                                continue;
index 5ea36410f716e7cb380f60bfbfee83dfde160d52..5708ffc62aec94debe2c9a6aa8b6562f6a40623f 100644 (file)
@@ -393,7 +393,7 @@ static const struct iio_event_spec ad799x_events[] = {
        }, {
                .type = IIO_EV_TYPE_THRESH,
                .dir = IIO_EV_DIR_FALLING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
                        BIT(IIO_EV_INFO_ENABLE),
        }, {
                .type = IIO_EV_TYPE_THRESH,
@@ -409,7 +409,13 @@ static const struct iio_event_spec ad799x_events[] = {
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
        .scan_index = (_index), \
-       .scan_type = IIO_ST('u', _realbits, 16, 12 - (_realbits)), \
+       .scan_type = { \
+               .sign = 'u', \
+               .realbits = (_realbits), \
+               .storagebits = 16, \
+               .shift = 12 - (_realbits), \
+               .endianness = IIO_BE, \
+       }, \
        .event_spec = _ev_spec, \
        .num_event_specs = _num_ev_spec, \
 }
@@ -588,7 +594,8 @@ static int ad799x_probe(struct i2c_client *client,
        return 0;
 
 error_free_irq:
-       free_irq(client->irq, indio_dev);
+       if (client->irq > 0)
+               free_irq(client->irq, indio_dev);
 error_cleanup_ring:
        ad799x_ring_cleanup(indio_dev);
 error_disable_reg:
index df71669bb60ea51be793903d7a62df399e388c55..514844efac75833252f25891d591dad1d844092c 100644 (file)
@@ -757,6 +757,7 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid)
        }
 
        /* if it is released, wait for the next touch via IRQ */
+       lradc->cur_plate = LRADC_TOUCH;
        mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1);
        mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1);
 }
@@ -1035,8 +1036,6 @@ SHOW_SCALE_AVAILABLE_ATTR(4);
 SHOW_SCALE_AVAILABLE_ATTR(5);
 SHOW_SCALE_AVAILABLE_ATTR(6);
 SHOW_SCALE_AVAILABLE_ATTR(7);
-SHOW_SCALE_AVAILABLE_ATTR(8);
-SHOW_SCALE_AVAILABLE_ATTR(9);
 SHOW_SCALE_AVAILABLE_ATTR(10);
 SHOW_SCALE_AVAILABLE_ATTR(11);
 SHOW_SCALE_AVAILABLE_ATTR(12);
@@ -1053,8 +1052,6 @@ static struct attribute *mxs_lradc_attributes[] = {
        &iio_dev_attr_in_voltage5_scale_available.dev_attr.attr,
        &iio_dev_attr_in_voltage6_scale_available.dev_attr.attr,
        &iio_dev_attr_in_voltage7_scale_available.dev_attr.attr,
-       &iio_dev_attr_in_voltage8_scale_available.dev_attr.attr,
-       &iio_dev_attr_in_voltage9_scale_available.dev_attr.attr,
        &iio_dev_attr_in_voltage10_scale_available.dev_attr.attr,
        &iio_dev_attr_in_voltage11_scale_available.dev_attr.attr,
        &iio_dev_attr_in_voltage12_scale_available.dev_attr.attr,
@@ -1613,7 +1610,7 @@ static int mxs_lradc_probe(struct platform_device *pdev)
                         * of the array.
                         */
                        scale_uv = ((u64)lradc->vref_mv[i] * 100000000) >>
-                                  (iio->channels[i].scan_type.realbits - s);
+                                  (LRADC_RESOLUTION - s);
                        lradc->scale_avail[i][s].nano =
                                        do_div(scale_uv, 100000000) * 10;
                        lradc->scale_avail[i][s].integer = scale_uv;
index 0a4298b744e6e686f8bdef9175d06666c1b5cf49..2b96665da8a25aa0390462897d777039a6ff2c9e 100644 (file)
@@ -629,7 +629,7 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
        struct iio_buffer *buffer;
 
        buffer = iio_kfifo_allocate(indio_dev);
-       if (buffer)
+       if (!buffer)
                return -ENOMEM;
 
        iio_device_attach_buffer(indio_dev, buffer);
index 09ef5fb8bae6f9cb4b99f936b2fcb52739f9edd9..236ed66f116a29fda3af7fc6764b506cacbef16a 100644 (file)
@@ -88,9 +88,9 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
        imx_drm_device_put();
 
-       drm_vblank_cleanup(imxdrm->drm);
-       drm_kms_helper_poll_fini(imxdrm->drm);
-       drm_mode_config_cleanup(imxdrm->drm);
+       drm_vblank_cleanup(drm);
+       drm_kms_helper_poll_fini(drm);
+       drm_mode_config_cleanup(drm);
 
        return 0;
 }
@@ -142,19 +142,19 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
-       return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+       return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
 
 void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
 {
-       drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+       drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
 
 void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
 {
-       drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+       drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
 
@@ -369,29 +369,6 @@ static void imx_drm_connector_unregister(
        drm_mode_group_reinit(imxdrm->drm);
 }
 
-/*
- * register a crtc to the drm core
- */
-static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
-{
-       struct imx_drm_device *imxdrm = __imx_drm_device();
-       int ret;
-
-       ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
-       if (ret)
-               return ret;
-
-       drm_crtc_helper_add(imx_drm_crtc->crtc,
-                       imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
-
-       drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
-                       imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
-
-       drm_mode_group_reinit(imxdrm->drm);
-
-       return 0;
-}
-
 /*
  * Called by the CRTC driver when all CRTCs are registered. This
  * puts all the pieces together and initializes the driver.
@@ -424,15 +401,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
        mutex_lock(&imxdrm->mutex);
 
-       drm_kms_helper_poll_init(imxdrm->drm);
+       drm_kms_helper_poll_init(drm);
 
        /* setup the grouping for the legacy output */
-       ret = drm_mode_group_init_legacy_group(imxdrm->drm,
-                       &imxdrm->drm->primary->mode_group);
+       ret = drm_mode_group_init_legacy_group(drm,
+                       &drm->primary->mode_group);
        if (ret)
                goto err_kms;
 
-       ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+       ret = drm_vblank_init(drm, MAX_CRTC);
        if (ret)
                goto err_kms;
 
@@ -441,7 +418,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
         * by drm timer once a current process gives up ownership of
         * vblank event.(after drm_vblank_put function is called)
         */
-       imxdrm->drm->vblank_disable_allowed = true;
+       drm->vblank_disable_allowed = true;
 
        if (!imx_drm_device_get()) {
                ret = -EINVAL;
@@ -536,10 +513,18 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 
        *new_crtc = imx_drm_crtc;
 
-       ret = imx_drm_crtc_register(imx_drm_crtc);
+       ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
        if (ret)
                goto err_register;
 
+       drm_crtc_helper_add(crtc,
+                       imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+       drm_crtc_init(imxdrm->drm, crtc,
+                       imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+
+       drm_mode_group_reinit(imxdrm->drm);
+
        imx_drm_update_possible_crtcs();
 
        mutex_unlock(&imxdrm->mutex);
index f3a1f5e2e492a465d9f3a85d6e981ba3c594489d..62ce0e86f14b50cfe7392bc5b47dd8871616af2b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/hdmi.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
@@ -52,11 +53,6 @@ enum hdmi_datamap {
        YCbCr422_12B = 0x12,
 };
 
-enum hdmi_colorimetry {
-       ITU601,
-       ITU709,
-};
-
 enum imx_hdmi_devtype {
        IMX6Q_HDMI,
        IMX6DL_HDMI,
@@ -489,12 +485,12 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 
        if (is_color_space_conversion(hdmi)) {
                if (hdmi->hdmi_data.enc_out_format == RGB) {
-                       if (hdmi->hdmi_data.colorimetry == ITU601)
+                       if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
                                csc_coeff = &csc_coeff_rgb_out_eitu601;
                        else
                                csc_coeff = &csc_coeff_rgb_out_eitu709;
                } else if (hdmi->hdmi_data.enc_in_format == RGB) {
-                       if (hdmi->hdmi_data.colorimetry == ITU601)
+                       if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
                                csc_coeff = &csc_coeff_rgb_in_eitu601;
                        else
                                csc_coeff = &csc_coeff_rgb_in_eitu709;
@@ -1140,16 +1136,16 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi)
        /* Set up colorimetry */
        if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
                colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
-               if (hdmi->hdmi_data.colorimetry == ITU601)
+               if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
                        ext_colorimetry =
                                HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
-               else /* hdmi->hdmi_data.colorimetry == ITU709 */
+               else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
                        ext_colorimetry =
                                HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
        } else if (hdmi->hdmi_data.enc_out_format != RGB) {
-               if (hdmi->hdmi_data.colorimetry == ITU601)
+               if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
                        colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
-               else /* hdmi->hdmi_data.colorimetry == ITU709 */
+               else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
                        colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
                ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
        } else { /* Carries no data */
@@ -1379,9 +1375,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
                (hdmi->vic == 21) || (hdmi->vic == 22) ||
                (hdmi->vic == 2) || (hdmi->vic == 3) ||
                (hdmi->vic == 17) || (hdmi->vic == 18))
-               hdmi->hdmi_data.colorimetry = ITU601;
+               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
        else
-               hdmi->hdmi_data.colorimetry = ITU709;
+               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
 
        if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
                (hdmi->vic == 12) || (hdmi->vic == 13) ||
index 22742d6d62a8012692c62749024b242e67e3d21d..0a2b6cb3775ee3001d4edc56d312527b6f468a8e 100644 (file)
@@ -9,5 +9,6 @@
 * Other minor misc cleanups...
 
 Please send any patches to Greg Kroah-Hartman <greg@kroah.com>, Andreas Dilger
-<andreas.dilger@intel.com> and Peng Tao <tao.peng@emc.com>. CCing
-hpdd-discuss <hpdd-discuss@lists.01.org> would be great too.
+<andreas.dilger@intel.com>, Oleg Drokin <oleg.drokin@intel.com> and
+Peng Tao <tao.peng@emc.com>. CCing hpdd-discuss <hpdd-discuss@lists.01.org>
+would be great too.
index 596a15fc899676709adf21fa437c91f53284bb17..037ae8a6d5319ee230fb9cb5de131b115db2cf43 100644 (file)
@@ -61,6 +61,8 @@ struct kuc_hdr {
        __u16 kuc_msglen;     /* Including header */
 } __attribute__((aligned(sizeof(__u64))));
 
+#define KUC_CHANGELOG_MSG_MAXSIZE (sizeof(struct kuc_hdr)+CR_MAXSIZE)
+
 #define KUC_MAGIC  0x191C /*Lustre9etLinC */
 #define KUC_FL_BLOCK 0x01   /* Wait for send */
 
index d0d942ced01a57c804efdfa712fa62977678c911..dddccca120c90be3a5d4a366b1a55caabe873971 100644 (file)
@@ -120,7 +120,7 @@ do {                                                \
 do {                                                                       \
        LASSERT(!in_interrupt() ||                                          \
                ((size) <= LIBCFS_VMALLOC_SIZE &&                           \
-                ((mask) & GFP_ATOMIC)) != 0);                      \
+                ((mask) & __GFP_WAIT) == 0));                              \
 } while (0)
 
 #define LIBCFS_ALLOC_POST(ptr, size)                                       \
index 93648632ba26f7fd0ab2390cbe5f427040393bcd..6f58ead2039343d1257381d5dcf05faff433044c 100644 (file)
@@ -529,7 +529,7 @@ kiblnd_kvaddr_to_page (unsigned long vaddr)
 {
        struct page *page;
 
-       if (is_vmalloc_addr(vaddr)) {
+       if (is_vmalloc_addr((void *)vaddr)) {
                page = vmalloc_to_page ((void *)vaddr);
                LASSERT (page != NULL);
                return page;
index 68a4f52ec998c14795d6f356e807b798c2dfa794..b7b53b579c8524abf460898212264b716ba0aac2 100644 (file)
@@ -924,7 +924,7 @@ ksocknal_launch_packet (lnet_ni_t *ni, ksock_tx_t *tx, lnet_process_id_t id)
 int
 ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
 {
-       int            mpflag = 0;
+       int            mpflag = 1;
        int            type = lntmsg->msg_type;
        lnet_process_id_t target = lntmsg->msg_target;
        unsigned int      payload_niov = lntmsg->msg_niov;
@@ -993,8 +993,9 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
 
        /* The first fragment will be set later in pro_pack */
        rc = ksocknal_launch_packet(ni, tx, target);
-       if (lntmsg->msg_vmflush)
+       if (!mpflag)
                cfs_memory_pressure_restore(mpflag);
+
        if (rc == 0)
                return (0);
 
index 6b6c0240e8243010f6bf5d20809b8667c70ebc39..7893d83e131ffcf451b584b0556c0685216bf0dd 100644 (file)
@@ -760,7 +760,8 @@ static inline void hsm_set_cl_error(int *flags, int error)
        *flags |= (error << CLF_HSM_ERR_L);
 }
 
-#define CR_MAXSIZE cfs_size_round(2*NAME_MAX + 1 + sizeof(struct changelog_rec))
+#define CR_MAXSIZE cfs_size_round(2*NAME_MAX + 1 + \
+                                 sizeof(struct changelog_ext_rec))
 
 struct changelog_rec {
        __u16            cr_namelen;
index 22d0acc95bc57f9e5c52f1ff62a42a39f4ea6079..52b7731bcc38679b0e4b6f1360c8a3baf7c76ac4 100644 (file)
@@ -1086,7 +1086,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
                break;
        case Q_GETQUOTA:
                if (((type == USRQUOTA &&
-                     uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
+                     !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
                     (type == GRPQUOTA &&
                      !in_egroup_p(make_kgid(&init_user_ns, id)))) &&
                    (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
index d1ad91c34ddcdad89ece9f1b4f21639b34dda9a4..83013927e13152d8b414dc715ec19df49f827dac 100644 (file)
@@ -1430,7 +1430,7 @@ static struct kuc_hdr *changelog_kuc_hdr(char *buf, int len, int flags)
 {
        struct kuc_hdr *lh = (struct kuc_hdr *)buf;
 
-       LASSERT(len <= CR_MAXSIZE);
+       LASSERT(len <= KUC_CHANGELOG_MSG_MAXSIZE);
 
        lh->kuc_magic = KUC_MAGIC;
        lh->kuc_transport = KUC_TRANSPORT_CHANGELOG;
@@ -1503,7 +1503,7 @@ static int mdc_changelog_send_thread(void *csdata)
        CDEBUG(D_CHANGELOG, "changelog to fp=%p start "LPU64"\n",
               cs->cs_fp, cs->cs_startrec);
 
-       OBD_ALLOC(cs->cs_buf, CR_MAXSIZE);
+       OBD_ALLOC(cs->cs_buf, KUC_CHANGELOG_MSG_MAXSIZE);
        if (cs->cs_buf == NULL)
                GOTO(out, rc = -ENOMEM);
 
@@ -1540,7 +1540,7 @@ out:
        if (ctxt)
                llog_ctxt_put(ctxt);
        if (cs->cs_buf)
-               OBD_FREE(cs->cs_buf, CR_MAXSIZE);
+               OBD_FREE(cs->cs_buf, KUC_CHANGELOG_MSG_MAXSIZE);
        OBD_FREE_PTR(cs);
        return rc;
 }
index eedffed17e391d3243443c443ff9338bf494c440..31b269a5fff768bb7fff82edfca35ead48c93fe7 100644 (file)
@@ -307,7 +307,7 @@ static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb,
 }
 
 static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb,
-                               void *accel_priv)
+                               void *accel_priv, select_queue_fallback_t fallback)
 {
        return (u16)smp_processor_id();
 }
@@ -892,6 +892,11 @@ static int xlr_setup_mdio(struct xlr_net_priv *priv,
        priv->mii_bus->write = xlr_mii_write;
        priv->mii_bus->parent = &pdev->dev;
        priv->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+       if (priv->mii_bus->irq == NULL) {
+               pr_err("irq alloc failed\n");
+               mdiobus_free(priv->mii_bus);
+               return -ENOMEM;
+       }
        priv->mii_bus->irq[priv->phy_addr] = priv->ndev->irq;
 
        /* Scan only the enabled address */
index 47e0a91238a107da2db14ab873685c582dcb59b9..5a001d9b425295eb8079a66c38c16baf8f36db7c 100644 (file)
@@ -275,13 +275,6 @@ enum cvmx_usb_pipe_flags {
  */
 #define MAX_TRANSFER_PACKETS   ((1<<10)-1)
 
-enum {
-       USB_CLOCK_TYPE_REF_12,
-       USB_CLOCK_TYPE_REF_24,
-       USB_CLOCK_TYPE_REF_48,
-       USB_CLOCK_TYPE_CRYSTAL_12,
-};
-
 /**
  * Logical transactions may take numerous low level
  * transactions, especially when splits are concerned. This
@@ -471,19 +464,6 @@ struct octeon_hcd {
 /* Returns the IO address to push/pop stuff data from the FIFOs */
 #define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
 
-static int octeon_usb_get_clock_type(void)
-{
-       switch (cvmx_sysinfo_get()->board_type) {
-       case CVMX_BOARD_TYPE_BBGW_REF:
-       case CVMX_BOARD_TYPE_LANAI2_A:
-       case CVMX_BOARD_TYPE_LANAI2_U:
-       case CVMX_BOARD_TYPE_LANAI2_G:
-       case CVMX_BOARD_TYPE_UBNT_E100:
-               return USB_CLOCK_TYPE_CRYSTAL_12;
-       }
-       return USB_CLOCK_TYPE_REF_48;
-}
-
 /**
  * Read a USB 32bit CSR. It performs the necessary address swizzle
  * for 32bit CSRs and logs the value in a readable format if
@@ -582,37 +562,6 @@ static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
                return 0; /* Data0 */
 }
 
-
-/**
- * Return the number of USB ports supported by this Octeon
- * chip. If the chip doesn't support USB, or is not supported
- * by this API, a zero will be returned. Most Octeon chips
- * support one usb port, but some support two ports.
- * cvmx_usb_initialize() must be called on independent
- * struct cvmx_usb_state.
- *
- * Returns: Number of port, zero if usb isn't supported
- */
-static int cvmx_usb_get_num_ports(void)
-{
-       int arch_ports = 0;
-
-       if (OCTEON_IS_MODEL(OCTEON_CN56XX))
-               arch_ports = 1;
-       else if (OCTEON_IS_MODEL(OCTEON_CN52XX))
-               arch_ports = 2;
-       else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
-               arch_ports = 1;
-       else if (OCTEON_IS_MODEL(OCTEON_CN31XX))
-               arch_ports = 1;
-       else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
-               arch_ports = 1;
-       else
-               arch_ports = 0;
-
-       return arch_ports;
-}
-
 /**
  * Initialize a USB port for use. This must be called before any
  * other access to the Octeon USB port is made. The port starts
@@ -628,41 +577,16 @@ static int cvmx_usb_get_num_ports(void)
  * Returns: 0 or a negative error code.
  */
 static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
-                              int usb_port_number)
+                              int usb_port_number,
+                              enum cvmx_usb_initialize_flags flags)
 {
        union cvmx_usbnx_clk_ctl usbn_clk_ctl;
        union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status;
-       enum cvmx_usb_initialize_flags flags = 0;
        int i;
 
        /* At first allow 0-1 for the usb port number */
        if ((usb_port_number < 0) || (usb_port_number > 1))
                return -EINVAL;
-       /* For all chips except 52XX there is only one port */
-       if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0))
-               return -EINVAL;
-       /* Try to determine clock type automatically */
-       if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12) {
-               /* Only 12 MHZ crystals are supported */
-               flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;
-       } else {
-               flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
-
-               switch (octeon_usb_get_clock_type()) {
-               case USB_CLOCK_TYPE_REF_12:
-                       flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
-                       break;
-               case USB_CLOCK_TYPE_REF_24:
-                       flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
-                       break;
-               case USB_CLOCK_TYPE_REF_48:
-                       flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
-                       break;
-               default:
-                       return -EINVAL;
-                       break;
-               }
-       }
 
        memset(usb, 0, sizeof(*usb));
        usb->init_flags = flags;
@@ -3431,7 +3355,6 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        return 0;
 }
 
-
 static const struct hc_driver octeon_hc_driver = {
        .description            = "Octeon USB",
        .product_desc           = "Octeon Host Controller",
@@ -3448,15 +3371,74 @@ static const struct hc_driver octeon_hc_driver = {
        .hub_control            = octeon_usb_hub_control,
 };
 
-
-static int octeon_usb_driver_probe(struct device *dev)
+static int octeon_usb_probe(struct platform_device *pdev)
 {
        int status;
-       int usb_num = to_platform_device(dev)->id;
-       int irq = platform_get_irq(to_platform_device(dev), 0);
+       int initialize_flags;
+       int usb_num;
+       struct resource *res_mem;
+       struct device_node *usbn_node;
+       int irq = platform_get_irq(pdev, 0);
+       struct device *dev = &pdev->dev;
        struct octeon_hcd *priv;
        struct usb_hcd *hcd;
        unsigned long flags;
+       u32 clock_rate = 48000000;
+       bool is_crystal_clock = false;
+       const char *clock_type;
+       int i;
+
+       if (dev->of_node == NULL) {
+               dev_err(dev, "Error: empty of_node\n");
+               return -ENXIO;
+       }
+       usbn_node = dev->of_node->parent;
+
+       i = of_property_read_u32(usbn_node,
+                                "refclk-frequency", &clock_rate);
+       if (i) {
+               dev_err(dev, "No USBN \"refclk-frequency\"\n");
+               return -ENXIO;
+       }
+       switch (clock_rate) {
+       case 12000000:
+               initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ;
+               break;
+       case 24000000:
+               initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ;
+               break;
+       case 48000000:
+               initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
+               break;
+       default:
+               dev_err(dev, "Illebal USBN \"refclk-frequency\" %u\n", clock_rate);
+               return -ENXIO;
+
+       }
+
+       i = of_property_read_string(usbn_node,
+                                   "refclk-type", &clock_type);
+
+       if (!i && strcmp("crystal", clock_type) == 0)
+               is_crystal_clock = true;
+
+       if (is_crystal_clock)
+               initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI;
+       else
+               initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem == NULL) {
+               dev_err(dev, "found no memory resource\n");
+               return -ENXIO;
+       }
+       usb_num = (res_mem->start >> 44) & 1;
+
+       if (irq < 0) {
+               /* Defective device tree, but we know how to fix it. */
+               irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56;
+               irq = irq_create_mapping(NULL, hwirq);
+       }
 
        /*
         * Set the DMA mask to 64bits so we get buffers already translated for
@@ -3465,6 +3447,26 @@ static int octeon_usb_driver_probe(struct device *dev)
        dev->coherent_dma_mask = ~0;
        dev->dma_mask = &dev->coherent_dma_mask;
 
+       /*
+        * Only cn52XX and cn56XX have DWC_OTG USB hardware and the
+        * IOB priority registers.  Under heavy network load USB
+        * hardware can be starved by the IOB causing a crash.  Give
+        * it a priority boost if it has been waiting more than 400
+        * cycles to avoid this situation.
+        *
+        * Testing indicates that a cnt_val of 8192 is not sufficient,
+        * but no failures are seen with 4096.  We choose a value of
+        * 400 to give a safety factor of 10.
+        */
+       if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
+               union cvmx_iob_n2c_l2c_pri_cnt pri_cnt;
+
+               pri_cnt.u64 = 0;
+               pri_cnt.s.cnt_enb = 1;
+               pri_cnt.s.cnt_val = 400;
+               cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64);
+       }
+
        hcd = usb_create_hcd(&octeon_hc_driver, dev, dev_name(dev));
        if (!hcd) {
                dev_dbg(dev, "Failed to allocate memory for HCD\n");
@@ -3478,7 +3480,7 @@ static int octeon_usb_driver_probe(struct device *dev)
        tasklet_init(&priv->dequeue_tasklet, octeon_usb_urb_dequeue_work, (unsigned long)priv);
        INIT_LIST_HEAD(&priv->dequeue_list);
 
-       status = cvmx_usb_initialize(&priv->usb, usb_num);
+       status = cvmx_usb_initialize(&priv->usb, usb_num, initialize_flags);
        if (status) {
                dev_dbg(dev, "USB initialization failed with %d\n", status);
                kfree(hcd);
@@ -3492,7 +3494,7 @@ static int octeon_usb_driver_probe(struct device *dev)
        cvmx_usb_poll(&priv->usb);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       status = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       status = usb_add_hcd(hcd, irq, 0);
        if (status) {
                dev_dbg(dev, "USB add HCD failed with %d\n", status);
                kfree(hcd);
@@ -3500,14 +3502,15 @@ static int octeon_usb_driver_probe(struct device *dev)
        }
        device_wakeup_enable(hcd->self.controller);
 
-       dev_dbg(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq);
+       dev_info(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq);
 
        return 0;
 }
 
-static int octeon_usb_driver_remove(struct device *dev)
+static int octeon_usb_remove(struct platform_device *pdev)
 {
        int status;
+       struct device *dev = &pdev->dev;
        struct usb_hcd *hcd = dev_get_drvdata(dev);
        struct octeon_hcd *priv = hcd_to_octeon(hcd);
        unsigned long flags;
@@ -3525,85 +3528,41 @@ static int octeon_usb_driver_remove(struct device *dev)
        return 0;
 }
 
-static struct device_driver octeon_usb_driver = {
-       .name   = "OcteonUSB",
-       .bus    = &platform_bus_type,
-       .probe  = octeon_usb_driver_probe,
-       .remove = octeon_usb_driver_remove,
+static struct of_device_id octeon_usb_match[] = {
+       {
+               .compatible = "cavium,octeon-5750-usbc",
+       },
+       {},
 };
 
+static struct platform_driver octeon_usb_driver = {
+       .driver = {
+               .name       = "OcteonUSB",
+               .owner          = THIS_MODULE,
+               .of_match_table = octeon_usb_match,
+       },
+       .probe      = octeon_usb_probe,
+       .remove     = octeon_usb_remove,
+};
 
-#define MAX_USB_PORTS   10
-static struct platform_device *pdev_glob[MAX_USB_PORTS];
-static int octeon_usb_registered;
-static int __init octeon_usb_module_init(void)
+static int __init octeon_usb_driver_init(void)
 {
-       int num_devices = cvmx_usb_get_num_ports();
-       int device;
-
-       if (usb_disabled() || num_devices == 0)
-               return -ENODEV;
-
-       if (driver_register(&octeon_usb_driver))
-               return -ENOMEM;
-
-       octeon_usb_registered = 1;
-
-       /*
-        * Only cn52XX and cn56XX have DWC_OTG USB hardware and the
-        * IOB priority registers.  Under heavy network load USB
-        * hardware can be starved by the IOB causing a crash.  Give
-        * it a priority boost if it has been waiting more than 400
-        * cycles to avoid this situation.
-        *
-        * Testing indicates that a cnt_val of 8192 is not sufficient,
-        * but no failures are seen with 4096.  We choose a value of
-        * 400 to give a safety factor of 10.
-        */
-       if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) {
-               union cvmx_iob_n2c_l2c_pri_cnt pri_cnt;
-
-               pri_cnt.u64 = 0;
-               pri_cnt.s.cnt_enb = 1;
-               pri_cnt.s.cnt_val = 400;
-               cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64);
-       }
-
-       for (device = 0; device < num_devices; device++) {
-               struct resource irq_resource;
-               struct platform_device *pdev;
-               memset(&irq_resource, 0, sizeof(irq_resource));
-               irq_resource.start = (device == 0) ? OCTEON_IRQ_USB0 : OCTEON_IRQ_USB1;
-               irq_resource.end = irq_resource.start;
-               irq_resource.flags = IORESOURCE_IRQ;
-               pdev = platform_device_register_simple((char *)octeon_usb_driver.  name, device, &irq_resource, 1);
-               if (IS_ERR(pdev)) {
-                       driver_unregister(&octeon_usb_driver);
-                       octeon_usb_registered = 0;
-                       return PTR_ERR(pdev);
-               }
-               if (device < MAX_USB_PORTS)
-                       pdev_glob[device] = pdev;
+       if (usb_disabled())
+               return 0;
 
-       }
-       return 0;
+       return platform_driver_register(&octeon_usb_driver);
 }
+module_init(octeon_usb_driver_init);
 
-static void __exit octeon_usb_module_cleanup(void)
+static void __exit octeon_usb_driver_exit(void)
 {
-       int i;
+       if (usb_disabled())
+               return;
 
-       for (i = 0; i < MAX_USB_PORTS; i++)
-               if (pdev_glob[i]) {
-                       platform_device_unregister(pdev_glob[i]);
-                       pdev_glob[i] = NULL;
-               }
-       if (octeon_usb_registered)
-               driver_unregister(&octeon_usb_driver);
+       platform_driver_unregister(&octeon_usb_driver);
 }
+module_exit(octeon_usb_driver_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
-MODULE_DESCRIPTION("Cavium Networks Octeon USB Host driver.");
-module_init(octeon_usb_module_init);
-module_exit(octeon_usb_module_cleanup);
+MODULE_AUTHOR("Cavium, Inc. <support@cavium.com>");
+MODULE_DESCRIPTION("Cavium Inc. OCTEON USB Host driver.");
index 47541e1608f35404cd80d93f768cecf67e549ba2..ebb3ebc7176b1e0fdc100329fbc5127ca48d6499 100644 (file)
@@ -554,7 +554,7 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
                printk_ratelimited("%s: Failed to allocate a work queue entry\n",
                                   dev->name);
                priv->stats.tx_dropped++;
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return 0;
        }
 
@@ -565,7 +565,7 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
                                   dev->name);
                cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
                priv->stats.tx_dropped++;
-               dev_kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return 0;
        }
 
@@ -682,7 +682,7 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev)
                             work->grp);
        priv->stats.tx_packets++;
        priv->stats.tx_bytes += skb->len;
-       dev_kfree_skb(skb);
+       dev_consume_skb_any(skb);
        return 0;
 }
 
index cb060364dfe7abd8933fd51e8c1c0003653052cf..5d965cf06d59c60c717e5b9b87b74605f720ec5c 100644 (file)
@@ -668,8 +668,8 @@ void oz_binding_add(const char *net_dev)
        if (binding) {
                binding->ptype.type = __constant_htons(OZ_ETHERTYPE);
                binding->ptype.func = oz_pkt_recv;
-               memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
                if (net_dev && *net_dev) {
+                       memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN);
                        oz_dbg(ON, "Adding binding: %s\n", net_dev);
                        binding->ptype.dev =
                                dev_get_by_name(&init_net, net_dev);
@@ -680,6 +680,7 @@ void oz_binding_add(const char *net_dev)
                        }
                } else {
                        oz_dbg(ON, "Binding to all netcards\n");
+                       memset(binding->name, 0, OZ_MAX_BINDING_LEN);
                        binding->ptype.dev = NULL;
                }
                if (binding) {
index 153ec61493ab6ef94a4ec71f886b8a700ecad4ad..96df62f95b6bbec0c3e6d0fe066d898f43d5b829 100644 (file)
@@ -912,12 +912,12 @@ int rtw_check_bcn_info(struct adapter  *Adapter, u8 *pframe, u32 packet_len)
        unsigned char *pbuf;
        u32 wpa_ielen = 0;
        u8 *pbssid = GetAddr3Ptr(pframe);
-       u32 hidden_ssid = 0;
        struct HT_info_element *pht_info = NULL;
        struct rtw_ieee80211_ht_cap *pht_cap = NULL;
        u32 bcn_channel;
        unsigned short  ht_cap_info;
        unsigned char   ht_info_infos_0;
+       int ssid_len;
 
        if (is_client_associated_to_ap(Adapter) == false)
                return true;
@@ -999,21 +999,15 @@ int rtw_check_bcn_info(struct adapter  *Adapter, u8 *pframe, u32 packet_len)
        }
 
        /* checking SSID */
+       ssid_len = 0;
        p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
-       if (p == NULL) {
-               DBG_88E("%s marc: cannot find SSID for survey event\n", __func__);
-               hidden_ssid = true;
-       } else {
-               hidden_ssid = false;
-       }
-
-       if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) {
-               memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1));
-               bssid->Ssid.SsidLength = *(p + 1);
-       } else {
-               bssid->Ssid.SsidLength = 0;
-               bssid->Ssid.Ssid[0] = '\0';
+       if (p) {
+               ssid_len = *(p + 1);
+               if (ssid_len > NDIS_802_11_LENGTH_SSID)
+                       ssid_len = 0;
        }
+       memcpy(bssid->Ssid.Ssid, (p + 2), ssid_len);
+       bssid->Ssid.SsidLength = ssid_len;
 
        RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d "
                                "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid,
index dec992569476cf23f4bb93379fe3b3ce13ce0d9e..4ad80ae1067f0fbe70eefe7b2efab5f08db76962 100644 (file)
@@ -2500,7 +2500,7 @@ static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info
                 ("rtw_mp_ioctl_hdl: subcode [%d], len[%d], buffer_len[%d]\r\n",
                  poidparam->subcode, poidparam->len, len));
 
-       if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
+       if (poidparam->subcode >= ARRAY_SIZE(mp_ioctl_hdl)) {
                RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("no matching drvext subcodes\r\n"));
                ret = -EINVAL;
                goto _rtw_mp_ioctl_hdl_exit;
@@ -3164,9 +3164,7 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev,
        u8 *p2pie;
        uint p2pielen = 0, attr_contentlen = 0;
        u8 attr_content[100] = {0x00};
-
-       u8 go_devadd_str[17 + 10] = {0x00};
-       /*  +10 is for the str "go_devadd =", we have to clear it at wrqu->data.pointer */
+       u8 go_devadd_str[17 + 12] = {};
 
        /*      Commented by Albert 20121209 */
        /*      The input data is the GO's interface address which the application wants to know its device address. */
@@ -3223,12 +3221,12 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev,
        spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
 
        if (!blnMatch)
-               sprintf(go_devadd_str, "\n\ndev_add = NULL");
+               snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add = NULL");
        else
-               sprintf(go_devadd_str, "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+               snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
                        attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]);
 
-       if (copy_to_user(wrqu->data.pointer, go_devadd_str, 10 + 17))
+       if (copy_to_user(wrqu->data.pointer, go_devadd_str, sizeof(go_devadd_str)))
                return -EFAULT;
        return ret;
 }
index 68f98fa114d2ec5feb124533824fcebae59a374e..7c9ee58f47bb741ebc4b78b99b112f4ac2fdce5d 100644 (file)
@@ -653,7 +653,7 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb)
 }
 
 static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb,
-                           void *accel_priv)
+                           void *accel_priv, select_queue_fallback_t fallback)
 {
        struct adapter  *padapter = rtw_netdev_priv(dev);
        struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
index 0a341d6ec51fa3def524ee33e9b583c172876894..2f40ff5901d64706e82e2f120208c62ef5b291f8 100644 (file)
@@ -53,8 +53,9 @@ static struct usb_device_id rtw_usb_id_tbl[] = {
        {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */
        /*=== Customer ID ===*/
        /****** 8188EUS ********/
-       {USB_DEVICE(0x8179, 0x07B8)}, /* Abocom - Abocom */
+       {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */
        {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */
+       {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */
        {}      /* Terminating entry */
 };
 
index 2aa5dac2f1dfea02e12b261c79d905c05d4b9a6e..abccc9dabd6550a3c316d16f4ae1d99d330d2d11 100644 (file)
@@ -1,6 +1,6 @@
 config R8821AE
        tristate "RealTek RTL8821AE Wireless LAN NIC driver"
-       depends on PCI && WLAN
+       depends on PCI && WLAN && MAC80211
        depends on m
        select WIRELESS_EXT
        select WEXT_PRIV
index cfe88a1efd55ac0eb6ce1982275fcd02ec504b3d..76bef93ad70a8d99895e308c9b9c19d336c595c6 100644 (file)
@@ -1414,7 +1414,7 @@ struct rtl_dm {
 
 
        /*88e tx power tracking*/
-       u8 bb_swing_idx_ofdm[2];
+       u8 bb_swing_idx_ofdm[MAX_RF_PATH];
        u8 bb_swing_idx_ofdm_current;
        u8 bb_swing_idx_ofdm_base[MAX_RF_PATH];
        bool bb_swing_flag_Ofdm;
index 3c8d28b771e0bba93de1337d8671dc784f6d355e..81ff8522405c29eb69675982cd3dc0407728964a 100644 (file)
@@ -169,14 +169,14 @@ static void *my_malloc(size_t size)
        struct pool *p;
 
        p = calloc(1, sizeof(struct pool));
-       if (!p) {
-               free(p);
+       if (!p)
                return NULL;
-       }
 
        p->mem = calloc(1, size);
-       if (!p->mem)
+       if (!p->mem) {
+               free(p);
                return NULL;
+       }
 
        p->next = pool_head;
        pool_head = p;
index 9b51586d11d92bb3bbc893086d4cb7f9f9bcd912..0141bc34d5cc3e43c5ea122347456935b5613bd4 100644 (file)
@@ -149,7 +149,8 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
        case USB_SPEED_WIRELESS:
                break;
        default:
-               pr_err("speed %d\n", speed);
+               pr_err("Failed attach request for unsupported USB speed: %s\n",
+                       usb_speed_string(speed));
                return -EINVAL;
        }
 
index 965b1c0a475325d2ce79c9a4760328e1c20fd162..69bc0a01ae14e07612c970870b2d7e12b7f655eb 100644 (file)
@@ -715,7 +715,7 @@ int wl_send( struct wl_private *lp )
 
         /* Free the skb and perform queue cleanup, as the buffer was
             transmitted successfully */
-        dev_kfree_skb( lp->txF.skb );
+        dev_consume_skb_any( lp->txF.skb );
 
         lp->txF.skb = NULL;
         lp->txF.port = 0;
@@ -1730,7 +1730,7 @@ int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port )
             WL_WDS_NETIF_STOP_QUEUE( lp );
             lp->netif_queue_on = FALSE;
 
-            dev_kfree_skb( skb );
+            dev_kfree_skb_any( skb );
             return 0;
         }
     }
@@ -1755,7 +1755,7 @@ int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port )
 
     /* Free the skb and perform queue cleanup, as the buffer was
             transmitted successfully */
-    dev_kfree_skb( skb );
+    dev_consume_skb_any( skb );
 
     return TRUE;
 } // wl_send_dma
index 4a1ddaf5e00f85bf3bcd6e4e41238449216464e4..187fc060de26bc732a434790c159b2274a83ebfc 100644 (file)
@@ -1061,7 +1061,7 @@ static int wireless_set_essid(struct net_device *dev, struct iw_request_info *in
                goto out;
        }
 
-       if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN + 1) {
+       if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN) {
                ret = -EINVAL;
                goto out;
        }
index 7f1a7ce4b771a791cdf636906fd5fcdcc16c9ba6..b83ec378d04f8f1ed5fbc820429c6f1657b4d7a0 100644 (file)
@@ -785,7 +785,7 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn)
        spin_unlock_bh(&conn->cmd_lock);
 
        list_for_each_entry_safe(cmd, cmd_p, &ack_list, i_conn_node) {
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                iscsit_free_cmd(cmd, false);
        }
 }
@@ -3708,7 +3708,7 @@ iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state
                break;
        case ISTATE_REMOVE:
                spin_lock_bh(&conn->cmd_lock);
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_free_cmd(cmd, false);
@@ -4151,7 +4151,7 @@ static void iscsit_release_commands_from_conn(struct iscsi_conn *conn)
        spin_lock_bh(&conn->cmd_lock);
        list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_conn_node) {
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_increment_maxcmdsn(cmd, sess);
@@ -4196,6 +4196,10 @@ int iscsit_close_connection(
        iscsit_stop_timers_for_cmds(conn);
        iscsit_stop_nopin_response_timer(conn);
        iscsit_stop_nopin_timer(conn);
+
+       if (conn->conn_transport->iscsit_wait_conn)
+               conn->conn_transport->iscsit_wait_conn(conn);
+
        iscsit_free_queue_reqs_for_conn(conn);
 
        /*
index e048d6439f4a67bac09c27010bc07953ddac78d4..cda4d80cfaef999e45e4ac8a6b894513a3a44ad6 100644 (file)
@@ -507,7 +507,9 @@ int iscsit_handle_status_snack(
        u32 last_statsn;
        int found_cmd;
 
-       if (conn->exp_statsn > begrun) {
+       if (!begrun) {
+               begrun = conn->exp_statsn;
+       } else if (conn->exp_statsn > begrun) {
                pr_err("Got Status SNACK Begrun: 0x%08x, RunLength:"
                        " 0x%08x but already got ExpStatSN: 0x%08x on CID:"
                        " %hu.\n", begrun, runlength, conn->exp_statsn,
index 33be1fb1df32f2850b6ceb1d54b3b5340a2b6bb1..4ca8fd2a70db4c05597f6b4bfbac171ce58ea8c7 100644 (file)
@@ -138,7 +138,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
                list_for_each_entry_safe(cmd, cmd_tmp,
                                &cr->conn_recovery_cmd_list, i_conn_node) {
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        cmd->conn = NULL;
                        spin_unlock(&cr->conn_recovery_cmd_lock);
                        iscsit_free_cmd(cmd, true);
@@ -160,7 +160,7 @@ void iscsit_free_connection_recovery_entires(struct iscsi_session *sess)
                list_for_each_entry_safe(cmd, cmd_tmp,
                                &cr->conn_recovery_cmd_list, i_conn_node) {
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        cmd->conn = NULL;
                        spin_unlock(&cr->conn_recovery_cmd_lock);
                        iscsit_free_cmd(cmd, true);
@@ -216,7 +216,7 @@ int iscsit_remove_cmd_from_connection_recovery(
        }
        cr = cmd->cr;
 
-       list_del(&cmd->i_conn_node);
+       list_del_init(&cmd->i_conn_node);
        return --cr->cmd_count;
 }
 
@@ -297,7 +297,7 @@ int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn)
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN))
                        continue;
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
 
                spin_unlock_bh(&conn->cmd_lock);
                iscsit_free_cmd(cmd, true);
@@ -335,7 +335,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
        /*
         * Only perform connection recovery on ISCSI_OP_SCSI_CMD or
         * ISCSI_OP_NOOP_OUT opcodes.  For all other opcodes call
-        * list_del(&cmd->i_conn_node); to release the command to the
+        * list_del_init(&cmd->i_conn_node); to release the command to the
         * session pool and remove it from the connection's list.
         *
         * Also stop the DataOUT timer, which will be restarted after
@@ -351,7 +351,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                                " CID: %hu\n", cmd->iscsi_opcode,
                                cmd->init_task_tag, cmd->cmd_sn, conn->cid);
 
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd, true);
                        spin_lock_bh(&conn->cmd_lock);
@@ -371,7 +371,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
                 */
                if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd &&
                     iscsi_sna_gte(cmd->cmd_sn, conn->sess->exp_cmd_sn)) {
-                       list_del(&cmd->i_conn_node);
+                       list_del_init(&cmd->i_conn_node);
                        spin_unlock_bh(&conn->cmd_lock);
                        iscsit_free_cmd(cmd, true);
                        spin_lock_bh(&conn->cmd_lock);
@@ -393,7 +393,7 @@ int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn)
 
                cmd->sess = conn->sess;
 
-               list_del(&cmd->i_conn_node);
+               list_del_init(&cmd->i_conn_node);
                spin_unlock_bh(&conn->cmd_lock);
 
                iscsit_free_all_datain_reqs(cmd);
index 39761837608d3a2ff059356e1049779580182952..44a5471de00ffe95c5fccdf5462931efa0acc361 100644 (file)
@@ -137,7 +137,7 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np(
        list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
 
                spin_lock(&tpg->tpg_state_lock);
-               if (tpg->tpg_state == TPG_STATE_FREE) {
+               if (tpg->tpg_state != TPG_STATE_ACTIVE) {
                        spin_unlock(&tpg->tpg_state_lock);
                        continue;
                }
index 12da9b386169b7ece6150387777bf467426dc42e..c3d9df6aaf5f35bc4665355bf7cfe18c9e522aa7 100644 (file)
@@ -500,7 +500,7 @@ static inline int core_alua_state_lba_dependent(
 
                        if (segment_mult) {
                                u64 tmp = lba;
-                               start_lba = sector_div(tmp, segment_size * segment_mult);
+                               start_lba = do_div(tmp, segment_size * segment_mult);
 
                                last_lba = first_lba + segment_size - 1;
                                if (start_lba >= first_lba &&
index 2f5d77932c80052448ab752fdc32d6942b3fc50c..3013287a2aaa192fdacdfde7eb87bcd48eb0aff4 100644 (file)
@@ -2009,7 +2009,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
        struct t10_reservation *pr_tmpl = &dev->t10_pr;
        unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL;
        sense_reason_t ret = TCM_NO_SENSE;
-       int pr_holder = 0;
+       int pr_holder = 0, type;
 
        if (!se_sess || !se_lun) {
                pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n");
@@ -2131,6 +2131,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                        ret = TCM_RESERVATION_CONFLICT;
                        goto out;
                }
+               type = pr_reg->pr_res_type;
 
                spin_lock(&pr_tmpl->registration_lock);
                /*
@@ -2161,6 +2162,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                 * Release the calling I_T Nexus registration now..
                 */
                __core_scsi3_free_registration(cmd->se_dev, pr_reg, NULL, 1);
+               pr_reg = NULL;
 
                /*
                 * From spc4r17, section 5.7.11.3 Unregistering
@@ -2174,8 +2176,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
                 * RESERVATIONS RELEASED.
                 */
                if (pr_holder &&
-                   (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
-                    pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {
+                   (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY ||
+                    type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) {
                        list_for_each_entry(pr_reg_p,
                                        &pr_tmpl->registration_list,
                                        pr_reg_list) {
@@ -2194,7 +2196,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key,
        ret = core_scsi3_update_and_write_aptpl(dev, aptpl);
 
 out:
-       core_scsi3_put_pr_reg(pr_reg);
+       if (pr_reg)
+               core_scsi3_put_pr_reg(pr_reg);
        return ret;
 }
 
index fa3cae393e13e64056da79e9a8daf43bfe8dc721..77e6531fb0a1c0a25ed16b71d1936ec37c2ed50a 100644 (file)
@@ -1074,23 +1074,36 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
        struct scatterlist *psg;
        void *paddr, *addr;
        unsigned int i, len, left;
+       unsigned int offset = sg_off;
 
        left = sectors * dev->prot_length;
 
        for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
+               unsigned int psg_len, copied = 0;
 
-               len = min(psg->length, left);
                paddr = kmap_atomic(sg_page(psg)) + psg->offset;
-               addr = kmap_atomic(sg_page(sg)) + sg_off;
+               psg_len = min(left, psg->length);
+               while (psg_len) {
+                       len = min(psg_len, sg->length - offset);
+                       addr = kmap_atomic(sg_page(sg)) + sg->offset + offset;
 
-               if (read)
-                       memcpy(paddr, addr, len);
-               else
-                       memcpy(addr, paddr, len);
+                       if (read)
+                               memcpy(paddr + copied, addr, len);
+                       else
+                               memcpy(addr, paddr + copied, len);
 
-               left -= len;
+                       left -= len;
+                       offset += len;
+                       copied += len;
+                       psg_len -= len;
+
+                       if (offset >= sg->length) {
+                               sg = sg_next(sg);
+                               offset = 0;
+                       }
+                       kunmap_atomic(addr);
+               }
                kunmap_atomic(paddr);
-               kunmap_atomic(addr);
        }
 }
 
@@ -1155,7 +1168,7 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
 {
        struct se_device *dev = cmd->se_dev;
        struct se_dif_v1_tuple *sdt;
-       struct scatterlist *dsg;
+       struct scatterlist *dsg, *psg = sg;
        sector_t sector = start;
        void *daddr, *paddr;
        int i, j, offset = sg_off;
@@ -1163,14 +1176,14 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
 
        for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
                daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
-               paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+               paddr = kmap_atomic(sg_page(psg)) + sg->offset;
 
                for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
 
-                       if (offset >= sg->length) {
+                       if (offset >= psg->length) {
                                kunmap_atomic(paddr);
-                               sg = sg_next(sg);
-                               paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+                               psg = sg_next(psg);
+                               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
                                offset = 0;
                        }
 
index 43c5ca9878bc5b6f3f1d675c04779b245ccc1a22..3bebc71ea033908e8e64843ba98b295b030a78ad 100644 (file)
@@ -440,8 +440,8 @@ check_scsi_name:
                padding = ((-scsi_target_len) & 3);
                if (padding)
                        scsi_target_len += padding;
-               if (scsi_name_len > 256)
-                       scsi_name_len = 256;
+               if (scsi_target_len > 256)
+                       scsi_target_len = 256;
 
                buf[off-1] = scsi_target_len;
                off += scsi_target_len;
index c50fd9f11aab8b0dfb8b90991378a51bf8255d1b..2956250b7225c99d77a7475b27d1bf881231539f 100644 (file)
@@ -669,9 +669,6 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
                return;
        }
 
-       if (!success)
-               cmd->transport_state |= CMD_T_FAILED;
-
        /*
         * Check for case where an explicit ABORT_TASK has been received
         * and transport_wait_for_tasks() will be waiting for completion..
@@ -681,7 +678,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status)
                spin_unlock_irqrestore(&cmd->t_state_lock, flags);
                complete(&cmd->t_transport_stop_comp);
                return;
-       } else if (cmd->transport_state & CMD_T_FAILED) {
+       } else if (!success) {
                INIT_WORK(&cmd->work, target_complete_failure_work);
        } else {
                INIT_WORK(&cmd->work, target_complete_ok_work);
@@ -1604,6 +1601,9 @@ void transport_generic_request_failure(struct se_cmd *cmd,
        case TCM_CHECK_CONDITION_ABORT_CMD:
        case TCM_CHECK_CONDITION_UNIT_ATTENTION:
        case TCM_CHECK_CONDITION_NOT_READY:
+       case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
+       case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
+       case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
                break;
        case TCM_OUT_OF_RESOURCES:
                sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
index 35c066489a19ecd1def35f044e45dc52d55688a1..5f88d767671e956fa400b039f2cc21de9bc58621 100644 (file)
@@ -136,6 +136,7 @@ config SPEAR_THERMAL
 config RCAR_THERMAL
        tristate "Renesas R-Car thermal driver"
        depends on ARCH_SHMOBILE || COMPILE_TEST
+       depends on HAS_IOMEM
        help
          Enable this to plug the R-Car thermal sensor driver into the Linux
          thermal framework.
@@ -210,8 +211,16 @@ config ACPI_INT3403_THERMAL
        tristate "ACPI INT3403 thermal driver"
        depends on X86 && ACPI
        help
-         This driver uses ACPI INT3403 device objects. If present, it will
-         register each INT3403 thermal sensor as a thermal zone.
+         Newer laptops and tablets that use ACPI may have thermal sensors
+         outside the core CPU/SOC for thermal safety reasons. These
+         temperature sensors are also exposed for the OS to use via the so
+         called INT3403 ACPI object. This driver will, on devices that have
+         such sensors, expose the temperature information from these sensors
+         to userspace via the normal thermal framework. This means that a wide
+         range of applications and GUI widgets can show this information to
+         the user or use this information for making decisions. For example,
+         the Intel Thermal Daemon can use this information to allow the user
+         to select his laptop to run without turning on the fans.
 
 menu "Texas Instruments thermal drivers"
 source "drivers/thermal/ti-soc-thermal/Kconfig"
index 338a88bf6662d1fd0b963f0f8bc7c02dce55e73b..71b0ec0c370d73aad18d685118c197735c5b2833 100644 (file)
@@ -56,10 +56,15 @@ static LIST_HEAD(thermal_governor_list);
 static DEFINE_MUTEX(thermal_list_lock);
 static DEFINE_MUTEX(thermal_governor_lock);
 
+static struct thermal_governor *def_governor;
+
 static struct thermal_governor *__find_governor(const char *name)
 {
        struct thermal_governor *pos;
 
+       if (!name || !name[0])
+               return def_governor;
+
        list_for_each_entry(pos, &thermal_governor_list, governor_list)
                if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
                        return pos;
@@ -82,17 +87,23 @@ int thermal_register_governor(struct thermal_governor *governor)
        if (__find_governor(governor->name) == NULL) {
                err = 0;
                list_add(&governor->governor_list, &thermal_governor_list);
+               if (!def_governor && !strncmp(governor->name,
+                       DEFAULT_THERMAL_GOVERNOR, THERMAL_NAME_LENGTH))
+                       def_governor = governor;
        }
 
        mutex_lock(&thermal_list_lock);
 
        list_for_each_entry(pos, &thermal_tz_list, node) {
+               /*
+                * only thermal zones with specified tz->tzp->governor_name
+                * may run with tz->govenor unset
+                */
                if (pos->governor)
                        continue;
-               if (pos->tzp)
-                       name = pos->tzp->governor_name;
-               else
-                       name = DEFAULT_THERMAL_GOVERNOR;
+
+               name = pos->tzp->governor_name;
+
                if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
                        pos->governor = governor;
        }
@@ -342,8 +353,8 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
 static void handle_non_critical_trips(struct thermal_zone_device *tz,
                        int trip, enum thermal_trip_type trip_type)
 {
-       if (tz->governor)
-               tz->governor->throttle(tz, trip);
+       tz->governor ? tz->governor->throttle(tz, trip) :
+                      def_governor->throttle(tz, trip);
 }
 
 static void handle_critical_trips(struct thermal_zone_device *tz,
@@ -1107,7 +1118,7 @@ __thermal_cooling_device_register(struct device_node *np,
        INIT_LIST_HEAD(&cdev->thermal_instances);
        cdev->np = np;
        cdev->ops = ops;
-       cdev->updated = true;
+       cdev->updated = false;
        cdev->device.class = &thermal_class;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@ -1533,7 +1544,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        if (tz->tzp)
                tz->governor = __find_governor(tz->tzp->governor_name);
        else
-               tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
+               tz->governor = def_governor;
 
        mutex_unlock(&thermal_governor_lock);
 
index 972e1c73722a4c4ec90cd75af32ce99da6438745..081fd7e6a9f070c683deaea799437a2e459b94f4 100644 (file)
@@ -68,6 +68,10 @@ struct phy_dev_entry {
        struct thermal_zone_device *tzone;
 };
 
+static const struct thermal_zone_params pkg_temp_tz_params = {
+       .no_hwmon       = true,
+};
+
 /* List maintaining number of package instances */
 static LIST_HEAD(phy_dev_list);
 static DEFINE_MUTEX(phy_dev_list_mutex);
@@ -394,7 +398,6 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        int err;
        u32 tj_max;
        struct phy_dev_entry *phy_dev_entry;
-       char buffer[30];
        int thres_count;
        u32 eax, ebx, ecx, edx;
        u8 *temp;
@@ -440,13 +443,11 @@ static int pkg_temp_thermal_device_add(unsigned int cpu)
        phy_dev_entry->first_cpu = cpu;
        phy_dev_entry->tj_max = tj_max;
        phy_dev_entry->ref_cnt = 1;
-       snprintf(buffer, sizeof(buffer), "pkg-temp-%d\n",
-                                       phy_dev_entry->phys_proc_id);
-       phy_dev_entry->tzone = thermal_zone_device_register(buffer,
+       phy_dev_entry->tzone = thermal_zone_device_register("x86_pkg_temp",
                        thres_count,
                        (thres_count == MAX_NUMBER_OF_TRIPS) ?
                                0x03 : 0x01,
-                       phy_dev_entry, &tzone_ops, NULL, 0, 0);
+                       phy_dev_entry, &tzone_ops, &pkg_temp_tz_params, 0, 0);
        if (IS_ERR(phy_dev_entry->tzone)) {
                err = PTR_ERR(phy_dev_entry->tzone);
                goto err_ret_free;
index 6496872e2e47c34c29ca75c79ce4d56bf7191146..b01659bd4f7c2163803d64f3fe83cfe063720bf7 100644 (file)
@@ -255,13 +255,7 @@ static int __init hvc_opal_init(void)
        /* Register as a vio device to receive callbacks */
        return platform_driver_register(&hvc_opal_driver);
 }
-module_init(hvc_opal_init);
-
-static void __exit hvc_opal_exit(void)
-{
-       platform_driver_unregister(&hvc_opal_driver);
-}
-module_exit(hvc_opal_exit);
+device_initcall(hvc_opal_init);
 
 static void udbg_opal_putc(char c)
 {
index 0069bb86ba49c5981f9cd1a35229fad37152ab04..08c87920b74a98a02e3fcde902a41a64e79b9caf 100644 (file)
@@ -102,17 +102,7 @@ static int __init hvc_rtas_init(void)
 
        return 0;
 }
-module_init(hvc_rtas_init);
-
-/* This will tear down the tty portion of the driver */
-static void __exit hvc_rtas_exit(void)
-{
-       /* Really the fun isn't over until the worker thread breaks down and
-        * the tty cleans up */
-       if (hvc_rtas_dev)
-               hvc_remove(hvc_rtas_dev);
-}
-module_exit(hvc_rtas_exit);
+device_initcall(hvc_rtas_init);
 
 /* This will happen prior to module init.  There is no tty at this time? */
 static int __init hvc_rtas_console_init(void)
index 72228276fe314b36a1344a1ffef36263a4379c4c..9cf573d06a29bb8f44067d4c2ac70283db20f6db 100644 (file)
@@ -80,14 +80,7 @@ static int __init hvc_udbg_init(void)
 
        return 0;
 }
-module_init(hvc_udbg_init);
-
-static void __exit hvc_udbg_exit(void)
-{
-       if (hvc_udbg_dev)
-               hvc_remove(hvc_udbg_dev);
-}
-module_exit(hvc_udbg_exit);
+device_initcall(hvc_udbg_init);
 
 static int __init hvc_udbg_console_init(void)
 {
index 636c9baad7a58b76fc740bd49794303cfcc472ef..2dc2831840ca1852efb1cec280ced8b2e0afb0ae 100644 (file)
@@ -561,18 +561,7 @@ static int __init xen_hvc_init(void)
 #endif
        return r;
 }
-
-static void __exit xen_hvc_fini(void)
-{
-       struct xencons_info *entry, *next;
-
-       if (list_empty(&xenconsoles))
-                       return;
-
-       list_for_each_entry_safe(entry, next, &xenconsoles, list) {
-               xen_console_remove(entry);
-       }
-}
+device_initcall(xen_hvc_init);
 
 static int xen_cons_init(void)
 {
@@ -598,10 +587,6 @@ static int xen_cons_init(void)
        hvc_instantiate(HVC_COOKIE, 0, ops);
        return 0;
 }
-
-
-module_init(xen_hvc_init);
-module_exit(xen_hvc_fini);
 console_initcall(xen_cons_init);
 
 #ifdef CONFIG_EARLY_PRINTK
index f34461c5f14e102cbf64dba861e46a4a94820ecb..2ebe47b78a3e3ba48093d46164bee6247a32295e 100644 (file)
@@ -1090,6 +1090,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
 {
        unsigned int addr = 0;
        unsigned int modem = 0;
+       unsigned int brk = 0;
        struct gsm_dlci *dlci;
        int len = clen;
        u8 *dp = data;
@@ -1116,6 +1117,16 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
                if (len == 0)
                        return;
        }
+       len--;
+       if (len > 0) {
+               while (gsm_read_ea(&brk, *dp++) == 0) {
+                       len--;
+                       if (len == 0)
+                               return;
+               }
+               modem <<= 7;
+               modem |= (brk & 0x7f);
+       }
        tty = tty_port_tty_get(&dlci->port);
        gsm_process_modem(tty, dlci, modem, clen);
        if (tty) {
index cb8017aa443472f8b67d9ec4eab7403b268d2c0f..d15624c1b75161877e6319e6460981866feb54cb 100644 (file)
@@ -817,8 +817,7 @@ static void process_echoes(struct tty_struct *tty)
        struct n_tty_data *ldata = tty->disc_data;
        size_t echoed;
 
-       if ((!L_ECHO(tty) && !L_ECHONL(tty)) ||
-           ldata->echo_mark == ldata->echo_tail)
+       if (ldata->echo_mark == ldata->echo_tail)
                return;
 
        mutex_lock(&ldata->output_lock);
@@ -1244,7 +1243,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
        if (L_ECHO(tty)) {
                echo_char(c, tty);
                commit_echoes(tty);
-       }
+       } else
+               process_echoes(tty);
        isig(signal, tty);
        return;
 }
@@ -1274,7 +1274,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
        if (I_IXON(tty)) {
                if (c == START_CHAR(tty)) {
                        start_tty(tty);
-                       commit_echoes(tty);
+                       process_echoes(tty);
                        return 0;
                }
                if (c == STOP_CHAR(tty)) {
@@ -1820,8 +1820,10 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
         * Fix tty hang when I_IXON(tty) is cleared, but the tty
         * been stopped by STOP_CHAR(tty) before it.
         */
-       if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped)
+       if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
                start_tty(tty);
+               process_echoes(tty);
+       }
 
        /* The termios change make the tty ready for I/O */
        if (waitqueue_active(&tty->write_wait))
@@ -1896,7 +1898,7 @@ err:
 static inline int input_available_p(struct tty_struct *tty, int poll)
 {
        struct n_tty_data *ldata = tty->disc_data;
-       int amt = poll && !TIME_CHAR(tty) ? MIN_CHAR(tty) : 1;
+       int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1;
 
        if (ldata->icanon && !L_EXTPROC(tty)) {
                if (ldata->canon_head != ldata->read_tail)
index 61ecd709a7229aa7d7d6fcc91326a8eda0861fa8..69932b7556cf822194413f2da0278d9bd3f4cb13 100644 (file)
@@ -2432,6 +2432,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 
        serial_dl_write(up, quot);
 
+       /*
+        * XR17V35x UARTs have an extra fractional divisor register (DLD)
+        *
+        * We need to recalculate all of the registers, because DLM and DLL
+        * are already rounded to a whole integer.
+        *
+        * When recalculating we use a 32x clock instead of a 16x clock to
+        * allow 1-bit for rounding in the fractional part.
+        */
+       if (up->port.type == PORT_XR17V35X) {
+               unsigned int baud_x32 = (port->uartclk * 2) / baud;
+               u16 quot = baud_x32 / 32;
+               u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
+
+               serial_dl_write(up, quot);
+               serial_port_out(port, 0x2, quot_frac & 0xf);
+       }
+
        /*
         * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
         * is written without DLAB set, this mode will be disabled.
index faa64e6461002136069e53619ad78c7534a7261d..ed311357674032ad4f53577fe2f8033ba1446941 100644 (file)
@@ -391,7 +391,7 @@ static int dw8250_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int dw8250_suspend(struct device *dev)
 {
        struct dw8250_data *data = dev_get_drvdata(dev);
@@ -409,7 +409,7 @@ static int dw8250_resume(struct device *dev)
 
        return 0;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_RUNTIME
 static int dw8250_runtime_suspend(struct device *dev)
index 50228eed3b6fa502a3a7bb93d14f9280f1f4e713..0ff3e3624d4c0599623af31535d02502c6da81c5 100644 (file)
@@ -783,7 +783,8 @@ static int pci_netmos_9900_setup(struct serial_private *priv,
 {
        unsigned int bar;
 
-       if ((priv->dev->subsystem_device & 0xff00) == 0x3000) {
+       if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) &&
+           (priv->dev->subsystem_device & 0xff00) == 0x3000) {
                /* netmos apparently orders BARs by datasheet layout, so serial
                 * ports get BARs 0 and 3 (or 1 and 4 for memmapped)
                 */
index fa511ebab67c67efda853be187ca670e20db4679..77f035158d6cac1cd7bd5ec094c2a9dfa71cab4e 100644 (file)
@@ -738,9 +738,6 @@ static int serial_omap_startup(struct uart_port *port)
                        return retval;
                }
                disable_irq(up->wakeirq);
-       } else {
-               dev_info(up->port.dev, "no wakeirq for uart%d\n",
-                        up->port.line);
        }
 
        dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line);
@@ -1604,8 +1601,11 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
                                            flags & SER_RS485_RTS_AFTER_SEND);
                if (ret < 0)
                        return ret;
-       } else
+       } else if (up->rts_gpio == -EPROBE_DEFER) {
+               return -EPROBE_DEFER;
+       } else {
                up->rts_gpio = -EINVAL;
+       }
 
        if (of_property_read_u32_array(np, "rs485-rts-delay",
                                    rs485_delay, 2) == 0) {
@@ -1687,6 +1687,9 @@ static int serial_omap_probe(struct platform_device *pdev)
        up->port.iotype = UPIO_MEM;
        up->port.irq = uartirq;
        up->wakeirq = wakeirq;
+       if (!up->wakeirq)
+               dev_info(up->port.dev, "no wakeirq for uart%d\n",
+                        up->port.line);
 
        up->port.regshift = 2;
        up->port.fifosize = 64;
index 49a2ffd101a7145ca1de4a7eccb72d56964037d0..b7bfe24d4ebca6f930bcaa3058b09f017561dfb5 100644 (file)
@@ -542,8 +542,10 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
        wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl,
                        rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) |
                        SIRFUART_IO_MODE);
-       sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
        spin_unlock_irqrestore(&sirfport->rx_lock, flags);
+       spin_lock(&port->lock);
+       sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
+       spin_unlock(&port->lock);
        if (sirfport->rx_io_count == 4) {
                spin_lock_irqsave(&sirfport->rx_lock, flags);
                sirfport->rx_io_count = 0;
index cf86e729532b9fc11b768863c94bfb9fe1da7109..dc697cee248ad3dcfa84e2f1d66f8c439b37dd81 100644 (file)
@@ -433,13 +433,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (port->sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&port->lock);
-       } else
-               spin_lock(&port->lock);
+       if (port->sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       else
+               spin_lock_irqsave(&port->lock, flags);
 
        while (n > 0) {
                unsigned long ra = __pa(con_write_page);
@@ -470,8 +467,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
        }
 
        if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static inline void sunhv_console_putchar(struct uart_port *port, char c)
@@ -492,7 +488,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
        unsigned long flags;
        int i, locked = 1;
 
-       local_irq_save(flags);
+       if (port->sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&port->lock, flags);
+       else
+               spin_lock_irqsave(&port->lock, flags);
        if (port->sysrq) {
                locked = 0;
        } else if (oops_in_progress) {
@@ -507,8 +506,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
        }
 
        if (locked)
-               spin_unlock(&port->lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&port->lock, flags);
 }
 
 static struct console sunhv_console = {
index 380fb5355cb26ae68a472a4e6097c57556d0b8e1..5faa8e905e9896e52489a84dd3f6e7925e147dfc 100644 (file)
@@ -844,20 +844,16 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n)
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
+       if (up->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        uart_console_write(&up->port, s, n, sunsab_console_putchar);
        sunsab_tec_wait(up);
 
        if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 static int sunsab_console_setup(struct console *con, char *options)
index db79b76f5c8e978e09824b719d585cf470d75d68..9a0f24f837209f2b15f9e11901f350dcb0230a19 100644 (file)
@@ -1295,13 +1295,10 @@ static void sunsu_console_write(struct console *co, const char *s,
        unsigned int ier;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
+       if (up->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        /*
         *      First save the UER then disable the interrupts
@@ -1319,8 +1316,7 @@ static void sunsu_console_write(struct console *co, const char *s,
        serial_out(up, UART_IER, ier);
 
        if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 /*
index 45a8c6aa583797ba717ec3da79a24929a6eb425f..a2c40ed287d21b7a7ff545626bba5b0711211149 100644 (file)
@@ -1195,20 +1195,16 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
        unsigned long flags;
        int locked = 1;
 
-       local_irq_save(flags);
-       if (up->port.sysrq) {
-               locked = 0;
-       } else if (oops_in_progress) {
-               locked = spin_trylock(&up->port.lock);
-       } else
-               spin_lock(&up->port.lock);
+       if (up->port.sysrq || oops_in_progress)
+               locked = spin_trylock_irqsave(&up->port.lock, flags);
+       else
+               spin_lock_irqsave(&up->port.lock, flags);
 
        uart_console_write(&up->port, s, count, sunzilog_putchar);
        udelay(2);
 
        if (locked)
-               spin_unlock(&up->port.lock);
-       local_irq_restore(flags);
+               spin_unlock_irqrestore(&up->port.lock, flags);
 }
 
 static int __init sunzilog_console_setup(struct console *con, char *options)
index 61b1137d7e56d877fad8b2339c368cd09a5419e1..23b5d32954bfc9365ec6453d69e331e975ca8d0e 100644 (file)
@@ -1164,6 +1164,8 @@ static void csi_J(struct vc_data *vc, int vpar)
                        scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char,
                                    vc->vc_screenbuf_size >> 1);
                        set_origin(vc);
+                       if (CON_IS_VISIBLE(vc))
+                               update_screen(vc);
                        /* fall through */
                case 2: /* erase whole display */
                        count = vc->vc_cols * vc->vc_rows;
index 80de2f88ed2c7852fdd38bec785e6d5681cbe310..4ab2cb62dfce4c1b3dfe140ef83f20d4633b9ff0 100644 (file)
@@ -105,7 +105,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)
 
        do {
                /* flush any pending transfer */
-               hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n));
+               hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n));
                while (hw_read(ci, OP_ENDPTFLUSH, BIT(n)))
                        cpu_relax();
        } while (hw_read(ci, OP_ENDPTSTAT, BIT(n)));
@@ -205,7 +205,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)
        if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))
                return -EAGAIN;
 
-       hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n));
+       hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n));
 
        while (hw_read(ci, OP_ENDPTPRIME, BIT(n)))
                cpu_relax();
index 8d72f0c659377371cc6c481e33458c7d555f3493..062967c90b2a06e66a081f81ab53aabe1a9e37e4 100644 (file)
@@ -717,6 +717,10 @@ int usb_get_configuration(struct usb_device *dev)
                        result = -ENOMEM;
                        goto err;
                }
+
+               if (dev->quirks & USB_QUIRK_DELAY_INIT)
+                       msleep(100);
+
                result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
                    bigbuffer, length);
                if (result < 0) {
index 5d01558cef666233b47f29d569595a1f42dda8b2..ab90a01568283c3c0d2a0a3df9b653bfba65a812 100644 (file)
@@ -63,8 +63,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        dynid->id.idProduct = idProduct;
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
        if (fields > 2 && bInterfaceClass) {
-               if (bInterfaceClass > 255)
-                       return -EINVAL;
+               if (bInterfaceClass > 255) {
+                       retval = -EINVAL;
+                       goto fail;
+               }
 
                dynid->id.bInterfaceClass = (u8)bInterfaceClass;
                dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
@@ -73,17 +75,21 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        if (fields > 4) {
                const struct usb_device_id *id = id_table;
 
-               if (!id)
-                       return -ENODEV;
+               if (!id) {
+                       retval = -ENODEV;
+                       goto fail;
+               }
 
                for (; id->match_flags; id++)
                        if (id->idVendor == refVendor && id->idProduct == refProduct)
                                break;
 
-               if (id->match_flags)
+               if (id->match_flags) {
                        dynid->id.driver_info = id->driver_info;
-               else
-                       return -ENODEV;
+               } else {
+                       retval = -ENODEV;
+                       goto fail;
+               }
        }
 
        spin_lock(&dynids->lock);
@@ -95,6 +101,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        if (retval)
                return retval;
        return count;
+
+fail:
+       kfree(dynid);
+       return retval;
 }
 EXPORT_SYMBOL_GPL(usb_store_new_id);
 
index 199aaea6bfe0ad308fd459e0d0eb61daa1cdcb77..2518c325075093a9c26044f2d9dd18483dc7dd60 100644 (file)
@@ -1032,7 +1032,6 @@ static int register_root_hub(struct usb_hcd *hcd)
                                        dev_name(&usb_dev->dev), retval);
                        return retval;
                }
-               usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
        }
 
        retval = usb_new_device (usb_dev);
index babba885978d11e1ba4ece32373ba38a962c3f64..64ea21971be23f770986b25cf05890553cf8d195 100644 (file)
@@ -128,7 +128,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
        return usb_get_intfdata(hdev->actconfig->interface[0]);
 }
 
-int usb_device_supports_lpm(struct usb_device *udev)
+static int usb_device_supports_lpm(struct usb_device *udev)
 {
        /* USB 2.1 (and greater) devices indicate LPM support through
         * their USB 2.0 Extended Capabilities BOS descriptor.
@@ -149,11 +149,6 @@ int usb_device_supports_lpm(struct usb_device *udev)
                                "Power management will be impacted.\n");
                return 0;
        }
-
-       /* udev is root hub */
-       if (!udev->parent)
-               return 1;
-
        if (udev->parent->lpm_capable)
                return 1;
 
index 8f37063c0a49eeff7ba2d0902621aaa91800c058..739ee8e8bdfdaf7bc6be98d716255e4f561cc17a 100644 (file)
@@ -47,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* Microsoft LifeCam-VX700 v2.0 */
        { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Logitech HD Pro Webcams C920 and C930e */
+       { USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT },
+       { USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },
+
        /* Logitech Quickcam Fusion */
        { USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME },
 
index c49383669cd87ce4dda9b996fd9b3f1caf03bd2b..823857767a16f3384730dcf1f90c42f8eedc3588 100644 (file)
@@ -35,7 +35,6 @@ extern int usb_get_device_descriptor(struct usb_device *dev,
                unsigned int size);
 extern int usb_get_bos_descriptor(struct usb_device *dev);
 extern void usb_release_bos_descriptor(struct usb_device *dev);
-extern int usb_device_supports_lpm(struct usb_device *udev);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_choose_configuration(struct usb_device *udev);
index 8565d87f94b4872e6f5fb7cb1d813f8e0b4493bc..1d129884cc39ad71e8fddc34b6dc9715ae679f47 100644 (file)
@@ -216,7 +216,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
        int retval = 0;
 
        if (!select_phy)
-               return -ENODEV;
+               return 0;
 
        usbcfg = readl(hsotg->regs + GUSBCFG);
 
index f59484d43b355b15b1297f3341c832a0a395ebb3..4d918ed8d343394bcc92cea19e4e025a9f7c7c5c 100644 (file)
@@ -2565,25 +2565,14 @@ static void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd,
                                     struct usb_host_endpoint *ep)
 {
        struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
-       int is_control = usb_endpoint_xfer_control(&ep->desc);
-       int is_out = usb_endpoint_dir_out(&ep->desc);
-       int epnum = usb_endpoint_num(&ep->desc);
-       struct usb_device *udev;
        unsigned long flags;
 
        dev_dbg(hsotg->dev,
                "DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n",
                ep->desc.bEndpointAddress);
 
-       udev = to_usb_device(hsotg->dev);
-
        spin_lock_irqsave(&hsotg->lock, flags);
-
-       usb_settoggle(udev, epnum, is_out, 0);
-       if (is_control)
-               usb_settoggle(udev, epnum, !is_out, 0);
        dwc2_hcd_endpoint_reset(hsotg, ep);
-
        spin_unlock_irqrestore(&hsotg->lock, flags);
 }
 
index d01d0d3f2cf0981b9e89654cac5697f747ef6d48..eaba547ce26b53699744adb4bcc77fa1627a7c05 100644 (file)
@@ -124,6 +124,9 @@ static int dwc2_driver_probe(struct platform_device *dev)
        int retval;
        int irq;
 
+       if (usb_disabled())
+               return -ENODEV;
+
        match = of_match_device(dwc2_of_match_table, &dev->dev);
        if (match && match->data) {
                params = match->data;
index 888fbb43b338ecebcaf7cf8cb267fb2de35cc240..e969eb809a853dbb38093a0f5d3d39f57f931bb7 100644 (file)
@@ -360,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
        bcm_writel(val, udc->iudma_regs + off);
 }
 
-static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off)
+static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan)
 {
-       return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+       return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
-static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off,
+                                       int chan)
 {
-       bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off);
+       bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
-static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off)
+static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan)
 {
-       return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+       return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
-static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off)
+static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off,
+                                       int chan)
 {
-       bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off);
+       bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off +
+                       (ENETDMA_CHAN_WIDTH * chan));
 }
 
 static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled)
@@ -638,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,
        } while (!last_bd);
 
        usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK,
-                       ENETDMAC_CHANCFG_REG(iudma->ch_idx));
+                       ENETDMAC_CHANCFG_REG, iudma->ch_idx);
 }
 
 /**
@@ -694,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
                bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));
 
        /* stop DMA, then wait for the hardware to wrap up */
-       usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx));
+       usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx);
 
-       while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) &
+       while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) &
                                   ENETDMAC_CHANCFG_EN_MASK) {
                udelay(1);
 
@@ -713,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
                        dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",
                                 ch_idx);
                        usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK,
-                                       ENETDMAC_CHANCFG_REG(ch_idx));
+                                       ENETDMAC_CHANCFG_REG, ch_idx);
                }
        }
-       usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx));
+       usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx);
 
        /* don't leave "live" HW-owned entries for the next guy to step on */
        for (d = iudma->bd_ring; d <= iudma->end_bd; d++)
@@ -728,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)
 
        /* set up IRQs, UBUS burst size, and BD base for this channel */
        usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
-                       ENETDMAC_IRMASK_REG(ch_idx));
-       usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx));
+                       ENETDMAC_IRMASK_REG, ch_idx);
+       usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx);
 
-       usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx));
-       usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx));
+       usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx);
+       usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx);
 }
 
 /**
@@ -2035,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)
        spin_lock(&udc->lock);
 
        usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK,
-                       ENETDMAC_IR_REG(iudma->ch_idx));
+                       ENETDMAC_IR_REG, iudma->ch_idx);
        bep = iudma->bep;
        rc = iudma_read(udc, iudma);
 
@@ -2175,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)
                seq_printf(s, " [ep%d]:\n",
                           max_t(int, iudma_defaults[ch_idx].ep_num, 0));
                seq_printf(s, "  cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n",
-                          usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)),
-                          usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)),
-                          usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)),
-                          usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx)));
+                          usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx),
+                          usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx),
+                          usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx),
+                          usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx));
 
-               sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx));
-               sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx));
+               sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx);
+               sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx);
                seq_printf(s, "  base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n",
-                          usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)),
+                          usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx),
                           sram2 >> 16, sram2 & 0xffff,
                           sram3 >> 16, sram3 & 0xffff,
-                          usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx)));
+                          usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx));
                seq_printf(s, "  desc: %d/%d used", iudma->n_bds_used,
                           iudma->n_bds);
 
index 306a2b52125c8e7ee2eba91bcf1156e689ae133e..2b43343940766251ee5f274b807b882273f09008 100644 (file)
@@ -585,7 +585,6 @@ static ssize_t ffs_epfile_io(struct file *file,
                             char __user *buf, size_t len, int read)
 {
        struct ffs_epfile *epfile = file->private_data;
-       struct usb_gadget *gadget = epfile->ffs->gadget;
        struct ffs_ep *ep;
        char *data = NULL;
        ssize_t ret, data_len;
@@ -621,6 +620,12 @@ static ssize_t ffs_epfile_io(struct file *file,
 
        /* Allocate & copy */
        if (!halt) {
+               /*
+                * if we _do_ wait above, the epfile->ffs->gadget might be NULL
+                * before the waiting completes, so do not assign to 'gadget' earlier
+                */
+               struct usb_gadget *gadget = epfile->ffs->gadget;
+
                /*
                 * Controller may require buffer size to be aligned to
                 * maxpacketsize of an out endpoint.
index bf7a56b6d48ac2c3ebb3acf8920c70d79900d307..69b76efd11e9bea3f11d9d2effe293c04045f01c 100644 (file)
@@ -1157,7 +1157,7 @@ static int __init printer_bind_config(struct usb_configuration *c)
 
        usb_gadget_set_selfpowered(gadget);
 
-       if (gadget->is_otg) {
+       if (gadget_is_otg(gadget)) {
                otg_descriptor.bmAttributes |= USB_OTG_HNP;
                printer_cfg_driver.descriptors = otg_desc;
                printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
index f04b2c3154dea73b0fa2c1d93322bdbf1c5930bc..dd9678f85c586a591b2a6514ba71034895d1769d 100644 (file)
@@ -1629,7 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
                ep->ep.desc = NULL;
                ep->halted = 0;
                INIT_LIST_HEAD(&ep->queue);
-               usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket);
+               usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);
        }
 }
 
index 471142725ffe1cd42f92b2ad0883fa925c715a2a..81cda09b47e3127772e51cbc5c57eab7761c4a52 100644 (file)
@@ -685,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     status, masked_status, pcd_status = 0, cmd;
        int                     bh;
+       unsigned long           flags;
 
-       spin_lock (&ehci->lock);
+       /*
+        * For threadirqs option we use spin_lock_irqsave() variant to prevent
+        * deadlock with ehci hrtimer callback, because hrtimer callbacks run
+        * in interrupt context even when threadirqs is specified. We can go
+        * back to spin_lock() variant when hrtimer callbacks become threaded.
+        */
+       spin_lock_irqsave(&ehci->lock, flags);
 
        status = ehci_readl(ehci, &ehci->regs->status);
 
@@ -704,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 
        /* Shared IRQ? */
        if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
-               spin_unlock(&ehci->lock);
+               spin_unlock_irqrestore(&ehci->lock, flags);
                return IRQ_NONE;
        }
 
@@ -815,7 +822,7 @@ dead:
 
        if (bh)
                ehci_work (ehci);
-       spin_unlock (&ehci->lock);
+       spin_unlock_irqrestore(&ehci->lock, flags);
        if (pcd_status)
                usb_hcd_poll_rh_status(hcd);
        return IRQ_HANDLED;
index 47b858fc50b2ee484c035cef8fe8b27c669009b5..7ae0c4d517417d46dbc2dd8f51993728fa839c3a 100644 (file)
@@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        int                     port;
        int                     mask;
        int                     changed;
+       bool                    fs_idle_delay;
 
        ehci_dbg(ehci, "suspend root hub\n");
 
@@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        ehci->bus_suspended = 0;
        ehci->owned_ports = 0;
        changed = 0;
+       fs_idle_delay = false;
        port = HCS_N_PORTS(ehci->hcs_params);
        while (port--) {
                u32 __iomem     *reg = &ehci->regs->port_status [port];
@@ -300,16 +302,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                }
 
                if (t1 != t2) {
+                       /*
+                        * On some controllers, Wake-On-Disconnect will
+                        * generate false wakeup signals until the bus
+                        * switches over to full-speed idle.  For their
+                        * sake, add a delay if we need one.
+                        */
+                       if ((t2 & PORT_WKDISC_E) &&
+                                       ehci_port_speed(ehci, t2) ==
+                                               USB_PORT_STAT_HIGH_SPEED)
+                               fs_idle_delay = true;
                        ehci_writel(ehci, t2, reg);
                        changed = 1;
                }
        }
+       spin_unlock_irq(&ehci->lock);
+
+       if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
+               /*
+                * Wait for HCD to enter low-power mode or for the bus
+                * to switch to full-speed idle.
+                */
+               usleep_range(5000, 5500);
+       }
 
        if (changed && ehci->has_tdi_phy_lpm) {
-               spin_unlock_irq(&ehci->lock);
-               msleep(5);      /* 5 ms for HCD to enter low-power mode */
                spin_lock_irq(&ehci->lock);
-
                port = HCS_N_PORTS(ehci->hcs_params);
                while (port--) {
                        u32 __iomem     *hostpc_reg = &ehci->regs->hostpc[port];
@@ -322,8 +340,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                                        port, (t3 & HOSTPC_PHCD) ?
                                        "succeeded" : "failed");
                }
+               spin_unlock_irq(&ehci->lock);
        }
-       spin_unlock_irq(&ehci->lock);
 
        /* Apparently some devices need a >= 1-uframe delay here */
        if (ehci->bus_suspended)
index b016d38199f2373cab0c789aecbd850b211345ab..eb009a457fb537f6c6674d097e852de0501e98dc 100644 (file)
@@ -203,12 +203,12 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num)
                                addr, (unsigned int)temp);
 
        addr = &ir_set->erst_base;
-       temp_64 = readq(addr);
+       temp_64 = xhci_read_64(xhci, addr);
        xhci_dbg(xhci, "  %p: ir_set.erst_base = @%08llx\n",
                        addr, temp_64);
 
        addr = &ir_set->erst_dequeue;
-       temp_64 = readq(addr);
+       temp_64 = xhci_read_64(xhci, addr);
        xhci_dbg(xhci, "  %p: ir_set.erst_dequeue = @%08llx\n",
                        addr, temp_64);
 }
@@ -412,7 +412,7 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
 {
        u64 val;
 
-       val = readq(&xhci->op_regs->cmd_ring);
+       val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
        xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n",
                        lower_32_bits(val));
        xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n",
index 873c272b3ef572f927504d0aea83b560785e6332..bce4391a0e7d708873180ab40f3ef17737f148a1 100644 (file)
@@ -1958,7 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
                xhci_warn(xhci, "WARN something wrong with SW event ring "
                                "dequeue ptr.\n");
        /* Update HC event ring dequeue pointer */
-       temp = readq(&xhci->ir_set->erst_dequeue);
+       temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
        temp &= ERST_PTR_MASK;
        /* Don't clear the EHB bit (which is RW1C) because
         * there might be more events to service.
@@ -1967,7 +1967,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "// Write event ring dequeue pointer, "
                        "preserving EHB bit");
-       writeq(((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
+       xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
                        &xhci->ir_set->erst_dequeue);
 }
 
@@ -2269,7 +2269,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "// Device context base array address = 0x%llx (DMA), %p (virt)",
                        (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
-       writeq(dma, &xhci->op_regs->dcbaa_ptr);
+       xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr);
 
        /*
         * Initialize the ring segment pool.  The ring must be a contiguous
@@ -2312,13 +2312,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
                        (unsigned long long)xhci->cmd_ring->first_seg->dma);
 
        /* Set the address in the Command Ring Control register */
-       val_64 = readq(&xhci->op_regs->cmd_ring);
+       val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
        val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
                (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) |
                xhci->cmd_ring->cycle_state;
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "// Setting command ring address to 0x%x", val);
-       writeq(val_64, &xhci->op_regs->cmd_ring);
+       xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
        xhci_dbg_cmd_ptrs(xhci);
 
        xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags);
@@ -2396,10 +2396,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "// Set ERST base address for ir_set 0 = 0x%llx",
                        (unsigned long long)xhci->erst.erst_dma_addr);
-       val_64 = readq(&xhci->ir_set->erst_base);
+       val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base);
        val_64 &= ERST_PTR_MASK;
        val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK);
-       writeq(val_64, &xhci->ir_set->erst_base);
+       xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base);
 
        /* Set the event ring dequeue address */
        xhci_set_hc_event_deq(xhci);
index 3c898c12a06b51c8926d85a3d3c5dda5d549a57f..04f986d9234f6de450888fb5178d14e3ea30dda0 100644 (file)
@@ -142,6 +142,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                                "QUIRK: Resetting on resume");
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
        }
+       if (pdev->vendor == PCI_VENDOR_ID_RENESAS &&
+                       pdev->device == 0x0015 &&
+                       pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG &&
+                       pdev->subsystem_device == 0xc0cd)
+               xhci->quirks |= XHCI_RESET_ON_RESUME;
        if (pdev->vendor == PCI_VENDOR_ID_VIA)
                xhci->quirks |= XHCI_RESET_ON_RESUME;
 }
index a0b248c345266e470441bba48247aea00b22fc13..0ed64eb68e48e226c0176c6e8c9c3f5247111c73 100644 (file)
@@ -307,13 +307,14 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
                return 0;
        }
 
-       temp_64 = readq(&xhci->op_regs->cmd_ring);
+       temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
        if (!(temp_64 & CMD_RING_RUNNING)) {
                xhci_dbg(xhci, "Command ring had been stopped\n");
                return 0;
        }
        xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;
-       writeq(temp_64 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring);
+       xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,
+                       &xhci->op_regs->cmd_ring);
 
        /* Section 4.6.1.2 of xHCI 1.0 spec says software should
         * time the completion od all xHCI commands, including
@@ -2864,8 +2865,9 @@ hw_died:
                /* Clear the event handler busy flag (RW1C);
                 * the event ring should be empty.
                 */
-               temp_64 = readq(&xhci->ir_set->erst_dequeue);
-               writeq(temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
+               temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+               xhci_write_64(xhci, temp_64 | ERST_EHB,
+                               &xhci->ir_set->erst_dequeue);
                spin_unlock(&xhci->lock);
 
                return IRQ_HANDLED;
@@ -2877,7 +2879,7 @@ hw_died:
         */
        while (xhci_handle_event(xhci) > 0) {}
 
-       temp_64 = readq(&xhci->ir_set->erst_dequeue);
+       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
        /* If necessary, update the HW's version of the event ring deq ptr. */
        if (event_ring_deq != xhci->event_ring->dequeue) {
                deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
@@ -2892,7 +2894,7 @@ hw_died:
 
        /* Clear the event handler busy flag (RW1C); event ring is empty. */
        temp_64 |= ERST_EHB;
-       writeq(temp_64, &xhci->ir_set->erst_dequeue);
+       xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue);
 
        spin_unlock(&xhci->lock);
 
@@ -2965,58 +2967,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
        }
 
        while (1) {
-               if (room_on_ring(xhci, ep_ring, num_trbs)) {
-                       union xhci_trb *trb = ep_ring->enqueue;
-                       unsigned int usable = ep_ring->enq_seg->trbs +
-                                       TRBS_PER_SEGMENT - 1 - trb;
-                       u32 nop_cmd;
-
-                       /*
-                        * Section 4.11.7.1 TD Fragments states that a link
-                        * TRB must only occur at the boundary between
-                        * data bursts (eg 512 bytes for 480M).
-                        * While it is possible to split a large fragment
-                        * we don't know the size yet.
-                        * Simplest solution is to fill the trb before the
-                        * LINK with nop commands.
-                        */
-                       if (num_trbs == 1 || num_trbs <= usable || usable == 0)
-                               break;
-
-                       if (ep_ring->type != TYPE_BULK)
-                               /*
-                                * While isoc transfers might have a buffer that
-                                * crosses a 64k boundary it is unlikely.
-                                * Since we can't add NOPs without generating
-                                * gaps in the traffic just hope it never
-                                * happens at the end of the ring.
-                                * This could be fixed by writing a LINK TRB
-                                * instead of the first NOP - however the
-                                * TRB_TYPE_LINK_LE32() calls would all need
-                                * changing to check the ring length.
-                                */
-                               break;
-
-                       if (num_trbs >= TRBS_PER_SEGMENT) {
-                               xhci_err(xhci, "Too many fragments %d, max %d\n",
-                                               num_trbs, TRBS_PER_SEGMENT - 1);
-                               return -EINVAL;
-                       }
-
-                       nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) |
-                                       ep_ring->cycle_state);
-                       ep_ring->num_trbs_free -= usable;
-                       do {
-                               trb->generic.field[0] = 0;
-                               trb->generic.field[1] = 0;
-                               trb->generic.field[2] = 0;
-                               trb->generic.field[3] = nop_cmd;
-                               trb++;
-                       } while (--usable);
-                       ep_ring->enqueue = trb;
-                       if (room_on_ring(xhci, ep_ring, num_trbs))
-                               break;
-               }
+               if (room_on_ring(xhci, ep_ring, num_trbs))
+                       break;
 
                if (ep_ring == xhci->cmd_ring) {
                        xhci_err(xhci, "Do not support expand command ring\n");
index ad364394885a221f8e52b212464ba27573433290..924a6ccdb622777a6fc71b21dfb6a0ee0792f536 100644 (file)
@@ -611,7 +611,7 @@ int xhci_run(struct usb_hcd *hcd)
        xhci_dbg(xhci, "Event ring:\n");
        xhci_debug_ring(xhci, xhci->event_ring);
        xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
-       temp_64 = readq(&xhci->ir_set->erst_dequeue);
+       temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
        temp_64 &= ~ERST_PTR_MASK;
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "ERST deq = 64'h%0lx", (long unsigned int) temp_64);
@@ -756,11 +756,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci)
 {
        xhci->s3.command = readl(&xhci->op_regs->command);
        xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);
-       xhci->s3.dcbaa_ptr = readq(&xhci->op_regs->dcbaa_ptr);
+       xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
        xhci->s3.config_reg = readl(&xhci->op_regs->config_reg);
        xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);
-       xhci->s3.erst_base = readq(&xhci->ir_set->erst_base);
-       xhci->s3.erst_dequeue = readq(&xhci->ir_set->erst_dequeue);
+       xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
+       xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
        xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending);
        xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);
 }
@@ -769,11 +769,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
 {
        writel(xhci->s3.command, &xhci->op_regs->command);
        writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
-       writeq(xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
+       xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
        writel(xhci->s3.config_reg, &xhci->op_regs->config_reg);
        writel(xhci->s3.erst_size, &xhci->ir_set->erst_size);
-       writeq(xhci->s3.erst_base, &xhci->ir_set->erst_base);
-       writeq(xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
+       xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
+       xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
        writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
        writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);
 }
@@ -783,7 +783,7 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
        u64     val_64;
 
        /* step 2: initialize command ring buffer */
-       val_64 = readq(&xhci->op_regs->cmd_ring);
+       val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
        val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
                (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
                                      xhci->cmd_ring->dequeue) &
@@ -792,7 +792,7 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "// Setting command ring address to 0x%llx",
                        (long unsigned long) val_64);
-       writeq(val_64, &xhci->op_regs->cmd_ring);
+       xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
 }
 
 /*
@@ -3842,7 +3842,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
        if (ret) {
                return ret;
        }
-       temp_64 = readq(&xhci->op_regs->dcbaa_ptr);
+       temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
        xhci_dbg_trace(xhci, trace_xhci_dbg_address,
                        "Op regs DCBAA ptr = %#016llx", temp_64);
        xhci_dbg_trace(xhci, trace_xhci_dbg_address,
@@ -4730,8 +4730,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
        struct device           *dev = hcd->self.controller;
        int                     retval;
 
-       /* Limit the block layer scatter-gather lists to half a segment. */
-       hcd->self.sg_tablesize = TRBS_PER_SEGMENT / 2;
+       /* Accept arbitrarily long scatter-gather lists */
+       hcd->self.sg_tablesize = ~0;
 
        /* support to build packet from discontinuous buffers */
        hcd->self.no_sg_constraint = 1;
index f8416639bf31cf420de82e9f82e35f67ea7c977b..58ed9d088e635c4e7d7ebeaa027da6f126f848eb 100644 (file)
 #include <linux/kernel.h>
 #include <linux/usb/hcd.h>
 
-/*
- * Registers should always be accessed with double word or quad word accesses.
- *
- * Some xHCI implementations may support 64-bit address pointers.  Registers
- * with 64-bit address pointers should be written to with dword accesses by
- * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
- * xHCI implementations that do not support 64-bit address pointers will ignore
- * the high dword, and write order is irrelevant.
- */
-#include <asm-generic/io-64-nonatomic-lo-hi.h>
-
 /* Code sharing between pci-quirks and xhci hcd */
 #include       "xhci-ext-caps.h"
 #include "pci-quirks.h"
@@ -1279,7 +1268,7 @@ union xhci_trb {
  * since the command ring is 64-byte aligned.
  * It must also be greater than 16.
  */
-#define TRBS_PER_SEGMENT       256
+#define TRBS_PER_SEGMENT       64
 /* Allow two commands + a link TRB, along with any reserved command TRBs */
 #define MAX_RSVD_CMD_TRBS      (TRBS_PER_SEGMENT - 3)
 #define TRB_SEGMENT_SIZE       (TRBS_PER_SEGMENT*16)
@@ -1614,6 +1603,34 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
 #define xhci_warn_ratelimited(xhci, fmt, args...) \
        dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 
+/*
+ * Registers should always be accessed with double word or quad word accesses.
+ *
+ * Some xHCI implementations may support 64-bit address pointers.  Registers
+ * with 64-bit address pointers should be written to with dword accesses by
+ * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
+ * xHCI implementations that do not support 64-bit address pointers will ignore
+ * the high dword, and write order is irrelevant.
+ */
+static inline u64 xhci_read_64(const struct xhci_hcd *xhci,
+               __le64 __iomem *regs)
+{
+       __u32 __iomem *ptr = (__u32 __iomem *) regs;
+       u64 val_lo = readl(ptr);
+       u64 val_hi = readl(ptr + 1);
+       return val_lo + (val_hi << 32);
+}
+static inline void xhci_write_64(struct xhci_hcd *xhci,
+                                const u64 val, __le64 __iomem *regs)
+{
+       __u32 __iomem *ptr = (__u32 __iomem *) regs;
+       u32 val_lo = lower_32_bits(val);
+       u32 val_hi = upper_32_bits(val);
+
+       writel(val_lo, ptr);
+       writel(val_hi, ptr + 1);
+}
+
 static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
 {
        return xhci->quirks & XHCI_LINK_TRB_QUIRK;
index fc192ad9cc6a60eb4a7f00d124eb0a0d1bca73fe..239ad0b1ceb6d15ddff5fa3741ca97796e70e067 100644 (file)
@@ -477,8 +477,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                musb->port1_status |=
                                                (USB_PORT_STAT_C_SUSPEND << 16)
                                                | MUSB_PORT_STAT_RESUME;
+                               musb->rh_timer = jiffies
+                                                + msecs_to_jiffies(20);
                                schedule_delayed_work(
-                                       &musb->finish_resume_work, 20);
+                                       &musb->finish_resume_work,
+                                       msecs_to_jiffies(20));
 
                                musb->xceiv->state = OTG_STATE_A_HOST;
                                musb->is_active = 1;
@@ -2157,11 +2160,19 @@ static void musb_restore_context(struct musb *musb)
        void __iomem *musb_base = musb->mregs;
        void __iomem *ep_target_regs;
        void __iomem *epio;
+       u8 power;
 
        musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
        musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
        musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
-       musb_writeb(musb_base, MUSB_POWER, musb->context.power);
+
+       /* Don't affect SUSPENDM/RESUME bits in POWER reg */
+       power = musb_readb(musb_base, MUSB_POWER);
+       power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME;
+       musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME);
+       power |= musb->context.power;
+       musb_writeb(musb_base, MUSB_POWER, power);
+
        musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);
        musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);
        musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
index ed455724017b5767f6ad849961946d7ad7af3228..abb38c3833ef46a1f8041c8a5f95fa96138b1796 100644 (file)
@@ -1183,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)
                                csr = MUSB_CSR0_H_STATUSPKT
                                        | MUSB_CSR0_TXPKTRDY;
 
+                       /* disable ping token in status phase */
+                       csr |= MUSB_CSR0_H_DIS_PING;
+
                        /* flag status stage */
                        musb->ep0_stage = MUSB_EP0_STATUS;
 
index eb634433ef095b631cd7e70df77453334cf48ddc..e2d2d8c9891bc1f7a4cf5f8a16048d58a3d4c630 100644 (file)
@@ -135,7 +135,8 @@ void musb_port_suspend(struct musb *musb, bool do_suspend)
 
                /* later, GetPortStatus will stop RESUME signaling */
                musb->port1_status |= MUSB_PORT_STAT_RESUME;
-               schedule_delayed_work(&musb->finish_resume_work, 20);
+               schedule_delayed_work(&musb->finish_resume_work,
+                                     msecs_to_jiffies(20));
        }
 }
 
@@ -158,7 +159,6 @@ void musb_port_reset(struct musb *musb, bool do_reset)
         */
        power = musb_readb(mbase, MUSB_POWER);
        if (do_reset) {
-
                /*
                 * If RESUME is set, we must make sure it stays minimum 20 ms.
                 * Then we must clear RESUME and wait a bit to let musb start
@@ -167,11 +167,22 @@ void musb_port_reset(struct musb *musb, bool do_reset)
                 * detected".
                 */
                if (power &  MUSB_POWER_RESUME) {
-                       while (time_before(jiffies, musb->rh_timer))
-                               msleep(1);
+                       long remain = (unsigned long) musb->rh_timer - jiffies;
+
+                       if (musb->rh_timer > 0 && remain > 0) {
+                               /* take into account the minimum delay after resume */
+                               schedule_delayed_work(
+                                       &musb->deassert_reset_work, remain);
+                               return;
+                       }
+
                        musb_writeb(mbase, MUSB_POWER,
-                               power & ~MUSB_POWER_RESUME);
-                       msleep(1);
+                                   power & ~MUSB_POWER_RESUME);
+
+                       /* Give the core 1 ms to clear MUSB_POWER_RESUME */
+                       schedule_delayed_work(&musb->deassert_reset_work,
+                                             msecs_to_jiffies(1));
+                       return;
                }
 
                power &= 0xf0;
@@ -180,7 +191,8 @@ void musb_port_reset(struct musb *musb, bool do_reset)
 
                musb->port1_status |= USB_PORT_STAT_RESET;
                musb->port1_status &= ~USB_PORT_STAT_ENABLE;
-               schedule_delayed_work(&musb->deassert_reset_work, 50);
+               schedule_delayed_work(&musb->deassert_reset_work,
+                                     msecs_to_jiffies(50));
        } else {
                dev_dbg(musb->controller, "root port reset stopped\n");
                musb_writeb(mbase, MUSB_POWER,
index 2a408cdaf7b2c7102098faac6d29727505f41c91..8aa59a2c5eb2485c823244012cc738ce5df7d127 100644 (file)
@@ -659,7 +659,6 @@ static int omap2430_runtime_suspend(struct device *dev)
                                OTG_INTERFSEL);
 
                omap2430_low_level_exit(musb);
-               phy_power_off(musb->phy);
        }
 
        return 0;
@@ -674,7 +673,6 @@ static int omap2430_runtime_resume(struct device *dev)
                omap2430_low_level_init(musb);
                musb_writel(musb->mregs, OTG_INTERFSEL,
                                musb->context.otg_interfsel);
-               phy_power_on(musb->phy);
        }
 
        return 0;
index 8546c8dccd51b003fc9aba3038184cd2d0eedbea..d204f745ed05e652ef168940dece89e2e16a8269 100644 (file)
@@ -159,32 +159,6 @@ put_3p3:
        return rc;
 }
 
-#ifdef CONFIG_PM_SLEEP
-#define USB_PHY_SUSP_DIG_VOL  500000
-static int msm_hsusb_config_vddcx(int high)
-{
-       int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
-       int min_vol;
-       int ret;
-
-       if (high)
-               min_vol = USB_PHY_VDD_DIG_VOL_MIN;
-       else
-               min_vol = USB_PHY_SUSP_DIG_VOL;
-
-       ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
-       if (ret) {
-               pr_err("%s: unable to set the voltage for regulator "
-                       "HSUSB_VDDCX\n", __func__);
-               return ret;
-       }
-
-       pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
-
-       return ret;
-}
-#endif
-
 static int msm_hsusb_ldo_set_mode(int on)
 {
        int ret = 0;
@@ -440,7 +414,32 @@ static int msm_otg_reset(struct usb_phy *phy)
 #define PHY_SUSPEND_TIMEOUT_USEC       (500 * 1000)
 #define PHY_RESUME_TIMEOUT_USEC        (100 * 1000)
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
+
+#define USB_PHY_SUSP_DIG_VOL  500000
+static int msm_hsusb_config_vddcx(int high)
+{
+       int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
+       int min_vol;
+       int ret;
+
+       if (high)
+               min_vol = USB_PHY_VDD_DIG_VOL_MIN;
+       else
+               min_vol = USB_PHY_SUSP_DIG_VOL;
+
+       ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
+       if (ret) {
+               pr_err("%s: unable to set the voltage for regulator "
+                       "HSUSB_VDDCX\n", __func__);
+               return ret;
+       }
+
+       pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol);
+
+       return ret;
+}
+
 static int msm_otg_suspend(struct msm_otg *motg)
 {
        struct usb_phy *phy = &motg->phy;
@@ -1733,22 +1732,18 @@ static int msm_otg_pm_resume(struct device *dev)
 }
 #endif
 
-#ifdef CONFIG_PM
 static const struct dev_pm_ops msm_otg_dev_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)
        SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,
                                msm_otg_runtime_idle)
 };
-#endif
 
 static struct platform_driver msm_otg_driver = {
        .remove = msm_otg_remove,
        .driver = {
                .name = DRIVER_NAME,
                .owner = THIS_MODULE,
-#ifdef CONFIG_PM
                .pm = &msm_otg_dev_pm_ops,
-#endif
        },
 };
 
index e6f61e4361df6bcd7f4f63b3124961c5b2be0bc0..8afa813d690bc6f7aa15c9b9c7523cf96b24099a 100644 (file)
@@ -130,7 +130,7 @@ struct usb_phy *usb_get_phy(enum usb_phy_type type)
 
        phy = __usb_find_phy(&phy_list, type);
        if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
-               pr_err("unable to find transceiver of type %s\n",
+               pr_debug("PHY: unable to find transceiver of type %s\n",
                        usb_phy_type_string(type));
                goto err0;
        }
@@ -228,7 +228,7 @@ struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)
 
        phy = __usb_find_phy_dev(dev, &phy_bind_list, index);
        if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
-               pr_err("unable to find transceiver\n");
+               dev_dbg(dev, "unable to find transceiver\n");
                goto err0;
        }
 
@@ -424,10 +424,8 @@ int usb_bind_phy(const char *dev_name, u8 index,
        unsigned long flags;
 
        phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL);
-       if (!phy_bind) {
-               pr_err("phy_bind(): No memory for phy_bind");
+       if (!phy_bind)
                return -ENOMEM;
-       }
 
        phy_bind->dev_name = dev_name;
        phy_bind->phy_dev_name = phy_dev_name;
index ce0d7b0db012ad9a31b8ea0ad71fd80881f6f8b4..44ab1298680557f840d243056d7fc4812d7adc0d 100644 (file)
@@ -152,6 +152,7 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
@@ -191,6 +192,8 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
        { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) },
+       { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) },
@@ -904,6 +907,8 @@ static const struct usb_device_id id_table_combined[] = {
        /* Crucible Devices */
        { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) },
+       /* Cressi Devices */
+       { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) },
        { }                                     /* Terminating entry */
 };
 
index a7019d1e305814867bb43792ebe55eb00dd7c3fd..e599fbfcde5f8fd5055f29f464fdaea13c130cb5 100644 (file)
@@ -50,6 +50,7 @@
 #define TI_XDS100V2_PID                0xa6d0
 
 #define FTDI_NXTCAM_PID                0xABB8 /* NXTCam for Mindstorms NXT */
+#define FTDI_EV3CON_PID                0xABB9 /* Mindstorms EV3 Console Adapter */
 
 /* US Interface Navigator (http://www.usinterface.com/) */
 #define FTDI_USINT_CAT_PID     0xb810  /* Navigator CAT and 2nd PTT lines */
 /* Sprog II (Andrew Crosland's SprogII DCC interface) */
 #define FTDI_SPROG_II          0xF0C8
 
+/*
+ * Two of the Tagsys RFID Readers
+ */
+#define FTDI_TAGSYS_LP101_PID  0xF0E9  /* Tagsys L-P101 RFID*/
+#define FTDI_TAGSYS_P200X_PID  0xF0EE  /* Tagsys Medio P200x RFID*/
+
 /* an infrared receiver for user access control with IR tags */
 #define FTDI_PIEGROUP_PID      0xF208  /* Product Id */
 
  * Manufacturer: Smart GSM Team
  */
 #define FTDI_Z3X_PID           0x0011
+
+/*
+ * Product: Cressi PC Interface
+ * Manufacturer: Cressi
+ */
+#define FTDI_CRESSI_PID                0x87d0
index 5c86f57e4afad448033baced5dbf4ca29da5a372..68fc9fe65936e712ba08e9f6825de4773b4cc9a9 100644 (file)
@@ -1362,7 +1362,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff),
+         .driver_info = (kernel_ulong_t)&net_intf5_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) },
@@ -1525,7 +1526,8 @@ static const struct usb_device_id option_ids[] = {
        /* Cinterion */
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
-       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
+               .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
        { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
                .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
index c65437cfd4a276a71ffe1e3bede20306c18fe75f..968a40201e5f6e2f2fed8de8e1668977e3f47db4 100644 (file)
@@ -139,6 +139,9 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 0)},       /* Sierra Wireless EM7700 Device Management */
        {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 2)},       /* Sierra Wireless EM7700 NMEA */
        {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 3)},       /* Sierra Wireless EM7700 Modem */
+       {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 0)},       /* Netgear AirCard 340U Device Management */
+       {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 2)},       /* Netgear AirCard 340U NMEA */
+       {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 3)},       /* Netgear AirCard 340U Modem */
 
        { }                             /* Terminating entry */
 };
index f112b079ddfc66895cf47858cfb93ff0e5a5265a..fb79775447b023aa849286856fd85fc0c19ac84e 100644 (file)
@@ -71,7 +71,8 @@ DEVICE(hp4x, HP4X_IDS);
 
 /* Suunto ANT+ USB Driver */
 #define SUUNTO_IDS()                   \
-       { USB_DEVICE(0x0fcf, 0x1008) }
+       { USB_DEVICE(0x0fcf, 0x1008) }, \
+       { USB_DEVICE(0x0fcf, 0x1009) } /* Dynastream ANT USB-m Stick */
 DEVICE(suunto, SUUNTO_IDS);
 
 /* Siemens USB/MPI adapter */
index 8470e1b114f2bff5538d9f4134e4f6222ab47500..1dd0604d1911d683015bedfe28ab86cdd42e8db4 100644 (file)
@@ -18,7 +18,9 @@ config USB_STORAGE
 
          This option depends on 'SCSI' support being enabled, but you
          probably also need 'SCSI device support: SCSI disk support'
-         (BLK_DEV_SD) for most USB storage devices.
+         (BLK_DEV_SD) for most USB storage devices.  Some devices also
+         will require 'Probe all LUNs on each SCSI device'
+         (SCSI_MULTI_LUN).
 
          To compile this driver as a module, choose M here: the
          module will be called usb-storage.
index 18509e6c21ab84e7d3133f7a0e428ba462d2a24b..9d38ddc8da492178afc8c2bebdbb8cb62cadc85f 100644 (file)
@@ -78,6 +78,8 @@ static const char* host_info(struct Scsi_Host *host)
 
 static int slave_alloc (struct scsi_device *sdev)
 {
+       struct us_data *us = host_to_us(sdev->host);
+
        /*
         * Set the INQUIRY transfer length to 36.  We don't use any of
         * the extra data and many devices choke if asked for more or
@@ -102,6 +104,10 @@ static int slave_alloc (struct scsi_device *sdev)
         */
        blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
 
+       /* Tell the SCSI layer if we know there is more than one LUN */
+       if (us->protocol == USB_PR_BULK && us->max_lun > 0)
+               sdev->sdev_bflags |= BLIST_FORCELUN;
+
        return 0;
 }
 
index 65a6a75066a81772584d884477dab435434ed19d..82e8ed0324e3c5fe75ed7548d66c2b19f509f200 100644 (file)
@@ -31,7 +31,7 @@ UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,
                "Cypress ISD-300LP",
                USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
 
-UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x0219,
+UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160,
                "Super Top",
                "USB 2.0  SATA BRIDGE",
                USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0),
index ad06255c2adeb52a185cfcd523973e8f9ecc7f9c..adbeb255616afd32d8dc9dcaa244bdafd6ed46c2 100644 (file)
@@ -1455,6 +1455,13 @@ UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
+/* Reported by Moritz Moeller-Herrmann <moritz-kernel@moeller-herrmann.de> */
+UNUSUAL_DEV(  0x0fca, 0x8004, 0x0201, 0x0201,
+               "Research In Motion",
+               "BlackBerry Bold 9000",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_MAX_SECTORS_64 ),
+
 /* Reported by Michael Stattmann <michael@stattmann.com> */
 UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
                "Sony Ericsson",
index 4fb7a8f83c8a99ff8d3412a5328b2407c98409a8..54af4e93369583e5629a4bac6d1ecdbd74f885cf 100644 (file)
@@ -186,12 +186,12 @@ static bool is_invalid_reserved_pfn(unsigned long pfn)
        if (pfn_valid(pfn)) {
                bool reserved;
                struct page *tail = pfn_to_page(pfn);
-               struct page *head = compound_trans_head(tail);
+               struct page *head = compound_head(tail);
                reserved = !!(PageReserved(head));
                if (head != tail) {
                        /*
                         * "head" is not a dangling pointer
-                        * (compound_trans_head takes care of that)
+                        * (compound_head takes care of that)
                         * but the hugepage may have been split
                         * from under us (and we may not hold a
                         * reference count on the head page so it can
index 9a68409580d5b76d8d3972e42a33314dc22f16f8..e1e22e0f01e881fe2961dbf1c43cb56f4e22cade 100644 (file)
@@ -70,7 +70,12 @@ enum {
 };
 
 struct vhost_net_ubuf_ref {
-       struct kref kref;
+       /* refcount follows semantics similar to kref:
+        *  0: object is released
+        *  1: no outstanding ubufs
+        * >1: outstanding ubufs
+        */
+       atomic_t refcount;
        wait_queue_head_t wait;
        struct vhost_virtqueue *vq;
 };
@@ -116,14 +121,6 @@ static void vhost_net_enable_zcopy(int vq)
        vhost_net_zcopy_mask |= 0x1 << vq;
 }
 
-static void vhost_net_zerocopy_done_signal(struct kref *kref)
-{
-       struct vhost_net_ubuf_ref *ubufs;
-
-       ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref);
-       wake_up(&ubufs->wait);
-}
-
 static struct vhost_net_ubuf_ref *
 vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy)
 {
@@ -134,21 +131,24 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy)
        ubufs = kmalloc(sizeof(*ubufs), GFP_KERNEL);
        if (!ubufs)
                return ERR_PTR(-ENOMEM);
-       kref_init(&ubufs->kref);
+       atomic_set(&ubufs->refcount, 1);
        init_waitqueue_head(&ubufs->wait);
        ubufs->vq = vq;
        return ubufs;
 }
 
-static void vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs)
+static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs)
 {
-       kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
+       int r = atomic_sub_return(1, &ubufs->refcount);
+       if (unlikely(!r))
+               wake_up(&ubufs->wait);
+       return r;
 }
 
 static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs)
 {
-       kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal);
-       wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount));
+       vhost_net_ubuf_put(ubufs);
+       wait_event(ubufs->wait, !atomic_read(&ubufs->refcount));
 }
 
 static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs)
@@ -306,23 +306,26 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success)
 {
        struct vhost_net_ubuf_ref *ubufs = ubuf->ctx;
        struct vhost_virtqueue *vq = ubufs->vq;
-       int cnt = atomic_read(&ubufs->kref.refcount);
+       int cnt;
+
+       rcu_read_lock_bh();
 
        /* set len to mark this desc buffers done DMA */
        vq->heads[ubuf->desc].len = success ?
                VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN;
-       vhost_net_ubuf_put(ubufs);
+       cnt = vhost_net_ubuf_put(ubufs);
 
        /*
         * Trigger polling thread if guest stopped submitting new buffers:
-        * in this case, the refcount after decrement will eventually reach 1
-        * so here it is 2.
+        * in this case, the refcount after decrement will eventually reach 1.
         * We also trigger polling periodically after each 16 packets
         * (the value 16 here is more or less arbitrary, it's tuned to trigger
         * less than 10% of times).
         */
-       if (cnt <= 2 || !(cnt % 16))
+       if (cnt <= 1 || !(cnt % 16))
                vhost_poll_queue(&vq->poll);
+
+       rcu_read_unlock_bh();
 }
 
 /* Expects to be always run from workqueue - which acts as
@@ -420,7 +423,7 @@ static void handle_tx(struct vhost_net *net)
                        msg.msg_control = ubuf;
                        msg.msg_controllen = sizeof(ubuf);
                        ubufs = nvq->ubufs;
-                       kref_get(&ubufs->kref);
+                       atomic_inc(&ubufs->refcount);
                        nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV;
                } else {
                        msg.msg_control = NULL;
@@ -502,9 +505,13 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
                        r = -ENOBUFS;
                        goto err;
                }
-               d = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
+               r = vhost_get_vq_desc(vq->dev, vq, vq->iov + seg,
                                      ARRAY_SIZE(vq->iov) - seg, &out,
                                      &in, log, log_num);
+               if (unlikely(r < 0))
+                       goto err;
+
+               d = r;
                if (d == vq->num) {
                        r = 0;
                        goto err;
@@ -529,6 +536,12 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
        *iovcount = seg;
        if (unlikely(log))
                *log_num = nlogs;
+
+       /* Detect overrun */
+       if (unlikely(datalen > 0)) {
+               r = UIO_MAXIOV + 1;
+               goto err;
+       }
        return headcount;
 err:
        vhost_discard_vq_desc(vq, headcount);
@@ -584,6 +597,14 @@ static void handle_rx(struct vhost_net *net)
                /* On error, stop handling until the next kick. */
                if (unlikely(headcount < 0))
                        break;
+               /* On overrun, truncate and discard */
+               if (unlikely(headcount > UIO_MAXIOV)) {
+                       msg.msg_iovlen = 1;
+                       err = sock->ops->recvmsg(NULL, sock, &msg,
+                                                1, MSG_DONTWAIT | MSG_TRUNC);
+                       pr_debug("Discarded rx packet: len %zd\n", sock_len);
+                       continue;
+               }
                /* OK, now we need to know about added descriptors. */
                if (!headcount) {
                        if (unlikely(vhost_enable_notify(&net->dev, vq))) {
@@ -780,7 +801,7 @@ static void vhost_net_flush(struct vhost_net *n)
                vhost_net_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs);
                mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex);
                n->tx_flush = false;
-               kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref);
+               atomic_set(&n->vqs[VHOST_NET_VQ_TX].ubufs->refcount, 1);
                mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex);
        }
 }
@@ -800,6 +821,8 @@ static int vhost_net_release(struct inode *inode, struct file *f)
                fput(tx_sock->file);
        if (rx_sock)
                fput(rx_sock->file);
+       /* Make sure no callbacks are outstanding */
+       synchronize_rcu_bh();
        /* We do an extra flush before freeing memory,
         * since jobs can re-queue themselves. */
        vhost_net_flush(n);
index 0a025b8e2a12efd2f58434b8084a45ad2454b604..e48d4a672580cd5eefaf741946435073a4e58e8c 100644 (file)
@@ -1001,6 +1001,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                        break;
                }
 
+               /* virtio-scsi spec requires byte 0 of the lun to be 1 */
+               if (unlikely(v_req.lun[0] != 1)) {
+                       vhost_scsi_send_bad_target(vs, vq, head, out);
+                       continue;
+               }
+
                /* Extract the tpgt */
                target = v_req.lun[1];
                tpg = ACCESS_ONCE(vs_tpg[target]);
index 22262a3a0e2df673e342fbe800526dab5983bd3a..dade5b7699bc240e81225e8d489136af9e0d71e0 100644 (file)
@@ -364,7 +364,7 @@ config FB_SA1100
 
 config FB_IMX
        tristate "Freescale i.MX1/21/25/27 LCD support"
-       depends on FB && IMX_HAVE_PLATFORM_IMX_FB
+       depends on FB && ARCH_MXC
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
index 1129d0e9e6403dbb6c68a0478fda17bc2117b7b9..75c8a8e7efc03ad42f2a2f44e60b61d273d62c18 100644 (file)
@@ -22,7 +22,8 @@ config EXYNOS_MIPI_DSI
 
 config EXYNOS_LCD_S6E8AX0
        bool "S6E8AX0 MIPI AMOLED LCD Driver"
-       depends on (EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE)
+       depends on EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE
+       depends on (LCD_CLASS_DEVICE = y)
        default n
        help
          If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
index bbeb8dd7f108fe9f65111337b7d1a30a039c3e2c..77d6221618f4eba677190c9a5c7acf7546b3f55d 100644 (file)
@@ -2160,8 +2160,8 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
        *five_taps = false;
 
        do {
-               in_height = DIV_ROUND_UP(height, *decim_y);
-               in_width = DIV_ROUND_UP(width, *decim_x);
+               in_height = height / *decim_y;
+               in_width = width / *decim_x;
                *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
                                in_height, out_width, out_height, mem_to_mem);
                error = (in_width > maxsinglelinewidth || !*core_clk ||
@@ -2199,8 +2199,8 @@ static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
                        dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
 
        do {
-               in_height = DIV_ROUND_UP(height, *decim_y);
-               in_width = DIV_ROUND_UP(width, *decim_x);
+               in_height = height / *decim_y;
+               in_width = width / *decim_x;
                *five_taps = in_height > out_height;
 
                if (in_width > maxsinglelinewidth)
@@ -2268,7 +2268,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
 {
        u16 in_width, in_width_max;
        int decim_x_min = *decim_x;
-       u16 in_height = DIV_ROUND_UP(height, *decim_y);
+       u16 in_height = height / *decim_y;
        const int maxsinglelinewidth =
                                dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
        const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
@@ -2287,7 +2287,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
                return -EINVAL;
 
        do {
-               in_width = DIV_ROUND_UP(width, *decim_x);
+               in_width = width / *decim_x;
        } while (*decim_x <= *x_predecim &&
                        in_width > maxsinglelinewidth && ++*decim_x);
 
@@ -2466,8 +2466,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane,
        if (r)
                return r;
 
-       in_width = DIV_ROUND_UP(in_width, x_predecim);
-       in_height = DIV_ROUND_UP(in_height, y_predecim);
+       in_width = in_width / x_predecim;
+       in_height = in_height / y_predecim;
 
        if (color_mode == OMAP_DSS_COLOR_YUV2 ||
                        color_mode == OMAP_DSS_COLOR_UYVY ||
index 7411f2674e1682d702c5e3b2af38ffcb8794b24c..23ef21ffc2c4998eee877e956f95c4b6d3166082 100644 (file)
@@ -117,7 +117,7 @@ struct dpi_clk_calc_ctx {
        /* outputs */
 
        struct dsi_clock_info dsi_cinfo;
-       unsigned long long fck;
+       unsigned long fck;
        struct dispc_clock_info dispc_cinfo;
 };
 
index efb9ee9e3c9696996a9be5d752c623ef9c2d7ff4..ba806c9e7f5486ffa40c1e6ba6e38e4dcc993ed7 100644 (file)
@@ -46,7 +46,7 @@ static struct {
 struct sdi_clk_calc_ctx {
        unsigned long pck_min, pck_max;
 
-       unsigned long long fck;
+       unsigned long fck;
        struct dispc_clock_info dispc_cinfo;
 };
 
index a06edbfa95ca6b894ce1ee01ad6ab10241937e5b..1b5d48c578e19208fbb2ef06f9e4788f93a0f5f5 100644 (file)
@@ -884,7 +884,7 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image,
                if (done == count)
                        goto out;
        }
-       if ((uintptr_t)addr & 0x2) {
+       if ((uintptr_t)(addr + done) & 0x2) {
                if ((count - done) < 2) {
                        *(u8 *)(buf + done) = ioread8(addr + done);
                        done += 1;
@@ -938,7 +938,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image,
                if (done == count)
                        goto out;
        }
-       if ((uintptr_t)addr & 0x2) {
+       if ((uintptr_t)(addr + done) & 0x2) {
                if ((count - done) < 2) {
                        iowrite8(*(u8 *)(buf + done), addr + done);
                        done += 1;
index 16830d8b777cbd8f68e7751dd37729bc2fd681f5..9911cd5fddb58415b56ad23efadef06504b822f3 100644 (file)
@@ -1289,7 +1289,7 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf,
                if (done == count)
                        goto out;
        }
-       if ((uintptr_t)addr & 0x2) {
+       if ((uintptr_t)(addr + done) & 0x2) {
                if ((count - done) < 2) {
                        *(u8 *)(buf + done) = ioread8(addr + done);
                        done += 1;
@@ -1371,7 +1371,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf,
                if (done == count)
                        goto out;
        }
-       if ((uintptr_t)addr & 0x2) {
+       if ((uintptr_t)(addr + done) & 0x2) {
                if ((count - done) < 2) {
                        iowrite8(*(u8 *)(buf + done), addr + done);
                        done += 1;
index aaf2995d37f4b595d010efa500e89bb1ae5aef5b..68b45fc9ba6a5de684f18128ca337c09e7b3657e 100644 (file)
@@ -402,7 +402,7 @@ static int __init wdt_init(void)
 
        if (!found) {
                pr_err("No W83697HF/HG could be found\n");
-               ret = -EIO;
+               ret = -ENODEV;
                goto out;
        }
 
index d75c811bfa56611a56af01504467781a4f58eccf..45e00afa7f2d70fc20241959edc659e4158847bc 100644 (file)
@@ -16,7 +16,6 @@ xen-pad-$(CONFIG_X86) += xen-acpi-pad.o
 dom0-$(CONFIG_X86) += pcpu.o
 obj-$(CONFIG_XEN_DOM0)                 += $(dom0-y)
 obj-$(CONFIG_BLOCK)                    += biomerge.o
-obj-$(CONFIG_XEN_XENCOMM)              += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)              += xen-balloon.o
 obj-$(CONFIG_XEN_SELFBALLOONING)       += xen-selfballoon.o
 obj-$(CONFIG_XEN_DEV_EVTCHN)           += xen-evtchn.o
index 37d06ea624aa953d40448bcd2a2d4943baf79fa9..61a6ac8fa8fc7ab00dcc7c33cea47981f2509d4b 100644 (file)
@@ -399,11 +399,25 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                        state = BP_EAGAIN;
                        break;
                }
+               scrub_page(page);
 
-               pfn = page_to_pfn(page);
-               frame_list[i] = pfn_to_mfn(pfn);
+               frame_list[i] = page_to_pfn(page);
+       }
 
-               scrub_page(page);
+       /*
+        * Ensure that ballooned highmem pages don't have kmaps.
+        *
+        * Do this before changing the p2m as kmap_flush_unused()
+        * reads PTEs to obtain pages (and hence needs the original
+        * p2m entry).
+        */
+       kmap_flush_unused();
+
+       /* Update direct mapping, invalidate P2M, and add to balloon. */
+       for (i = 0; i < nr_pages; i++) {
+               pfn = frame_list[i];
+               frame_list[i] = pfn_to_mfn(pfn);
+               page = pfn_to_page(pfn);
 
 #ifdef CONFIG_XEN_HAVE_PVMMU
                /*
@@ -429,11 +443,9 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                }
 #endif
 
-               balloon_append(pfn_to_page(pfn));
+               balloon_append(page);
        }
 
-       /* Ensure that ballooned highmem pages don't have kmaps. */
-       kmap_flush_unused();
        flush_tlb_all();
 
        set_xen_guest_handle(reservation.extent_start, frame_list);
index 4672e003c0ad03e0a10529fad839a1c799d179a1..f4a9e3311297b7b562f9235dae03e92b9266a9cc 100644 (file)
@@ -862,6 +862,8 @@ int bind_evtchn_to_irq(unsigned int evtchn)
                        irq = ret;
                        goto out;
                }
+               /* New interdomain events are bound to VCPU 0. */
+               bind_evtchn_to_cpu(evtchn, 0);
        } else {
                struct irq_info *info = info_for_irq(irq);
                WARN_ON(info == NULL || info->type != IRQT_EVTCHN);
diff --git a/drivers/xen/xencomm.c b/drivers/xen/xencomm.c
deleted file mode 100644 (file)
index 4793fc5..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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
- *
- * Copyright (C) IBM Corp. 2006
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <asm/page.h>
-#include <xen/xencomm.h>
-#include <xen/interface/xen.h>
-#include <asm/xen/xencomm.h>   /* for xencomm_is_phys_contiguous() */
-
-static int xencomm_init(struct xencomm_desc *desc,
-                       void *buffer, unsigned long bytes)
-{
-       unsigned long recorded = 0;
-       int i = 0;
-
-       while ((recorded < bytes) && (i < desc->nr_addrs)) {
-               unsigned long vaddr = (unsigned long)buffer + recorded;
-               unsigned long paddr;
-               int offset;
-               int chunksz;
-
-               offset = vaddr % PAGE_SIZE; /* handle partial pages */
-               chunksz = min(PAGE_SIZE - offset, bytes - recorded);
-
-               paddr = xencomm_vtop(vaddr);
-               if (paddr == ~0UL) {
-                       printk(KERN_DEBUG "%s: couldn't translate vaddr %lx\n",
-                              __func__, vaddr);
-                       return -EINVAL;
-               }
-
-               desc->address[i++] = paddr;
-               recorded += chunksz;
-       }
-
-       if (recorded < bytes) {
-               printk(KERN_DEBUG
-                      "%s: could only translate %ld of %ld bytes\n",
-                      __func__, recorded, bytes);
-               return -ENOSPC;
-       }
-
-       /* mark remaining addresses invalid (just for safety) */
-       while (i < desc->nr_addrs)
-               desc->address[i++] = XENCOMM_INVALID;
-
-       desc->magic = XENCOMM_MAGIC;
-
-       return 0;
-}
-
-static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask,
-                                         void *buffer, unsigned long bytes)
-{
-       struct xencomm_desc *desc;
-       unsigned long buffer_ulong = (unsigned long)buffer;
-       unsigned long start = buffer_ulong & PAGE_MASK;
-       unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK;
-       unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT;
-       unsigned long size = sizeof(*desc) +
-               sizeof(desc->address[0]) * nr_addrs;
-
-       /*
-        * slab allocator returns at least sizeof(void*) aligned pointer.
-        * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might
-        * cross page boundary.
-        */
-       if (sizeof(*desc) > sizeof(void *)) {
-               unsigned long order = get_order(size);
-               desc = (struct xencomm_desc *)__get_free_pages(gfp_mask,
-                                                              order);
-               if (desc == NULL)
-                       return NULL;
-
-               desc->nr_addrs =
-                       ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) /
-                       sizeof(*desc->address);
-       } else {
-               desc = kmalloc(size, gfp_mask);
-               if (desc == NULL)
-                       return NULL;
-
-               desc->nr_addrs = nr_addrs;
-       }
-       return desc;
-}
-
-void xencomm_free(struct xencomm_handle *desc)
-{
-       if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) {
-               struct xencomm_desc *desc__ = (struct xencomm_desc *)desc;
-               if (sizeof(*desc__) > sizeof(void *)) {
-                       unsigned long size = sizeof(*desc__) +
-                               sizeof(desc__->address[0]) * desc__->nr_addrs;
-                       unsigned long order = get_order(size);
-                       free_pages((unsigned long)__va(desc), order);
-               } else
-                       kfree(__va(desc));
-       }
-}
-
-static int xencomm_create(void *buffer, unsigned long bytes,
-                         struct xencomm_desc **ret, gfp_t gfp_mask)
-{
-       struct xencomm_desc *desc;
-       int rc;
-
-       pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes);
-
-       if (bytes == 0) {
-               /* don't create a descriptor; Xen recognizes NULL. */
-               BUG_ON(buffer != NULL);
-               *ret = NULL;
-               return 0;
-       }
-
-       BUG_ON(buffer == NULL); /* 'bytes' is non-zero */
-
-       desc = xencomm_alloc(gfp_mask, buffer, bytes);
-       if (!desc) {
-               printk(KERN_DEBUG "%s failure\n", "xencomm_alloc");
-               return -ENOMEM;
-       }
-
-       rc = xencomm_init(desc, buffer, bytes);
-       if (rc) {
-               printk(KERN_DEBUG "%s failure: %d\n", "xencomm_init", rc);
-               xencomm_free((struct xencomm_handle *)__pa(desc));
-               return rc;
-       }
-
-       *ret = desc;
-       return 0;
-}
-
-static struct xencomm_handle *xencomm_create_inline(void *ptr)
-{
-       unsigned long paddr;
-
-       BUG_ON(!xencomm_is_phys_contiguous((unsigned long)ptr));
-
-       paddr = (unsigned long)xencomm_pa(ptr);
-       BUG_ON(paddr & XENCOMM_INLINE_FLAG);
-       return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
-}
-
-/* "mini" routine, for stack-based communications: */
-static int xencomm_create_mini(void *buffer,
-       unsigned long bytes, struct xencomm_mini *xc_desc,
-       struct xencomm_desc **ret)
-{
-       int rc = 0;
-       struct xencomm_desc *desc;
-       BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0);
-
-       desc = (void *)xc_desc;
-
-       desc->nr_addrs = XENCOMM_MINI_ADDRS;
-
-       rc = xencomm_init(desc, buffer, bytes);
-       if (!rc)
-               *ret = desc;
-
-       return rc;
-}
-
-struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes)
-{
-       int rc;
-       struct xencomm_desc *desc;
-
-       if (xencomm_is_phys_contiguous((unsigned long)ptr))
-               return xencomm_create_inline(ptr);
-
-       rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL);
-
-       if (rc || desc == NULL)
-               return NULL;
-
-       return xencomm_pa(desc);
-}
-
-struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes,
-                       struct xencomm_mini *xc_desc)
-{
-       int rc;
-       struct xencomm_desc *desc = NULL;
-
-       if (xencomm_is_phys_contiguous((unsigned long)ptr))
-               return xencomm_create_inline(ptr);
-
-       rc = xencomm_create_mini(ptr, bytes, xc_desc,
-                               &desc);
-
-       if (rc)
-               return NULL;
-
-       return xencomm_pa(desc);
-}
index 24084732b1d0b264b5c3262796f1ec3dd5fc505f..80ef38c73e5a16af0f9443d94bec3aae700370df 100644 (file)
@@ -41,19 +41,8 @@ static const struct dentry_operations anon_inodefs_dentry_operations = {
 static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
                                int flags, const char *dev_name, void *data)
 {
-       struct dentry *root;
-       root = mount_pseudo(fs_type, "anon_inode:", NULL,
+       return mount_pseudo(fs_type, "anon_inode:", NULL,
                        &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
-       if (!IS_ERR(root)) {
-               struct super_block *s = root->d_sb;
-               anon_inode_inode = alloc_anon_inode(s);
-               if (IS_ERR(anon_inode_inode)) {
-                       dput(root);
-                       deactivate_locked_super(s);
-                       root = ERR_CAST(anon_inode_inode);
-               }
-       }
-       return root;
 }
 
 static struct file_system_type anon_inode_fs_type = {
@@ -175,22 +164,15 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd);
 
 static int __init anon_inode_init(void)
 {
-       int error;
-
-       error = register_filesystem(&anon_inode_fs_type);
-       if (error)
-               goto err_exit;
        anon_inode_mnt = kern_mount(&anon_inode_fs_type);
-       if (IS_ERR(anon_inode_mnt)) {
-               error = PTR_ERR(anon_inode_mnt);
-               goto err_unregister_filesystem;
-       }
-       return 0;
+       if (IS_ERR(anon_inode_mnt))
+               panic("anon_inode_init() kernel mount failed (%ld)\n", PTR_ERR(anon_inode_mnt));
 
-err_unregister_filesystem:
-       unregister_filesystem(&anon_inode_fs_type);
-err_exit:
-       panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
+       anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
+       if (IS_ERR(anon_inode_inode))
+               panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode));
+
+       return 0;
 }
 
 fs_initcall(anon_inode_init);
index 0bad24ddc2e7a39abf29547f24173cc050017d15..4f70f383132cc9dfe143c570fbb9759967fefc6f 100644 (file)
@@ -114,6 +114,14 @@ void bio_integrity_free(struct bio *bio)
 }
 EXPORT_SYMBOL(bio_integrity_free);
 
+static inline unsigned int bip_integrity_vecs(struct bio_integrity_payload *bip)
+{
+       if (bip->bip_slab == BIO_POOL_NONE)
+               return BIP_INLINE_VECS;
+
+       return bvec_nr_vecs(bip->bip_slab);
+}
+
 /**
  * bio_integrity_add_page - Attach integrity metadata
  * @bio:       bio to update
@@ -129,7 +137,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
        struct bio_integrity_payload *bip = bio->bi_integrity;
        struct bio_vec *iv;
 
-       if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_slab)) {
+       if (bip->bip_vcnt >= bip_integrity_vecs(bip)) {
                printk(KERN_ERR "%s: bip_vec full\n", __func__);
                return 0;
        }
@@ -226,7 +234,8 @@ unsigned int bio_integrity_tag_size(struct bio *bio)
 }
 EXPORT_SYMBOL(bio_integrity_tag_size);
 
-int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set)
+static int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len,
+                            int set)
 {
        struct bio_integrity_payload *bip = bio->bi_integrity;
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
@@ -449,11 +458,10 @@ static int bio_integrity_verify(struct bio *bio)
        struct blk_integrity_exchg bix;
        struct bio_vec *bv;
        sector_t sector = bio->bi_integrity->bip_iter.bi_sector;
-       unsigned int sectors, total, ret;
+       unsigned int sectors, ret = 0;
        void *prot_buf = bio->bi_integrity->bip_buf;
        int i;
 
-       ret = total = 0;
        bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
        bix.sector_size = bi->sector_size;
 
@@ -475,8 +483,6 @@ static int bio_integrity_verify(struct bio *bio)
                sectors = bv->bv_len / bi->sector_size;
                sector += sectors;
                prot_buf += sectors * bi->tuple_size;
-               total += sectors * bi->tuple_size;
-               BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
 
                kunmap_atomic(kaddr);
        }
index 75c49a38223969c1f7256868cb3b09fc7d3bd286..8754e7b6eb49330055a1efc69e86451fa9c65ff8 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -611,7 +611,6 @@ EXPORT_SYMBOL(bio_clone_fast);
 struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
                             struct bio_set *bs)
 {
-       unsigned nr_iovecs = 0;
        struct bvec_iter iter;
        struct bio_vec bv;
        struct bio *bio;
@@ -638,10 +637,7 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
         *    __bio_clone_fast() anyways.
         */
 
-       bio_for_each_segment(bv, bio_src, iter)
-               nr_iovecs++;
-
-       bio = bio_alloc_bioset(gfp_mask, nr_iovecs, bs);
+       bio = bio_alloc_bioset(gfp_mask, bio_segments(bio_src), bs);
        if (!bio)
                return NULL;
 
@@ -650,9 +646,18 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
        bio->bi_iter.bi_sector  = bio_src->bi_iter.bi_sector;
        bio->bi_iter.bi_size    = bio_src->bi_iter.bi_size;
 
+       if (bio->bi_rw & REQ_DISCARD)
+               goto integrity_clone;
+
+       if (bio->bi_rw & REQ_WRITE_SAME) {
+               bio->bi_io_vec[bio->bi_vcnt++] = bio_src->bi_io_vec[0];
+               goto integrity_clone;
+       }
+
        bio_for_each_segment(bv, bio_src, iter)
                bio->bi_io_vec[bio->bi_vcnt++] = bv;
 
+integrity_clone:
        if (bio_integrity(bio_src)) {
                int ret;
 
index 5215f04260b21bee4026fbbd6132067880b0e224..81ea55314b1ff0f61d2691f786a481889cd831ac 100644 (file)
@@ -3839,7 +3839,6 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
                        rb_erase(&ref->rb_node, &head->ref_root);
                        atomic_dec(&delayed_refs->num_entries);
                        btrfs_put_delayed_ref(ref);
-                       cond_resched_lock(&head->lock);
                }
                if (head->must_insert_reserved)
                        pin_bytes = true;
index 184e9cb396477f92499a9b3834f32732f46ed38c..d3d44486290bf6c8dce015ec24f440874ceb6d67 100644 (file)
@@ -5154,7 +5154,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                        return ERR_CAST(inode);
        }
 
-       return d_splice_alias(inode, dentry);
+       return d_materialise_unique(dentry, inode);
 }
 
 unsigned char btrfs_filetype_table[] = {
index 383ab455bfa7ce421f0f0c380224a10820e3801e..a6d8efa46bfe50129b54ef11e4a854adad3b56ac 100644 (file)
@@ -3537,20 +3537,6 @@ out:
        return ret;
 }
 
-static long btrfs_ioctl_global_rsv(struct btrfs_root *root, void __user *arg)
-{
-       struct btrfs_block_rsv *block_rsv = &root->fs_info->global_block_rsv;
-       u64 reserved;
-
-       spin_lock(&block_rsv->lock);
-       reserved = block_rsv->reserved;
-       spin_unlock(&block_rsv->lock);
-
-       if (arg && copy_to_user(arg, &reserved, sizeof(reserved)))
-               return -EFAULT;
-       return 0;
-}
-
 /*
  * there are many ways the trans_start and trans_end ioctls can lead
  * to deadlocks.  They should only be used by applications that
@@ -4757,8 +4743,6 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_logical_to_ino(root, argp);
        case BTRFS_IOC_SPACE_INFO:
                return btrfs_ioctl_space_info(root, argp);
-       case BTRFS_IOC_GLOBAL_RSV:
-               return btrfs_ioctl_global_rsv(root, argp);
        case BTRFS_IOC_SYNC: {
                int ret;
 
index 9c8d1a3fdc3a203d2b81e79b772af926fc639030..9dde9717c1b9264124d007184bc4c4d60276d99c 100644 (file)
@@ -1332,6 +1332,16 @@ verbose_printk(KERN_DEBUG "btrfs: find_extent_clone: data_offset=%llu, "
        }
 
        if (cur_clone_root) {
+               if (compressed != BTRFS_COMPRESS_NONE) {
+                       /*
+                        * Offsets given by iterate_extent_inodes() are relative
+                        * to the start of the extent, we need to add logical
+                        * offset from the file extent item.
+                        * (See why at backref.c:check_extent_in_eb())
+                        */
+                       cur_clone_root->offset += btrfs_file_extent_offset(eb,
+                                                                          fi);
+               }
                *found = cur_clone_root;
                ret = 0;
        } else {
index 97cc24198554cedd4ada307f2bbe99b80edf4ded..d04db817be5c8271f531d87d0ee9a4a950f616f8 100644 (file)
@@ -566,7 +566,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                kfree(num);
 
                                if (info->max_inline) {
-                                       info->max_inline = max_t(u64,
+                                       info->max_inline = min_t(u64,
                                                info->max_inline,
                                                root->sectorsize);
                                }
@@ -855,6 +855,7 @@ static struct dentry *get_default_root(struct super_block *sb,
        struct btrfs_path *path;
        struct btrfs_key location;
        struct inode *inode;
+       struct dentry *dentry;
        u64 dir_id;
        int new = 0;
 
@@ -925,7 +926,13 @@ setup_root:
                return dget(sb->s_root);
        }
 
-       return d_obtain_alias(inode);
+       dentry = d_obtain_alias(inode);
+       if (!IS_ERR(dentry)) {
+               spin_lock(&dentry->d_lock);
+               dentry->d_flags &= ~DCACHE_DISCONNECTED;
+               spin_unlock(&dentry->d_lock);
+       }
+       return dentry;
 }
 
 static int btrfs_fill_super(struct super_block *sb,
index 782374d8fd1970ee9d6b4742fc2e213dc4d2e637..865f4cf9a7695899c18d368f6ab2629340994dce 100644 (file)
@@ -578,8 +578,14 @@ static int add_device_membership(struct btrfs_fs_info *fs_info)
                return -ENOMEM;
 
        list_for_each_entry(dev, &fs_devices->devices, dev_list) {
-               struct hd_struct *disk = dev->bdev->bd_part;
-               struct kobject *disk_kobj = &part_to_dev(disk)->kobj;
+               struct hd_struct *disk;
+               struct kobject *disk_kobj;
+
+               if (!dev->bdev)
+                       continue;
+
+               disk = dev->bdev->bd_part;
+               disk_kobj = &part_to_dev(disk)->kobj;
 
                error = sysfs_create_link(fs_info->device_dir_kobj,
                                          disk_kobj, disk_kobj->name);
index 4c2d452c4bfc0abad11cf3e3b0577d62ed3ef240..21887d63dad589a53e3da21fccb00c45a5c28ab6 100644 (file)
@@ -54,11 +54,6 @@ static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode,
        return acl;
 }
 
-void ceph_forget_all_cached_acls(struct inode *inode)
-{
-       forget_all_cached_acls(inode);
-}
-
 struct posix_acl *ceph_get_acl(struct inode *inode, int type)
 {
        int size;
@@ -160,11 +155,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
                        goto out_dput;
        }
 
-       if (value)
-               ret = __ceph_setxattr(dentry, name, value, size, 0);
-       else
-               ret = __ceph_removexattr(dentry, name);
-
+       ret = __ceph_setxattr(dentry, name, value, size, 0);
        if (ret) {
                if (new_mode != old_mode) {
                        newattrs.ia_mode = old_mode;
index 6da4df84ba300824a8a6afdea9f2a20121600765..45eda6d7a40c2030db42fc06fa2d741f180c254f 100644 (file)
@@ -100,6 +100,14 @@ static unsigned fpos_off(loff_t p)
        return p & 0xffffffff;
 }
 
+static int fpos_cmp(loff_t l, loff_t r)
+{
+       int v = ceph_frag_compare(fpos_frag(l), fpos_frag(r));
+       if (v)
+               return v;
+       return (int)(fpos_off(l) - fpos_off(r));
+}
+
 /*
  * When possible, we try to satisfy a readdir by peeking at the
  * dcache.  We make this work by carefully ordering dentries on
@@ -156,7 +164,7 @@ more:
                if (!d_unhashed(dentry) && dentry->d_inode &&
                    ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
                    ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
-                   ctx->pos <= di->offset)
+                   fpos_cmp(ctx->pos, di->offset) <= 0)
                        break;
                dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
                     dentry->d_name.len, dentry->d_name.name, di->offset,
@@ -695,9 +703,8 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
        ceph_mdsc_put_request(req);
 
        if (!err)
-               err = ceph_init_acl(dentry, dentry->d_inode, dir);
-
-       if (err)
+               ceph_init_acl(dentry, dentry->d_inode, dir);
+       else
                d_drop(dentry);
        return err;
 }
@@ -735,7 +742,9 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
        if (!err && !req->r_reply_info.head->is_dentry)
                err = ceph_handle_notrace_create(dir, dentry);
        ceph_mdsc_put_request(req);
-       if (err)
+       if (!err)
+               ceph_init_acl(dentry, dentry->d_inode, dir);
+       else
                d_drop(dentry);
        return err;
 }
@@ -776,7 +785,9 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                err = ceph_handle_notrace_create(dir, dentry);
        ceph_mdsc_put_request(req);
 out:
-       if (err < 0)
+       if (!err)
+               ceph_init_acl(dentry, dentry->d_inode, dir);
+       else
                d_drop(dentry);
        return err;
 }
index dfd2ce3419f812f71769406023d0ff33cea3a35b..09c7afe32e496c7dfe20d527106c7a184248c3ca 100644 (file)
@@ -286,6 +286,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
        } else {
                dout("atomic_open finish_open on dn %p\n", dn);
                if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
+                       ceph_init_acl(dentry, dentry->d_inode, dir);
                        *opened |= FILE_CREATED;
                }
                err = finish_open(file, dentry, ceph_open, opened);
index 2df963f1cf5a3b84615772e793cd45eeddec801f..10a4ccbf38dab2c6f26407e7383815986f337bc0 100644 (file)
@@ -144,7 +144,11 @@ enum {
        Opt_ino32,
        Opt_noino32,
        Opt_fscache,
-       Opt_nofscache
+       Opt_nofscache,
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       Opt_acl,
+#endif
+       Opt_noacl
 };
 
 static match_table_t fsopt_tokens = {
@@ -172,6 +176,10 @@ static match_table_t fsopt_tokens = {
        {Opt_noino32, "noino32"},
        {Opt_fscache, "fsc"},
        {Opt_nofscache, "nofsc"},
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       {Opt_acl, "acl"},
+#endif
+       {Opt_noacl, "noacl"},
        {-1, NULL}
 };
 
@@ -271,6 +279,14 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_nofscache:
                fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
                break;
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       case Opt_acl:
+               fsopt->sb_flags |= MS_POSIXACL;
+               break;
+#endif
+       case Opt_noacl:
+               fsopt->sb_flags &= ~MS_POSIXACL;
+               break;
        default:
                BUG_ON(token);
        }
@@ -438,6 +454,13 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
        else
                seq_puts(m, ",nofsc");
 
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       if (fsopt->sb_flags & MS_POSIXACL)
+               seq_puts(m, ",acl");
+       else
+               seq_puts(m, ",noacl");
+#endif
+
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
        if (fsopt->rsize != CEPH_RSIZE_DEFAULT)
@@ -819,9 +842,6 @@ static int ceph_set_super(struct super_block *s, void *data)
 
        s->s_flags = fsc->mount_options->sb_flags;
        s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
-#ifdef CONFIG_CEPH_FS_POSIX_ACL
-       s->s_flags |= MS_POSIXACL;
-#endif
 
        s->s_xattr = ceph_xattr_handlers;
        s->s_fs_info = fsc;
@@ -911,6 +931,10 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
        struct ceph_options *opt = NULL;
 
        dout("ceph_mount\n");
+
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       flags |= MS_POSIXACL;
+#endif
        err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path);
        if (err < 0) {
                res = ERR_PTR(err);
index 19793b56d0a7d3a90330c36a218312728b42e45e..d8801a95b6857d514fc27e440af8d476513cae3e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/wait.h>
 #include <linux/writeback.h>
 #include <linux/slab.h>
+#include <linux/posix_acl.h>
 
 #include <linux/ceph/libceph.h>
 
@@ -743,7 +744,11 @@ extern const struct xattr_handler *ceph_xattr_handlers[];
 struct posix_acl *ceph_get_acl(struct inode *, int);
 int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 int ceph_init_acl(struct dentry *, struct inode *, struct inode *);
-void ceph_forget_all_cached_acls(struct inode *inode);
+
+static inline void ceph_forget_all_cached_acls(struct inode *inode)
+{
+       forget_all_cached_acls(inode);
+}
 
 #else
 
index 898b6565ad3e2c114baca0282fafea6a5643071a..a55ec37378c6730efa476d3d6a923e37ba10ec72 100644 (file)
@@ -12,6 +12,9 @@
 #define XATTR_CEPH_PREFIX "ceph."
 #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
 
+static int __remove_xattr(struct ceph_inode_info *ci,
+                         struct ceph_inode_xattr *xattr);
+
 /*
  * List of handlers for synthetic system.* attributes. Other
  * attributes are handled directly.
@@ -319,8 +322,7 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode,
 static int __set_xattr(struct ceph_inode_info *ci,
                           const char *name, int name_len,
                           const char *val, int val_len,
-                          int dirty,
-                          int should_free_name, int should_free_val,
+                          int flags, int update_xattr,
                           struct ceph_inode_xattr **newxattr)
 {
        struct rb_node **p;
@@ -349,12 +351,31 @@ static int __set_xattr(struct ceph_inode_info *ci,
                xattr = NULL;
        }
 
+       if (update_xattr) {
+               int err = 0;
+               if (xattr && (flags & XATTR_CREATE))
+                       err = -EEXIST;
+               else if (!xattr && (flags & XATTR_REPLACE))
+                       err = -ENODATA;
+               if (err) {
+                       kfree(name);
+                       kfree(val);
+                       return err;
+               }
+               if (update_xattr < 0) {
+                       if (xattr)
+                               __remove_xattr(ci, xattr);
+                       kfree(name);
+                       return 0;
+               }
+       }
+
        if (!xattr) {
                new = 1;
                xattr = *newxattr;
                xattr->name = name;
                xattr->name_len = name_len;
-               xattr->should_free_name = should_free_name;
+               xattr->should_free_name = update_xattr;
 
                ci->i_xattrs.count++;
                dout("__set_xattr count=%d\n", ci->i_xattrs.count);
@@ -364,7 +385,7 @@ static int __set_xattr(struct ceph_inode_info *ci,
                if (xattr->should_free_val)
                        kfree((void *)xattr->val);
 
-               if (should_free_name) {
+               if (update_xattr) {
                        kfree((void *)name);
                        name = xattr->name;
                }
@@ -379,8 +400,8 @@ static int __set_xattr(struct ceph_inode_info *ci,
                xattr->val = "";
 
        xattr->val_len = val_len;
-       xattr->dirty = dirty;
-       xattr->should_free_val = (val && should_free_val);
+       xattr->dirty = update_xattr;
+       xattr->should_free_val = (val && update_xattr);
 
        if (new) {
                rb_link_node(&xattr->node, parent, p);
@@ -442,7 +463,7 @@ static int __remove_xattr(struct ceph_inode_info *ci,
                          struct ceph_inode_xattr *xattr)
 {
        if (!xattr)
-               return -EOPNOTSUPP;
+               return -ENODATA;
 
        rb_erase(&xattr->node, &ci->i_xattrs.index);
 
@@ -588,7 +609,7 @@ start:
                        p += len;
 
                        err = __set_xattr(ci, name, namelen, val, len,
-                                         0, 0, 0, &xattrs[numattr]);
+                                         0, 0, &xattrs[numattr]);
 
                        if (err < 0)
                                goto bad;
@@ -850,6 +871,9 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
 
        dout("setxattr value=%.*s\n", (int)size, value);
 
+       if (!value)
+               flags |= CEPH_XATTR_REMOVE;
+
        /* do request */
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
                                       USE_AUTH_MDS);
@@ -892,7 +916,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
        struct ceph_inode_info *ci = ceph_inode(inode);
        int issued;
        int err;
-       int dirty;
+       int dirty = 0;
        int name_len = strlen(name);
        int val_len = size;
        char *newname = NULL;
@@ -953,12 +977,14 @@ retry:
                goto retry;
        }
 
-       err = __set_xattr(ci, newname, name_len, newval,
-                         val_len, 1, 1, 1, &xattr);
+       err = __set_xattr(ci, newname, name_len, newval, val_len,
+                         flags, value ? 1 : -1, &xattr);
 
-       dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
-       ci->i_xattrs.dirty = true;
-       inode->i_ctime = CURRENT_TIME;
+       if (!err) {
+               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
+               ci->i_xattrs.dirty = true;
+               inode->i_ctime = CURRENT_TIME;
+       }
 
        spin_unlock(&ci->i_ceph_lock);
        if (dirty)
index 8f9b4f710d4a31ea651f64586fa2469edd92c2fa..7ff866dbb89eb7b31033ce1e99f7b56f664fbdf6 100644 (file)
@@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
        return rc;
 }
 
-static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
-               __u16 fid, u32 *pacllen)
+struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
+               const struct cifs_fid *cifsfid, u32 *pacllen)
 {
        struct cifs_ntsd *pntsd = NULL;
        unsigned int xid;
@@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
                return ERR_CAST(tlink);
 
        xid = get_xid();
-       rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
+       rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
+                               pacllen);
        free_xid(xid);
 
        cifs_put_tlink(tlink);
@@ -946,7 +947,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
        if (!open_file)
                return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
-       pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
+       pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
        cifsFileInfo_put(open_file);
        return pntsd;
 }
@@ -1006,19 +1007,31 @@ out:
 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
 int
 cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
-                 struct inode *inode, const char *path, const __u16 *pfid)
+                 struct inode *inode, const char *path,
+                 const struct cifs_fid *pfid)
 {
        struct cifs_ntsd *pntsd = NULL;
        u32 acllen = 0;
        int rc = 0;
+       struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
+       struct cifs_tcon *tcon;
 
        cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
 
-       if (pfid)
-               pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
-       else
-               pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
 
+       if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
+               pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
+                                                         &acllen);
+       else if (tcon->ses->server->ops->get_acl)
+               pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
+                                                       &acllen);
+       else {
+               cifs_put_tlink(tlink);
+               return -EOPNOTSUPP;
+       }
        /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
        if (IS_ERR(pntsd)) {
                rc = PTR_ERR(pntsd);
@@ -1030,6 +1043,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
                        cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
        }
 
+       cifs_put_tlink(tlink);
+
        return rc;
 }
 
@@ -1043,15 +1058,30 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
        __u32 secdesclen = 0;
        struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
        struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
+       struct cifs_tcon *tcon;
+
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       tcon = tlink_tcon(tlink);
 
        cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
 
        /* Get the security descriptor */
-       pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
+
+       if (tcon->ses->server->ops->get_acl == NULL) {
+               cifs_put_tlink(tlink);
+               return -EOPNOTSUPP;
+       }
+
+       pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
+                                               &secdesclen);
        if (IS_ERR(pntsd)) {
                rc = PTR_ERR(pntsd);
                cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
-               goto out;
+               cifs_put_tlink(tlink);
+               return rc;
        }
 
        /*
@@ -1064,6 +1094,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
        pnntsd = kmalloc(secdesclen, GFP_KERNEL);
        if (!pnntsd) {
                kfree(pntsd);
+               cifs_put_tlink(tlink);
                return -ENOMEM;
        }
 
@@ -1072,14 +1103,18 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
 
        cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
 
+       if (tcon->ses->server->ops->set_acl == NULL)
+               rc = -EOPNOTSUPP;
+
        if (!rc) {
                /* Set the security descriptor */
-               rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
+               rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
+                                                    path, aclflag);
                cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
        }
+       cifs_put_tlink(tlink);
 
        kfree(pnntsd);
        kfree(pntsd);
-out:
        return rc;
 }
index a245d1809ed8d63dc7ee5cbc5320bb117a12c71e..c0f3718b77a83e7e0e010b089e436356e83a1eb7 100644 (file)
@@ -323,7 +323,8 @@ struct smb_version_operations {
        /* async read from the server */
        int (*async_readv)(struct cifs_readdata *);
        /* async write to the server */
-       int (*async_writev)(struct cifs_writedata *);
+       int (*async_writev)(struct cifs_writedata *,
+                           void (*release)(struct kref *));
        /* sync read from the server */
        int (*sync_read)(const unsigned int, struct cifsFileInfo *,
                         struct cifs_io_parms *, unsigned int *, char **,
@@ -395,6 +396,12 @@ struct smb_version_operations {
        int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
                        const char *, const void *, const __u16,
                        const struct nls_table *, int);
+       struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
+                       const char *, u32 *);
+       struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
+                       const struct cifs_fid *, u32 *);
+       int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
+                       int);
 };
 
 struct smb_version_values {
@@ -506,7 +513,7 @@ struct cifs_mnt_data {
 static inline unsigned int
 get_rfc1002_length(void *buf)
 {
-       return be32_to_cpu(*((__be32 *)buf));
+       return be32_to_cpu(*((__be32 *)buf)) & 0xffffff;
 }
 
 static inline void
@@ -1064,7 +1071,7 @@ struct cifs_writedata {
        unsigned int                    pagesz;
        unsigned int                    tailsz;
        unsigned int                    nr_pages;
-       struct page                     *pages[1];
+       struct page                     *pages[];
 };
 
 /*
index 79e6e9a93a8ce984420ef8dc68fa3d941ff1f045..acc4ee8ed0759a7e786709ea61d5077970b3ef3e 100644 (file)
@@ -151,7 +151,7 @@ extern struct inode *cifs_iget(struct super_block *sb,
 
 extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
                               FILE_ALL_INFO *data, struct super_block *sb,
-                              int xid, const __u16 *fid);
+                              int xid, const struct cifs_fid *fid);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, unsigned int xid);
@@ -162,11 +162,13 @@ extern int cifs_rename_pending_delete(const char *full_path,
                                      const unsigned int xid);
 extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
                              struct cifs_fattr *fattr, struct inode *inode,
-                             const char *path, const __u16 *pfid);
+                             const char *path, const struct cifs_fid *pfid);
 extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
                                        kuid_t, kgid_t);
 extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
                                        const char *, u32 *);
+extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
+                                               const struct cifs_fid *, u32 *);
 extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
                                const char *, int);
 
@@ -488,7 +490,8 @@ void cifs_readdata_release(struct kref *refcount);
 int cifs_async_readv(struct cifs_readdata *rdata);
 int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
 
-int cifs_async_writev(struct cifs_writedata *wdata);
+int cifs_async_writev(struct cifs_writedata *wdata,
+                     void (*release)(struct kref *kref));
 void cifs_writev_complete(struct work_struct *work);
 struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
                                                work_func_t complete);
index 4d881c35eecaa035717b52d9c19b9dac00dd9dae..f3264bd7a83d9427a158130a7d4a842443bd8b53 100644 (file)
@@ -1910,7 +1910,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
 
        do {
                server = tlink_tcon(wdata->cfile->tlink)->ses->server;
-               rc = server->ops->async_writev(wdata);
+               rc = server->ops->async_writev(wdata, cifs_writedata_release);
        } while (rc == -EAGAIN);
 
        for (i = 0; i < wdata->nr_pages; i++) {
@@ -1962,15 +1962,9 @@ cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
 {
        struct cifs_writedata *wdata;
 
-       /* this would overflow */
-       if (nr_pages == 0) {
-               cifs_dbg(VFS, "%s: called with nr_pages == 0!\n", __func__);
-               return NULL;
-       }
-
        /* writedata + number of page pointers */
        wdata = kzalloc(sizeof(*wdata) +
-                       sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
+                       sizeof(struct page *) * nr_pages, GFP_NOFS);
        if (wdata != NULL) {
                kref_init(&wdata->refcount);
                INIT_LIST_HEAD(&wdata->list);
@@ -2031,7 +2025,8 @@ cifs_writev_callback(struct mid_q_entry *mid)
 
 /* cifs_async_writev - send an async write, and set up mid to handle result */
 int
-cifs_async_writev(struct cifs_writedata *wdata)
+cifs_async_writev(struct cifs_writedata *wdata,
+                 void (*release)(struct kref *kref))
 {
        int rc = -EACCES;
        WRITE_REQ *smb = NULL;
@@ -2105,7 +2100,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
        if (rc == 0)
                cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
        else
-               kref_put(&wdata->refcount, cifs_writedata_release);
+               kref_put(&wdata->refcount, release);
 
 async_writev_out:
        cifs_small_buf_release(smb);
index d3a6796caa5a3fce527584ae6437b2a446663da4..3db0c5fd9a1109629764cf5f2b759dd9ddd8cd8a 100644 (file)
@@ -378,7 +378,7 @@ cifs_create_get_file_info:
                                              xid);
        else {
                rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
-                                        xid, &fid->netfid);
+                                        xid, fid);
                if (newinode) {
                        if (server->ops->set_lease_key)
                                server->ops->set_lease_key(newinode, fid);
index a7eda8ebfacc8ca90210358b5e2300c7530e0223..834fce759d8075313261dfa0a01c76ba9c2cb5b3 100644 (file)
@@ -244,7 +244,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
                                              xid);
        else
                rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
-                                        xid, &fid->netfid);
+                                        xid, fid);
 
 out:
        kfree(buf);
@@ -2043,7 +2043,8 @@ retry:
                        }
                        wdata->pid = wdata->cfile->pid;
                        server = tlink_tcon(wdata->cfile->tlink)->ses->server;
-                       rc = server->ops->async_writev(wdata);
+                       rc = server->ops->async_writev(wdata,
+                                                       cifs_writedata_release);
                } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
                for (i = 0; i < nr_pages; ++i)
@@ -2331,9 +2332,20 @@ size_t get_numpages(const size_t wsize, const size_t len, size_t *cur_len)
 }
 
 static void
-cifs_uncached_writev_complete(struct work_struct *work)
+cifs_uncached_writedata_release(struct kref *refcount)
 {
        int i;
+       struct cifs_writedata *wdata = container_of(refcount,
+                                       struct cifs_writedata, refcount);
+
+       for (i = 0; i < wdata->nr_pages; i++)
+               put_page(wdata->pages[i]);
+       cifs_writedata_release(refcount);
+}
+
+static void
+cifs_uncached_writev_complete(struct work_struct *work)
+{
        struct cifs_writedata *wdata = container_of(work,
                                        struct cifs_writedata, work);
        struct inode *inode = wdata->cfile->dentry->d_inode;
@@ -2347,12 +2359,7 @@ cifs_uncached_writev_complete(struct work_struct *work)
 
        complete(&wdata->done);
 
-       if (wdata->result != -EAGAIN) {
-               for (i = 0; i < wdata->nr_pages; i++)
-                       put_page(wdata->pages[i]);
-       }
-
-       kref_put(&wdata->refcount, cifs_writedata_release);
+       kref_put(&wdata->refcount, cifs_uncached_writedata_release);
 }
 
 /* attempt to send write to server, retry on any -EAGAIN errors */
@@ -2370,7 +2377,8 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
                        if (rc != 0)
                                continue;
                }
-               rc = server->ops->async_writev(wdata);
+               rc = server->ops->async_writev(wdata,
+                                              cifs_uncached_writedata_release);
        } while (rc == -EAGAIN);
 
        return rc;
@@ -2381,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
                 unsigned long nr_segs, loff_t *poffset)
 {
        unsigned long nr_pages, i;
-       size_t copied, len, cur_len;
+       size_t bytes, copied, len, cur_len;
        ssize_t total_written = 0;
        loff_t offset;
        struct iov_iter it;
@@ -2436,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
 
                save_len = cur_len;
                for (i = 0; i < nr_pages; i++) {
-                       copied = min_t(const size_t, cur_len, PAGE_SIZE);
+                       bytes = min_t(const size_t, cur_len, PAGE_SIZE);
                        copied = iov_iter_copy_from_user(wdata->pages[i], &it,
-                                                        0, copied);
+                                                        0, bytes);
                        cur_len -= copied;
                        iov_iter_advance(&it, copied);
+                       /*
+                        * If we didn't copy as much as we expected, then that
+                        * may mean we trod into an unmapped area. Stop copying
+                        * at that point. On the next pass through the big
+                        * loop, we'll likely end up getting a zero-length
+                        * write and bailing out of it.
+                        */
+                       if (copied < bytes)
+                               break;
                }
                cur_len = save_len - cur_len;
 
+               /*
+                * If we have no data to send, then that probably means that
+                * the copy above failed altogether. That's most likely because
+                * the address in the iovec was bogus. Set the rc to -EFAULT,
+                * free anything we allocated and bail out.
+                */
+               if (!cur_len) {
+                       for (i = 0; i < nr_pages; i++)
+                               put_page(wdata->pages[i]);
+                       kfree(wdata);
+                       rc = -EFAULT;
+                       break;
+               }
+
+               /*
+                * i + 1 now represents the number of pages we actually used in
+                * the copy phase above. Bring nr_pages down to that, and free
+                * any pages that we didn't use.
+                */
+               for ( ; nr_pages > i + 1; nr_pages--)
+                       put_page(wdata->pages[nr_pages - 1]);
+
                wdata->sync_mode = WB_SYNC_ALL;
                wdata->nr_pages = nr_pages;
                wdata->offset = (__u64)offset;
@@ -2454,7 +2493,8 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
                wdata->tailsz = cur_len - ((nr_pages - 1) * PAGE_SIZE);
                rc = cifs_uncached_retry_writev(wdata);
                if (rc) {
-                       kref_put(&wdata->refcount, cifs_writedata_release);
+                       kref_put(&wdata->refcount,
+                                cifs_uncached_writedata_release);
                        break;
                }
 
@@ -2496,7 +2536,7 @@ restart_loop:
                        }
                }
                list_del_init(&wdata->list);
-               kref_put(&wdata->refcount, cifs_writedata_release);
+               kref_put(&wdata->refcount, cifs_uncached_writedata_release);
        }
 
        if (total_written > 0)
@@ -2539,31 +2579,19 @@ cifs_writev(struct kiocb *iocb, const struct iovec *iov,
        struct cifsInodeInfo *cinode = CIFS_I(inode);
        struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
        ssize_t rc = -EACCES;
+       loff_t lock_pos = pos;
 
-       BUG_ON(iocb->ki_pos != pos);
-
+       if (file->f_flags & O_APPEND)
+               lock_pos = i_size_read(inode);
        /*
         * We need to hold the sem to be sure nobody modifies lock list
         * with a brlock that prevents writing.
         */
        down_read(&cinode->lock_sem);
-       if (!cifs_find_lock_conflict(cfile, pos, iov_length(iov, nr_segs),
+       if (!cifs_find_lock_conflict(cfile, lock_pos, iov_length(iov, nr_segs),
                                     server->vals->exclusive_lock_type, NULL,
-                                    CIFS_WRITE_OP)) {
-               mutex_lock(&inode->i_mutex);
-               rc = __generic_file_aio_write(iocb, iov, nr_segs,
-                                              &iocb->ki_pos);
-               mutex_unlock(&inode->i_mutex);
-       }
-
-       if (rc > 0) {
-               ssize_t err;
-
-               err = generic_write_sync(file, iocb->ki_pos - rc, rc);
-               if (err < 0)
-                       rc = err;
-       }
-
+                                    CIFS_WRITE_OP))
+               rc = generic_file_aio_write(iocb, iov, nr_segs, pos);
        up_read(&cinode->lock_sem);
        return rc;
 }
index 9cb9679d735719b42f83b89e39b9c0bbd56fdd65..aadc2b68678b7d70c0381d10c847c86624589c4c 100644 (file)
@@ -527,10 +527,15 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
                return PTR_ERR(tlink);
        tcon = tlink_tcon(tlink);
 
-       rc = CIFSSMBQAllEAs(xid, tcon, path, "SETFILEBITS",
-                           ea_value, 4 /* size of buf */, cifs_sb->local_nls,
-                           cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (tcon->ses->server->ops->query_all_EAs == NULL) {
+               cifs_put_tlink(tlink);
+               return -EOPNOTSUPP;
+       }
+
+       rc = tcon->ses->server->ops->query_all_EAs(xid, tcon, path,
+                       "SETFILEBITS", ea_value, 4 /* size of buf */,
+                       cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
        cifs_put_tlink(tlink);
        if (rc < 0)
                return (int)rc;
@@ -672,7 +677,7 @@ cgfi_exit:
 int
 cifs_get_inode_info(struct inode **inode, const char *full_path,
                    FILE_ALL_INFO *data, struct super_block *sb, int xid,
-                   const __u16 *fid)
+                   const struct cifs_fid *fid)
 {
        bool validinum = false;
        __u16 srchflgs;
index 9ac5bfc9cc56af6ee74f9f3d2e15e66ab2dd2e54..526fb89f92305b9e85d1f62f65a6e48c04555e83 100644 (file)
@@ -1067,6 +1067,15 @@ struct smb_version_operations smb1_operations = {
        .query_mf_symlink = cifs_query_mf_symlink,
        .create_mf_symlink = cifs_create_mf_symlink,
        .is_read_op = cifs_is_read_op,
+#ifdef CONFIG_CIFS_XATTR
+       .query_all_EAs = CIFSSMBQAllEAs,
+       .set_EA = CIFSSMBSetEA,
+#endif /* CIFS_XATTR */
+#ifdef CONFIG_CIFS_ACL
+       .get_acl = get_cifs_acl,
+       .get_acl_by_fid = get_cifs_acl_by_fid,
+       .set_acl = set_cifs_acl,
+#endif /* CIFS_ACL */
 };
 
 struct smb_version_values smb1_values = {
index c38350851b0883cd6074b04f5aa36398b2528e3c..bc0bb9c34f72aaef62383760a06fa55c72d5b70b 100644 (file)
@@ -57,4 +57,7 @@
 #define SMB2_CMACAES_SIZE (16)
 #define SMB3_SIGNKEY_SIZE (16)
 
+/* Maximum buffer size value we can send with 1 credit */
+#define SMB2_MAX_BUFFER_SIZE 65536
+
 #endif /* _SMB2_GLOB_H */
index 757da3e54d3dce601b71b97883f3430556040107..192f51a12cf1c63fb6eee3359b2350747343a76c 100644 (file)
@@ -182,11 +182,8 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
        /* start with specified wsize, or default */
        wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
        wsize = min_t(unsigned int, wsize, server->max_write);
-       /*
-        * limit write size to 2 ** 16, because we don't support multicredit
-        * requests now.
-        */
-       wsize = min_t(unsigned int, wsize, 2 << 15);
+       /* set it to the maximum buffer size value we can send with 1 credit */
+       wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
 
        return wsize;
 }
@@ -200,11 +197,8 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
        /* start with specified rsize, or default */
        rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
        rsize = min_t(unsigned int, rsize, server->max_read);
-       /*
-        * limit write size to 2 ** 16, because we don't support multicredit
-        * requests now.
-        */
-       rsize = min_t(unsigned int, rsize, 2 << 15);
+       /* set it to the maximum buffer size value we can send with 1 credit */
+       rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
 
        return rsize;
 }
index 2013234b73adc47a5a34cb907ce0b818f65a16f5..860344701067f49169e20a8a41df55145fa5f023 100644 (file)
@@ -413,7 +413,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 
        /* SMB2 only has an extended negflavor */
        server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
-       server->maxBuf = le32_to_cpu(rsp->MaxTransactSize);
+       /* set it to the maximum buffer size value we can send with 1 credit */
+       server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize),
+                              SMB2_MAX_BUFFER_SIZE);
        server->max_read = le32_to_cpu(rsp->MaxReadSize);
        server->max_write = le32_to_cpu(rsp->MaxWriteSize);
        /* BB Do we need to validate the SecurityMode? */
@@ -1890,7 +1892,8 @@ smb2_writev_callback(struct mid_q_entry *mid)
 
 /* smb2_async_writev - send an async write, and set up mid to handle result */
 int
-smb2_async_writev(struct cifs_writedata *wdata)
+smb2_async_writev(struct cifs_writedata *wdata,
+                 void (*release)(struct kref *kref))
 {
        int rc = -EACCES;
        struct smb2_write_req *req = NULL;
@@ -1938,7 +1941,7 @@ smb2_async_writev(struct cifs_writedata *wdata)
                                smb2_writev_callback, wdata, 0);
 
        if (rc) {
-               kref_put(&wdata->refcount, cifs_writedata_release);
+               kref_put(&wdata->refcount, release);
                cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
        }
 
index 93adc64666f310345b4c6d76bba628741aa4e634..0ce48db20a6511add52f9b44f5cbf664a178e41f 100644 (file)
@@ -123,7 +123,8 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_async_readv(struct cifs_readdata *rdata);
 extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
                     unsigned int *nbytes, char **buf, int *buf_type);
-extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int smb2_async_writev(struct cifs_writedata *wdata,
+                            void (*release)(struct kref *kref));
 extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
                      unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
index b375709528467b5a1a74e078fae2aeb7813e1a1e..18cd5650a5fc6106394691f6ee5baf37f5d8d49b 100644 (file)
@@ -270,6 +270,26 @@ cifs_rqst_page_to_kvec(struct smb_rqst *rqst, unsigned int idx,
                iov->iov_len = rqst->rq_pagesz;
 }
 
+static unsigned long
+rqst_len(struct smb_rqst *rqst)
+{
+       unsigned int i;
+       struct kvec *iov = rqst->rq_iov;
+       unsigned long buflen = 0;
+
+       /* total up iov array first */
+       for (i = 0; i < rqst->rq_nvec; i++)
+               buflen += iov[i].iov_len;
+
+       /* add in the page array if there is one */
+       if (rqst->rq_npages) {
+               buflen += rqst->rq_pagesz * (rqst->rq_npages - 1);
+               buflen += rqst->rq_tailsz;
+       }
+
+       return buflen;
+}
+
 static int
 smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 {
@@ -277,6 +297,7 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
        unsigned int smb_buf_length = get_rfc1002_length(iov[0].iov_base);
+       unsigned long send_length;
        unsigned int i;
        size_t total_len = 0, sent;
        struct socket *ssocket = server->ssocket;
@@ -285,6 +306,14 @@ smb_send_rqst(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        if (ssocket == NULL)
                return -ENOTSOCK;
 
+       /* sanity check send length */
+       send_length = rqst_len(rqst);
+       if (send_length != smb_buf_length + 4) {
+               WARN(1, "Send length mismatch(send_length=%lu smb_buf_length=%u)\n",
+                       send_length, smb_buf_length);
+               return -EIO;
+       }
+
        cifs_dbg(FYI, "Sending smb: smb_len=%u\n", smb_buf_length);
        dump_smb(iov[0].iov_base, iov[0].iov_len);
 
index 95c43bb203353a65974a6cf5b24a0fe02c3c5c86..5ac836a86b1885d4e1766e831a1b56d3a263e277 100644 (file)
@@ -176,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
                        rc = -ENOMEM;
                } else {
                        memcpy(pacl, ea_value, value_size);
-                       rc = set_cifs_acl(pacl, value_size,
-                               direntry->d_inode, full_path, CIFS_ACL_DACL);
+                       if (pTcon->ses->server->ops->set_acl)
+                               rc = pTcon->ses->server->ops->set_acl(pacl,
+                                               value_size, direntry->d_inode,
+                                               full_path, CIFS_ACL_DACL);
+                       else
+                               rc = -EOPNOTSUPP;
                        if (rc == 0) /* force revalidate of the inode */
                                CIFS_I(direntry->d_inode)->time = 0;
                        kfree(pacl);
@@ -323,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
                        u32 acllen;
                        struct cifs_ntsd *pacl;
 
-                       pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
-                                               full_path, &acllen);
+                       if (pTcon->ses->server->ops->get_acl == NULL)
+                               goto get_ea_exit; /* rc already EOPNOTSUPP */
+
+                       pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
+                                       direntry->d_inode, full_path, &acllen);
                        if (IS_ERR(pacl)) {
                                rc = PTR_ERR(pacl);
                                cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
index 265e0ce9769c70db65d5f9df11c4365f44c6dd29..ca02c13a84aa24d55b18bbced577ece923605665 100644 (file)
@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
        u32 dlen = ACCESS_ONCE(name->len);
        char *p;
 
-       if (*buflen < dlen + 1)
-               return -ENAMETOOLONG;
        *buflen -= dlen + 1;
+       if (*buflen < 0)
+               return -ENAMETOOLONG;
        p = *buffer -= dlen + 1;
        *p++ = '/';
        while (dlen--) {
index ece55565b9cd35575c454d44656c63321d89e0f9..d3a534fdc5ff6c766131e5d843591149736cc4d8 100644 (file)
@@ -771,6 +771,8 @@ do {                                                                               \
        if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))                      \
                (einode)->xtime.tv_sec =                                       \
                        (signed)le32_to_cpu((raw_inode)->xtime);               \
+       else                                                                   \
+               (einode)->xtime.tv_sec = 0;                                    \
        if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))            \
                ext4_decode_extra_time(&(einode)->xtime,                       \
                                       raw_inode->xtime ## _extra);            \
index 10cff4736b116185f9d0a2cea73dca9423c6fb92..74bc2d549c58bd57d60ebcb0a143a3fdf4e95997 100644 (file)
@@ -3906,6 +3906,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
                } else
                        err = ret;
                map->m_flags |= EXT4_MAP_MAPPED;
+               map->m_pblk = newblock;
                if (allocated > map->m_len)
                        allocated = map->m_len;
                map->m_len = allocated;
index 6bea80614d77c19c6ca7b1ac9160d64f1115b36e..a2a837f0040743d9e76608904c5b2cb429aaadd2 100644 (file)
@@ -140,7 +140,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
        handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2);
        if (IS_ERR(handle)) {
                err = -EINVAL;
-               goto swap_boot_out;
+               goto journal_err_out;
        }
 
        /* Protect extent tree against block allocations via delalloc */
@@ -198,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
 
        ext4_double_up_write_data_sem(inode, inode_bl);
 
+journal_err_out:
        ext4_inode_resume_unlocked_dio(inode);
        ext4_inode_resume_unlocked_dio(inode_bl);
 
index c5adbb318a90c8c612c97dab1a47c0143b19ef77..f3b84cd9de566ff7b1ffb5d16e75483e9b9d06f2 100644 (file)
@@ -243,6 +243,7 @@ static int ext4_alloc_group_tables(struct super_block *sb,
        ext4_group_t group;
        ext4_group_t last_group;
        unsigned overhead;
+       __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0;
 
        BUG_ON(flex_gd->count == 0 || group_data == NULL);
 
@@ -266,7 +267,7 @@ next_group:
        src_group++;
        for (; src_group <= last_group; src_group++) {
                overhead = ext4_group_overhead_blocks(sb, src_group);
-               if (overhead != 0)
+               if (overhead == 0)
                        last_blk += group_data[src_group - group].blocks_count;
                else
                        break;
@@ -280,8 +281,7 @@ next_group:
                group = ext4_get_group_number(sb, start_blk - 1);
                group -= group_data[0].group;
                group_data[group].free_blocks_count--;
-               if (flexbg_size > 1)
-                       flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+               flex_gd->bg_flags[group] &= uninit_mask;
        }
 
        /* Allocate inode bitmaps */
@@ -292,22 +292,30 @@ next_group:
                group = ext4_get_group_number(sb, start_blk - 1);
                group -= group_data[0].group;
                group_data[group].free_blocks_count--;
-               if (flexbg_size > 1)
-                       flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
+               flex_gd->bg_flags[group] &= uninit_mask;
        }
 
        /* Allocate inode tables */
        for (; it_index < flex_gd->count; it_index++) {
-               if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk)
+               unsigned int itb = EXT4_SB(sb)->s_itb_per_group;
+               ext4_fsblk_t next_group_start;
+
+               if (start_blk + itb > last_blk)
                        goto next_group;
                group_data[it_index].inode_table = start_blk;
-               group = ext4_get_group_number(sb, start_blk - 1);
+               group = ext4_get_group_number(sb, start_blk);
+               next_group_start = ext4_group_first_block_no(sb, group + 1);
                group -= group_data[0].group;
-               group_data[group].free_blocks_count -=
-                                       EXT4_SB(sb)->s_itb_per_group;
-               if (flexbg_size > 1)
-                       flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT;
 
+               if (start_blk + itb > next_group_start) {
+                       flex_gd->bg_flags[group + 1] &= uninit_mask;
+                       overhead = start_blk + itb - next_group_start;
+                       group_data[group + 1].free_blocks_count -= overhead;
+                       itb -= overhead;
+               }
+
+               group_data[group].free_blocks_count -= itb;
+               flex_gd->bg_flags[group] &= uninit_mask;
                start_blk += EXT4_SB(sb)->s_itb_per_group;
        }
 
@@ -401,7 +409,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle,
                start = ext4_group_first_block_no(sb, group);
                group -= flex_gd->groups[0].group;
 
-               count2 = sb->s_blocksize * 8 - (block - start);
+               count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start);
                if (count2 > count)
                        count2 = count;
 
@@ -620,7 +628,7 @@ handle_ib:
                        if (err)
                                goto out;
                        count = group_table_count[j];
-                       start = group_data[i].block_bitmap;
+                       start = (&group_data[i].block_bitmap)[j];
                        block = start;
                }
 
index 1f7784de05b6c6afad4d7437202ceb6efeec3399..710fed2377d415a32b0658faabde9960ff639b84 100644 (file)
@@ -3695,16 +3695,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        for (i = 0; i < 4; i++)
                sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
        sbi->s_def_hash_version = es->s_def_hash_version;
-       i = le32_to_cpu(es->s_flags);
-       if (i & EXT2_FLAGS_UNSIGNED_HASH)
-               sbi->s_hash_unsigned = 3;
-       else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
+       if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+               i = le32_to_cpu(es->s_flags);
+               if (i & EXT2_FLAGS_UNSIGNED_HASH)
+                       sbi->s_hash_unsigned = 3;
+               else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
 #ifdef __CHAR_UNSIGNED__
-               es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
-               sbi->s_hash_unsigned = 3;
+                       if (!(sb->s_flags & MS_RDONLY))
+                               es->s_flags |=
+                                       cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
+                       sbi->s_hash_unsigned = 3;
 #else
-               es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               es->s_flags |=
+                                       cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
 #endif
+               }
        }
 
        /* Handle clustersize */
index 771578b33fb6c7fee9a7c28d01138e4670e07e59..eb56a13dab3ed5561a9521b2b2d1a6000a7158a3 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -34,7 +34,7 @@ static void *alloc_fdmem(size_t size)
         * vmalloc() if the allocation size will be considered "large" by the VM.
         */
        if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
-               void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN);
+               void *data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY);
                if (data != NULL)
                        return data;
        }
@@ -683,35 +683,54 @@ EXPORT_SYMBOL(fget_raw);
  * The fput_needed flag returned by fget_light should be passed to the
  * corresponding fput_light.
  */
-struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
+static unsigned long __fget_light(unsigned int fd, fmode_t mask)
 {
        struct files_struct *files = current->files;
        struct file *file;
 
-       *fput_needed = 0;
        if (atomic_read(&files->count) == 1) {
                file = __fcheck_files(files, fd);
-               if (file && (file->f_mode & mask))
-                       file = NULL;
+               if (!file || unlikely(file->f_mode & mask))
+                       return 0;
+               return (unsigned long)file;
        } else {
                file = __fget(fd, mask);
-               if (file)
-                       *fput_needed = 1;
+               if (!file)
+                       return 0;
+               return FDPUT_FPUT | (unsigned long)file;
        }
-
-       return file;
 }
-struct file *fget_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget(unsigned int fd)
 {
-       return __fget_light(fd, FMODE_PATH, fput_needed);
+       return __fget_light(fd, FMODE_PATH);
 }
-EXPORT_SYMBOL(fget_light);
+EXPORT_SYMBOL(__fdget);
 
-struct file *fget_raw_light(unsigned int fd, int *fput_needed)
+unsigned long __fdget_raw(unsigned int fd)
 {
-       return __fget_light(fd, 0, fput_needed);
+       return __fget_light(fd, 0);
 }
 
+unsigned long __fdget_pos(unsigned int fd)
+{
+       unsigned long v = __fdget(fd);
+       struct file *file = (struct file *)(v & ~3);
+
+       if (file && (file->f_mode & FMODE_ATOMIC_POS)) {
+               if (file_count(file) > 1) {
+                       v |= FDPUT_POS_UNLOCK;
+                       mutex_lock(&file->f_pos_lock);
+               }
+       }
+       return v;
+}
+
+/*
+ * We only lock f_pos if we have threads or if the file might be
+ * shared with another process. In both cases we'll have an elevated
+ * file count (done either by fdget() or by fork()).
+ */
+
 void set_close_on_exec(unsigned int fd, int flag)
 {
        struct files_struct *files = current->files;
index 5fff9030be34df26aff0c0ed56081aee1306bf02..5b24008ea4f678b668ff2a52fa41f1812b579645 100644 (file)
@@ -135,6 +135,7 @@ struct file *get_empty_filp(void)
        atomic_long_set(&f->f_count, 1);
        rwlock_init(&f->f_owner.lock);
        spin_lock_init(&f->f_lock);
+       mutex_init(&f->f_pos_lock);
        eventpoll_init_file(f);
        /* f->f_version: 0 */
        return f;
index e0259a163f98e69000c28bdb78fcf2b77c2bed2d..d754e3cf99a85af0c433e71846db6ee051751ebd 100644 (file)
 struct wb_writeback_work {
        long nr_pages;
        struct super_block *sb;
-       /*
-        * Write only inodes dirtied before this time. Don't forget to set
-        * older_than_this_is_set when you set this.
-        */
-       unsigned long older_than_this;
+       unsigned long *older_than_this;
        enum writeback_sync_modes sync_mode;
        unsigned int tagged_writepages:1;
        unsigned int for_kupdate:1;
        unsigned int range_cyclic:1;
        unsigned int for_background:1;
        unsigned int for_sync:1;        /* sync(2) WB_SYNC_ALL writeback */
-       unsigned int older_than_this_is_set:1;
        enum wb_reason reason;          /* why was writeback initiated? */
 
        struct list_head list;          /* pending work list */
@@ -252,10 +247,10 @@ static int move_expired_inodes(struct list_head *delaying_queue,
        int do_sb_sort = 0;
        int moved = 0;
 
-       WARN_ON_ONCE(!work->older_than_this_is_set);
        while (!list_empty(delaying_queue)) {
                inode = wb_inode(delaying_queue->prev);
-               if (inode_dirtied_after(inode, work->older_than_this))
+               if (work->older_than_this &&
+                   inode_dirtied_after(inode, *work->older_than_this))
                        break;
                list_move(&inode->i_wb_list, &tmp);
                moved++;
@@ -742,8 +737,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
                .sync_mode      = WB_SYNC_NONE,
                .range_cyclic   = 1,
                .reason         = reason,
-               .older_than_this = jiffies,
-               .older_than_this_is_set = 1,
        };
 
        spin_lock(&wb->list_lock);
@@ -802,13 +795,12 @@ static long wb_writeback(struct bdi_writeback *wb,
 {
        unsigned long wb_start = jiffies;
        long nr_pages = work->nr_pages;
+       unsigned long oldest_jif;
        struct inode *inode;
        long progress;
 
-       if (!work->older_than_this_is_set) {
-               work->older_than_this = jiffies;
-               work->older_than_this_is_set = 1;
-       }
+       oldest_jif = jiffies;
+       work->older_than_this = &oldest_jif;
 
        spin_lock(&wb->list_lock);
        for (;;) {
@@ -842,10 +834,10 @@ static long wb_writeback(struct bdi_writeback *wb,
                 * safe.
                 */
                if (work->for_kupdate) {
-                       work->older_than_this = jiffies -
+                       oldest_jif = jiffies -
                                msecs_to_jiffies(dirty_expire_interval * 10);
                } else if (work->for_background)
-                       work->older_than_this = jiffies;
+                       oldest_jif = jiffies;
 
                trace_writeback_start(wb->bdi, work);
                if (list_empty(&wb->b_io))
@@ -1357,21 +1349,18 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb);
 
 /**
  * sync_inodes_sb      -       sync sb inode pages
- * @sb:                        the superblock
- * @older_than_this:   timestamp
+ * @sb: the superblock
  *
  * This function writes and waits on any dirty inode belonging to this
- * superblock that has been dirtied before given timestamp.
+ * super_block.
  */
-void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this)
+void sync_inodes_sb(struct super_block *sb)
 {
        DECLARE_COMPLETION_ONSTACK(done);
        struct wb_writeback_work work = {
                .sb             = sb,
                .sync_mode      = WB_SYNC_ALL,
                .nr_pages       = LONG_MAX,
-               .older_than_this = older_than_this,
-               .older_than_this_is_set = 1,
                .range_cyclic   = 0,
                .done           = &done,
                .reason         = WB_REASON_SYNC,
index e1959efad64fa0f4101541683e8c422d27a37aa7..b5ebc2d7d80d30d39b21243561e1f7d26c300329 100644 (file)
@@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj)
        struct fscache_object *xobj;
        struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL;
 
+       ASSERT(RB_EMPTY_NODE(&obj->objlist_link));
+
        write_lock(&fscache_object_list_lock);
 
        while (*p) {
@@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj)
  */
 void fscache_objlist_remove(struct fscache_object *obj)
 {
+       if (RB_EMPTY_NODE(&obj->objlist_link))
+               return;
+
        write_lock(&fscache_object_list_lock);
 
        BUG_ON(RB_EMPTY_ROOT(&fscache_object_list));
index 53d35c5042404738c213233220500feaf7686ae8..d3b4539f16515451cdd691fd853927d00fa3f8a8 100644 (file)
@@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object,
        object->cache = cache;
        object->cookie = cookie;
        object->parent = NULL;
+#ifdef CONFIG_FSCACHE_OBJECT_LIST
+       RB_CLEAR_NODE(&object->objlist_link);
+#endif
 
        object->oob_event_mask = 0;
        for (t = object->oob_table; t->events; t++)
index 968ce411db53e807b6f3b0fd216cd6730f226b5d..32602c667b4aaf697c97b7f7e709d808328a5468 100644 (file)
@@ -103,6 +103,8 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry,
                folder = &entry->folder;
                memset(folder, 0, sizeof(*folder));
                folder->type = cpu_to_be16(HFSPLUS_FOLDER);
+               if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags))
+                       folder->flags |= cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT);
                folder->id = cpu_to_be32(inode->i_ino);
                HFSPLUS_I(inode)->create_date =
                        folder->create_date =
@@ -203,6 +205,36 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
        return hfs_brec_find(fd, hfs_find_rec_by_key);
 }
 
+static void hfsplus_subfolders_inc(struct inode *dir)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               /*
+                * Increment subfolder count. Note, the value is only meaningful
+                * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+                */
+               HFSPLUS_I(dir)->subfolders++;
+       }
+}
+
+static void hfsplus_subfolders_dec(struct inode *dir)
+{
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               /*
+                * Decrement subfolder count. Note, the value is only meaningful
+                * for folders with HFSPLUS_HAS_FOLDER_COUNT flag set.
+                *
+                * Check for zero. Some subfolders may have been created
+                * by an implementation ignorant of this counter.
+                */
+               if (HFSPLUS_I(dir)->subfolders)
+                       HFSPLUS_I(dir)->subfolders--;
+       }
+}
+
 int hfsplus_create_cat(u32 cnid, struct inode *dir,
                struct qstr *str, struct inode *inode)
 {
@@ -247,6 +279,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
                goto err1;
 
        dir->i_size++;
+       if (S_ISDIR(inode->i_mode))
+               hfsplus_subfolders_inc(dir);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 
@@ -336,6 +370,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                goto out;
 
        dir->i_size--;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_dec(dir);
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
        hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
 
@@ -380,6 +416,7 @@ int hfsplus_rename_cat(u32 cnid,
 
        hfs_bnode_read(src_fd.bnode, &entry, src_fd.entryoffset,
                                src_fd.entrylength);
+       type = be16_to_cpu(entry.type);
 
        /* create new dir entry with the data from the old entry */
        hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
@@ -394,6 +431,8 @@ int hfsplus_rename_cat(u32 cnid,
        if (err)
                goto out;
        dst_dir->i_size++;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_inc(dst_dir);
        dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC;
 
        /* finally remove the old entry */
@@ -405,6 +444,8 @@ int hfsplus_rename_cat(u32 cnid,
        if (err)
                goto out;
        src_dir->i_size--;
+       if (type == HFSPLUS_FOLDER)
+               hfsplus_subfolders_dec(src_dir);
        src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC;
 
        /* remove old thread entry */
index 08846425b67ffa112b7978650e1521b74955a1dc..62d571eb69bae9c7d04b5c27238b9fa2a1d4a633 100644 (file)
@@ -242,6 +242,7 @@ struct hfsplus_inode_info {
         */
        sector_t fs_blocks;
        u8 userflags;           /* BSD user file flags */
+       u32 subfolders;         /* Subfolder count (HFSX only) */
        struct list_head open_dir_list;
        loff_t phys_size;
 
index 8ffb3a8ffe75b9d6374cb9198d83d5dce5553457..5a126828d85eb011714b067976f0a14981103c7c 100644 (file)
@@ -261,7 +261,7 @@ struct hfsplus_cat_folder {
        struct DInfo user_info;
        struct DXInfo finder_info;
        __be32 text_encoding;
-       u32 reserved;
+       __be32 subfolders;      /* Subfolder count in HFSX. Reserved in HFS+. */
 } __packed;
 
 /* HFS file info (stolen from hfs.h) */
@@ -301,11 +301,13 @@ struct hfsplus_cat_file {
        struct hfsplus_fork_raw rsrc_fork;
 } __packed;
 
-/* File attribute bits */
+/* File and folder flag bits */
 #define HFSPLUS_FILE_LOCKED            0x0001
 #define HFSPLUS_FILE_THREAD_EXISTS     0x0002
 #define HFSPLUS_XATTR_EXISTS           0x0004
 #define HFSPLUS_ACL_EXISTS             0x0008
+#define HFSPLUS_HAS_FOLDER_COUNT       0x0010  /* Folder has subfolder count
+                                                * (HFSX only) */
 
 /* HFS+ catalog thread (part of a cat_entry) */
 struct hfsplus_cat_thread {
index fa929f325f87502074d66e208c1a57feba089c82..a4f45bd88a631ad5a153a8f45fdd1044a3637c1c 100644 (file)
@@ -375,6 +375,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
        hip->extent_state = 0;
        hip->flags = 0;
        hip->userflags = 0;
+       hip->subfolders = 0;
        memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
        memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
        hip->alloc_blocks = 0;
@@ -494,6 +495,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
                HFSPLUS_I(inode)->create_date = folder->create_date;
                HFSPLUS_I(inode)->fs_blocks = 0;
+               if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+                       HFSPLUS_I(inode)->subfolders =
+                               be32_to_cpu(folder->subfolders);
+               }
                inode->i_op = &hfsplus_dir_inode_operations;
                inode->i_fop = &hfsplus_dir_operations;
        } else if (type == HFSPLUS_FILE) {
@@ -566,6 +571,10 @@ int hfsplus_cat_write_inode(struct inode *inode)
                folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
                folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
                folder->valence = cpu_to_be32(inode->i_size - 2);
+               if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
+                       folder->subfolders =
+                               cpu_to_be32(HFSPLUS_I(inode)->subfolders);
+               }
                hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
                                         sizeof(struct hfsplus_cat_folder));
        } else if (HFSPLUS_IS_RSRC(inode)) {
index 968eab5bc1f5623f09169c65f178518dbd87ee2b..68537e8b7a0934859048ecd4cfb0e67cdcb6b819 100644 (file)
@@ -75,7 +75,7 @@ int hfsplus_parse_options_remount(char *input, int *force)
        int token;
 
        if (!input)
-               return 0;
+               return 1;
 
        while ((p = strsep(&input, ",")) != NULL) {
                if (!*p)
index 8360674c85bcb98af88d6aaff3ee4c46fe6f31bf..60bb365f54a52efb8ff859ff746ac1af201bb7d2 100644 (file)
@@ -514,11 +514,13 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type,
         * similarly constrained call sites
         */
        ret = start_this_handle(journal, handle, GFP_NOFS);
-       if (ret < 0)
+       if (ret < 0) {
                jbd2_journal_free_reserved(handle);
+               return ret;
+       }
        handle->h_type = type;
        handle->h_line_no = line_no;
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(jbd2_journal_start_reserved);
 
index e973b85d6afd9f136bcae002cbe70432000e5a15..5a8ea16eedbcd1d634feedce069637a717c49c19 100644 (file)
@@ -86,6 +86,8 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
                rc = posix_acl_equiv_mode(acl, &inode->i_mode);
                if (rc < 0)
                        return rc;
+               inode->i_ctime = CURRENT_TIME;
+               mark_inode_dirty(inode);
                if (rc == 0)
                        acl = NULL;
                break;
index 0d6ce895a9eec0ce3b3329d1353b594d353aeacb..0f4152defe7b6f96afa752acdbc075a512bc8c5d 100644 (file)
@@ -94,6 +94,7 @@ const void *kernfs_super_ns(struct super_block *sb)
  * @fs_type: file_system_type of the fs being mounted
  * @flags: mount flags specified for the mount
  * @root: kernfs_root of the hierarchy being mounted
+ * @new_sb_created: tell the caller if we allocated a new superblock
  * @ns: optional namespace tag of the mount
  *
  * This is to be called from each kernfs user's file_system_type->mount()
@@ -104,7 +105,8 @@ const void *kernfs_super_ns(struct super_block *sb)
  * The return value can be passed to the vfs layer verbatim.
  */
 struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-                              struct kernfs_root *root, const void *ns)
+                              struct kernfs_root *root, bool *new_sb_created,
+                              const void *ns)
 {
        struct super_block *sb;
        struct kernfs_super_info *info;
@@ -122,6 +124,10 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
                kfree(info);
        if (IS_ERR(sb))
                return ERR_CAST(sb);
+
+       if (new_sb_created)
+               *new_sb_created = !sb->s_root;
+
        if (!sb->s_root) {
                error = kernfs_fill_super(sb);
                if (error) {
index e066a3902973640ae3d75dc0c768ceb8f15eb9d8..ab798a88ec1d52347afe05d4b8ed2eff13151de1 100644 (file)
@@ -779,6 +779,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
        struct nlm_file         *file = block->b_file;
        struct nlm_lock         *lock = &block->b_call->a_args.lock;
        int                     error;
+       loff_t                  fl_start, fl_end;
 
        dprintk("lockd: grant blocked lock %p\n", block);
 
@@ -796,9 +797,16 @@ nlmsvc_grant_blocked(struct nlm_block *block)
        }
 
        /* Try the lock operation again */
+       /* vfs_lock_file() can mangle fl_start and fl_end, but we need
+        * them unchanged for the GRANT_MSG
+        */
        lock->fl.fl_flags |= FL_SLEEP;
+       fl_start = lock->fl.fl_start;
+       fl_end = lock->fl.fl_end;
        error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
        lock->fl.fl_flags &= ~FL_SLEEP;
+       lock->fl.fl_start = fl_start;
+       lock->fl.fl_end = fl_end;
 
        switch (error) {
        case 0:
index 385f7817bfccbd12fbc352c39827586d4cf953d7..4b491b4319905b2dd6698d3f58aae1d0d0141499 100644 (file)
@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                        return false;
 
                if (!d_mountpoint(path->dentry))
-                       break;
+                       return true;
 
                mounted = __lookup_mnt(path->mnt, path->dentry);
                if (!mounted)
@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 */
                *inode = path->dentry->d_inode;
        }
-       return true;
-}
-
-static void follow_mount_rcu(struct nameidata *nd)
-{
-       while (d_mountpoint(nd->path.dentry)) {
-               struct mount *mounted;
-               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
-               if (!mounted)
-                       break;
-               nd->path.mnt = &mounted->mnt;
-               nd->path.dentry = mounted->mnt.mnt_root;
-               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-       }
+       return read_seqretry(&mount_lock, nd->m_seq);
 }
 
 static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                        break;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
        }
-       follow_mount_rcu(nd);
+       while (d_mountpoint(nd->path.dentry)) {
+               struct mount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+               if (!mounted)
+                       break;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               if (!read_seqretry(&mount_lock, nd->m_seq))
+                       goto failed;
+       }
        nd->inode = nd->path.dentry->d_inode;
        return 0;
 
@@ -1884,7 +1881,7 @@ static int path_init(int dfd, const char *name, unsigned int flags,
 
                nd->path = f.file->f_path;
                if (flags & LOOKUP_RCU) {
-                       if (f.need_put)
+                       if (f.flags & FDPUT_FPUT)
                                *fp = f.file;
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
                        rcu_read_lock();
index ef792f29f831c4c72e3e4edd7db9257165aca2fe..5d8ccecf5f5caada2de94bf30689ecd9e725a15a 100644 (file)
@@ -659,16 +659,19 @@ int nfs_async_inode_return_delegation(struct inode *inode,
 
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
+       if (delegation == NULL)
+               goto out_enoent;
 
-       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
-               rcu_read_unlock();
-               return -ENOENT;
-       }
+       if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
+               goto out_enoent;
        nfs_mark_return_delegation(server, delegation);
        rcu_read_unlock();
 
        nfs_delegation_run_state_manager(clp);
        return 0;
+out_enoent:
+       rcu_read_unlock();
+       return -ENOENT;
 }
 
 static struct inode *
index be38b573495a78ddf281629da6e5f85f98eed17b..4a48fe4b84b68c4e704aea84ea761e101a5ad0df 100644 (file)
@@ -1846,6 +1846,11 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
                                                        GFP_KERNEL)) {
                SetPageUptodate(page);
                unlock_page(page);
+               /*
+                * add_to_page_cache_lru() grabs an extra page refcount.
+                * Drop it here to avoid leaking this page later.
+                */
+               page_cache_release(page);
        } else
                __free_page(page);
 
index 28a0a3cbd3b7818ee255f3a3c57b738d098e48c3..360114ae8b829bf705eaf4feda49b8fe484de2c0 100644 (file)
@@ -164,17 +164,16 @@ static void nfs_zap_caches_locked(struct inode *inode)
        if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
                nfs_fscache_invalidate(inode);
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR
-                                       | NFS_INO_INVALID_LABEL
                                        | NFS_INO_INVALID_DATA
                                        | NFS_INO_INVALID_ACCESS
                                        | NFS_INO_INVALID_ACL
                                        | NFS_INO_REVAL_PAGECACHE;
        } else
                nfsi->cache_validity |= NFS_INO_INVALID_ATTR
-                                       | NFS_INO_INVALID_LABEL
                                        | NFS_INO_INVALID_ACCESS
                                        | NFS_INO_INVALID_ACL
                                        | NFS_INO_REVAL_PAGECACHE;
+       nfs_zap_label_cache_locked(nfsi);
 }
 
 void nfs_zap_caches(struct inode *inode)
@@ -266,6 +265,13 @@ nfs_init_locked(struct inode *inode, void *opaque)
 }
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
+static void nfs_clear_label_invalid(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL;
+       spin_unlock(&inode->i_lock);
+}
+
 void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                        struct nfs4_label *label)
 {
@@ -283,6 +289,7 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
                                        __func__,
                                        (char *)label->label,
                                        label->len, error);
+               nfs_clear_label_invalid(inode);
        }
 }
 
@@ -1648,7 +1655,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                inode->i_blocks = fattr->du.nfs2.blocks;
 
        /* Update attrtimeo value if we're out of the unstable period */
-       if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) {
+       if (invalid & NFS_INO_INVALID_ATTR) {
                nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE);
                nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
                nfsi->attrtimeo_timestamp = now;
@@ -1661,7 +1668,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                }
        }
        invalid &= ~NFS_INO_INVALID_ATTR;
-       invalid &= ~NFS_INO_INVALID_LABEL;
        /* Don't invalidate the data if we were to blame */
        if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
                                || S_ISLNK(inode->i_mode)))
index 8b5cc04a86115e05f0a2e98e9b02a0b307b1b910..b46cf5a6732952460c68f6faeeb5479f355868d7 100644 (file)
@@ -176,7 +176,8 @@ extern struct nfs_server *nfs4_create_server(
 extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
                                                      struct nfs_fh *);
 extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
-                                       struct sockaddr *sap, size_t salen);
+                                       struct sockaddr *sap, size_t salen,
+                                       struct net *net);
 extern void nfs_free_server(struct nfs_server *server);
 extern struct nfs_server *nfs_clone_server(struct nfs_server *,
                                           struct nfs_fh *,
@@ -279,9 +280,18 @@ static inline void nfs4_label_free(struct nfs4_label *label)
        }
        return;
 }
+
+static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
+{
+       if (nfs_server_capable(&nfsi->vfs_inode, NFS_CAP_SECURITY_LABEL))
+               nfsi->cache_validity |= NFS_INO_INVALID_LABEL;
+}
 #else
 static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; }
 static inline void nfs4_label_free(void *label) {}
+static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi)
+{
+}
 #endif /* CONFIG_NFS_V4_SECURITY_LABEL */
 
 /* proc.c */
index aa9bc973f36a31eacbca297c71f2cd9bb5fb81e9..a462ef0fb5d6dcda8bab6f211e8122d7d972b070 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/lockd/bind.h>
 #include <linux/nfs_mount.h>
 #include <linux/freezer.h>
+#include <linux/xattr.h>
 
 #include "iostat.h"
 #include "internal.h"
index 860ad26a55905be060c1bcd1db5e9dde11746eec..0e46d3d1b6cc6c06854517c66ab4aa5f783cfb9e 100644 (file)
@@ -1135,6 +1135,7 @@ static int nfs_probe_destination(struct nfs_server *server)
  * @hostname: new end-point's hostname
  * @sap: new end-point's socket address
  * @salen: size of "sap"
+ * @net: net namespace
  *
  * The nfs_server must be quiescent before this function is invoked.
  * Either its session is drained (NFSv4.1+), or its transport is
@@ -1143,13 +1144,13 @@ static int nfs_probe_destination(struct nfs_server *server)
  * Returns zero on success, or a negative errno value.
  */
 int nfs4_update_server(struct nfs_server *server, const char *hostname,
-                      struct sockaddr *sap, size_t salen)
+                      struct sockaddr *sap, size_t salen, struct net *net)
 {
        struct nfs_client *clp = server->nfs_client;
        struct rpc_clnt *clnt = server->client;
        struct xprt_create xargs = {
                .ident          = clp->cl_proto,
-               .net            = &init_net,
+               .net            = net,
                .dstaddr        = sap,
                .addrlen        = salen,
                .servername     = hostname,
@@ -1189,7 +1190,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
        error = nfs4_set_client(server, hostname, sap, salen, buf,
                                clp->cl_rpcclient->cl_auth->au_flavor,
                                clp->cl_proto, clnt->cl_timeout,
-                               clp->cl_minorversion, clp->cl_net);
+                               clp->cl_minorversion, net);
        nfs_put_client(clp);
        if (error != 0) {
                nfs_server_insert_lists(server);
index 12c8132ad4081a3937c12ceebc991d1f61048093..b9a35c05b60f7f418ce91443d46dab88c690ca69 100644 (file)
@@ -324,8 +324,9 @@ static void filelayout_read_prepare(struct rpc_task *task, void *data)
                        &rdata->res.seq_res,
                        task))
                return;
-       nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
-                       rdata->args.lock_context, FMODE_READ);
+       if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context,
+                       rdata->args.lock_context, FMODE_READ) == -EIO)
+               rpc_exit(task, -EIO); /* lost lock, terminate I/O */
 }
 
 static void filelayout_read_call_done(struct rpc_task *task, void *data)
@@ -435,8 +436,9 @@ static void filelayout_write_prepare(struct rpc_task *task, void *data)
                        &wdata->res.seq_res,
                        task))
                return;
-       nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
-                       wdata->args.lock_context, FMODE_WRITE);
+       if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context,
+                       wdata->args.lock_context, FMODE_WRITE) == -EIO)
+               rpc_exit(task, -EIO); /* lost lock, terminate I/O */
 }
 
 static void filelayout_write_call_done(struct rpc_task *task, void *data)
index 4e7f05d3e9db77d1fe96533424362c4171201014..3d5dbf80d46a8c844bf7fd96c6db6935bb76d48b 100644 (file)
@@ -121,9 +121,8 @@ static int nfs4_validate_fspath(struct dentry *dentry,
 }
 
 static size_t nfs_parse_server_name(char *string, size_t len,
-               struct sockaddr *sa, size_t salen, struct nfs_server *server)
+               struct sockaddr *sa, size_t salen, struct net *net)
 {
-       struct net *net = rpc_net_ns(server->client);
        ssize_t ret;
 
        ret = rpc_pton(net, string, len, sa, salen);
@@ -223,6 +222,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
                                     const struct nfs4_fs_location *location)
 {
        const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+       struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
        struct vfsmount *mnt = ERR_PTR(-ENOENT);
        char *mnt_path;
        unsigned int maxbuflen;
@@ -248,8 +248,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
                        continue;
 
                mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
-                               mountdata->addr, addr_bufsize,
-                               NFS_SB(mountdata->sb));
+                               mountdata->addr, addr_bufsize, net);
                if (mountdata->addrlen == 0)
                        continue;
 
@@ -419,6 +418,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                const struct nfs4_fs_location *location)
 {
        const size_t addr_bufsize = sizeof(struct sockaddr_storage);
+       struct net *net = rpc_net_ns(server->client);
        struct sockaddr *sap;
        unsigned int s;
        size_t salen;
@@ -440,7 +440,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                        continue;
 
                salen = nfs_parse_server_name(buf->data, buf->len,
-                                               sap, addr_bufsize, server);
+                                               sap, addr_bufsize, net);
                if (salen == 0)
                        continue;
                rpc_set_port(sap, NFS_PORT);
@@ -450,7 +450,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server,
                if (hostname == NULL)
                        break;
 
-               error = nfs4_update_server(server, hostname, sap, salen);
+               error = nfs4_update_server(server, hostname, sap, salen, net);
                kfree(hostname);
                if (error == 0)
                        break;
index 2da6a698b8f7719c14eefec65e6148a48d030bb3..450bfedbe2f4c0f88cacc44ec504872487279faa 100644 (file)
@@ -2398,13 +2398,16 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
        if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
                /* Use that stateid */
-       } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
+       } else if (truncate && state != NULL) {
                struct nfs_lockowner lockowner = {
                        .l_owner = current->files,
                        .l_pid = current->tgid,
                };
-               nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
-                               &lockowner);
+               if (!nfs4_valid_open_stateid(state))
+                       return -EBADF;
+               if (nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+                               &lockowner) == -EIO)
+                       return -EBADF;
        } else
                nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
@@ -4011,8 +4014,9 @@ static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
 {
        nfs4_stateid current_stateid;
 
-       if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode))
-               return false;
+       /* If the current stateid represents a lost lock, then exit */
+       if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode) == -EIO)
+               return true;
        return nfs4_stateid_match(stateid, &current_stateid);
 }
 
@@ -5828,8 +5832,7 @@ struct nfs_release_lockowner_data {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server;
        struct nfs_release_lockowner_args args;
-       struct nfs4_sequence_args seq_args;
-       struct nfs4_sequence_res seq_res;
+       struct nfs_release_lockowner_res res;
        unsigned long timestamp;
 };
 
@@ -5837,7 +5840,7 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
 {
        struct nfs_release_lockowner_data *data = calldata;
        nfs40_setup_sequence(data->server,
-                               &data->seq_args, &data->seq_res, task);
+                               &data->args.seq_args, &data->res.seq_res, task);
        data->timestamp = jiffies;
 }
 
@@ -5846,7 +5849,7 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
        struct nfs_release_lockowner_data *data = calldata;
        struct nfs_server *server = data->server;
 
-       nfs40_sequence_done(task, &data->seq_res);
+       nfs40_sequence_done(task, &data->res.seq_res);
 
        switch (task->tk_status) {
        case 0:
@@ -5887,7 +5890,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
-       nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
@@ -5895,6 +5897,8 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
        data->args.lock_owner.s_dev = server->s_dev;
 
        msg.rpc_argp = &data->args;
+       msg.rpc_resp = &data->res;
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
 }
index e5be72518bd7ebe813522b1c24f7fa16b539421e..0deb32105ccf3cb8b40fe95365f91f8b4b9c4da4 100644 (file)
@@ -974,9 +974,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
        else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
                nfs4_stateid_copy(dst, &lsp->ls_stateid);
                ret = 0;
-               smp_rmb();
-               if (!list_empty(&lsp->ls_seqid.list))
-                       ret = -EWOULDBLOCK;
        }
        spin_unlock(&state->state_lock);
        nfs4_put_lock_state(lsp);
@@ -984,10 +981,9 @@ out:
        return ret;
 }
 
-static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 {
        const nfs4_stateid *src;
-       int ret;
        int seq;
 
        do {
@@ -996,12 +992,7 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
                if (test_bit(NFS_OPEN_STATE, &state->flags))
                        src = &state->open_stateid;
                nfs4_stateid_copy(dst, src);
-               ret = 0;
-               smp_rmb();
-               if (!list_empty(&state->owner->so_seqid.list))
-                       ret = -EWOULDBLOCK;
        } while (read_seqretry(&state->seqlock, seq));
-       return ret;
 }
 
 /*
@@ -1015,15 +1006,19 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
        if (ret == -EIO)
                /* A lost lock - don't even consider delegations */
                goto out;
-       if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
+       /* returns true if delegation stateid found and copied */
+       if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) {
+               ret = 0;
                goto out;
+       }
        if (ret != -ENOENT)
                /* nfs4_copy_delegation_stateid() didn't over-write
                 * dst, so it still has the lock stateid which we now
                 * choose to use.
                 */
                goto out;
-       ret = nfs4_copy_open_stateid(dst, state);
+       nfs4_copy_open_stateid(dst, state);
+       ret = 0;
 out:
        if (nfs_server_capable(state->inode, NFS_CAP_STATEID_NFSV41))
                dst->seqid = 0;
index d3a587144222b56becd0ce82597fb95bc8767592..d190e33d0ec2fdeb845eec70ab3c610ab551758d 100644 (file)
@@ -151,17 +151,15 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
                pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
                if (IS_ERR(pacl))
                        return PTR_ERR(pacl);
-               /* allocate for worst case: one (deny, allow) pair each: */
-               size += 2 * pacl->a_count;
        }
+       /* allocate for worst case: one (deny, allow) pair each: */
+       size += 2 * pacl->a_count;
 
        if (S_ISDIR(inode->i_mode)) {
                flags = NFS4_ACL_DIR;
                dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
                if (dpacl)
                        size += 2 * dpacl->a_count;
-       } else {
-               dpacl = NULL;
        }
 
        *acl = nfs4_acl_new(size);
@@ -170,8 +168,7 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
                goto out;
        }
 
-       if (pacl)
-               _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
+       _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
 
        if (dpacl)
                _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT);
index 017d3cb5e99b4391027fe37b7c56c23966754e2d..6d7be3f8035631cb207a5733c71dbfc2f800fa4c 100644 (file)
@@ -449,6 +449,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        fh_lock(fhp);
        host_err = notify_change(dentry, iap, NULL);
        fh_unlock(fhp);
+       err = nfserrno(host_err);
 
 out_put_write_access:
        if (size_change)
index 0b9ff4395e6ac320f6108f7c3cabb2d57d5a426f..abc8cbcfe90e0fca9f67471740c0b41c9055b7c6 100644 (file)
@@ -86,7 +86,7 @@ static int dnotify_handle_event(struct fsnotify_group *group,
                                struct fsnotify_mark *inode_mark,
                                struct fsnotify_mark *vfsmount_mark,
                                u32 mask, void *data, int data_type,
-                               const unsigned char *file_name)
+                               const unsigned char *file_name, u32 cookie)
 {
        struct dnotify_mark *dn_mark;
        struct dnotify_struct *dn;
index 0e792f5e3147c3cfcf38a980716075ea509b0e46..dc638f786d5c762373288942dc04cc5c5cee0750 100644 (file)
@@ -147,7 +147,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
                                 struct fsnotify_mark *inode_mark,
                                 struct fsnotify_mark *fanotify_mark,
                                 u32 mask, void *data, int data_type,
-                                const unsigned char *file_name)
+                                const unsigned char *file_name, u32 cookie)
 {
        int ret = 0;
        struct fanotify_event_info *event;
@@ -192,10 +192,12 @@ static int fanotify_handle_event(struct fsnotify_group *group,
 
        ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
        if (ret) {
-               BUG_ON(mask & FAN_ALL_PERM_EVENTS);
+               /* Permission events shouldn't be merged */
+               BUG_ON(ret == 1 && mask & FAN_ALL_PERM_EVENTS);
                /* Our event wasn't used in the end. Free it. */
                fsnotify_destroy_event(group, fsn_event);
-               ret = 0;
+
+               return 0;
        }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
index b6175fa11bf856809d1ee6a43ee9b861980e9160..287a22c041496a206d94daa299be55a20b4786a2 100644 (file)
@@ -698,6 +698,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        struct fsnotify_group *group;
        int f_flags, fd;
        struct user_struct *user;
+       struct fanotify_event_info *oevent;
 
        pr_debug("%s: flags=%d event_f_flags=%d\n",
                __func__, flags, event_f_flags);
@@ -730,8 +731,20 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        group->fanotify_data.user = user;
        atomic_inc(&user->fanotify_listeners);
 
+       oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+       if (unlikely(!oevent)) {
+               fd = -ENOMEM;
+               goto out_destroy_group;
+       }
+       group->overflow_event = &oevent->fse;
+       fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+       oevent->tgid = get_pid(task_tgid(current));
+       oevent->path.mnt = NULL;
+       oevent->path.dentry = NULL;
+
        group->fanotify_data.f_flags = event_f_flags;
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       oevent->response = 0;
        mutex_init(&group->fanotify_data.access_mutex);
        init_waitqueue_head(&group->fanotify_data.access_waitq);
        INIT_LIST_HEAD(&group->fanotify_data.access_list);
index 1d4e1ea2f37ca4995db3f16db9bd00bbf862ca93..9d3e9c50066aaf5856350cf3bc85576a79bab900 100644 (file)
@@ -179,7 +179,7 @@ static int send_to_group(struct inode *to_tell,
 
        return group->ops->handle_event(group, to_tell, inode_mark,
                                        vfsmount_mark, mask, data, data_is,
-                                       file_name);
+                                       file_name, cookie);
 }
 
 /*
index ee674fe2cec7f3f7b99ad09363b6a425ff4d6dbd..ad199598045655105e7ba4db0ed639357bf3fc6f 100644 (file)
@@ -55,6 +55,13 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
        /* clear the notification queue of all events */
        fsnotify_flush_notify(group);
 
+       /*
+        * Destroy overflow event (we cannot use fsnotify_destroy_event() as
+        * that deliberately ignores overflow events.
+        */
+       if (group->overflow_event)
+               group->ops->free_event(group->overflow_event);
+
        fsnotify_put_group(group);
 }
 
@@ -99,7 +106,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
        INIT_LIST_HEAD(&group->marks_list);
 
        group->ops = ops;
-       fsnotify_init_event(&group->overflow_event, NULL, FS_Q_OVERFLOW);
 
        return group;
 }
index 485eef3f4407a0371d903c08a75c9f262dfde82e..ed855ef6f0775e447489e7dd43e00ff3891c850e 100644 (file)
@@ -27,6 +27,6 @@ extern int inotify_handle_event(struct fsnotify_group *group,
                                struct fsnotify_mark *inode_mark,
                                struct fsnotify_mark *vfsmount_mark,
                                u32 mask, void *data, int data_type,
-                               const unsigned char *file_name);
+                               const unsigned char *file_name, u32 cookie);
 
 extern const struct fsnotify_ops inotify_fsnotify_ops;
index d5ee56348bb803fd0ddff46d4f3da7d0fa7016d1..43ab1e1a07a20acaca5a4741487ac5121e00bbd4 100644 (file)
@@ -67,7 +67,7 @@ int inotify_handle_event(struct fsnotify_group *group,
                         struct fsnotify_mark *inode_mark,
                         struct fsnotify_mark *vfsmount_mark,
                         u32 mask, void *data, int data_type,
-                        const unsigned char *file_name)
+                        const unsigned char *file_name, u32 cookie)
 {
        struct inotify_inode_mark *i_mark;
        struct inotify_event_info *event;
@@ -103,6 +103,7 @@ int inotify_handle_event(struct fsnotify_group *group,
        fsn_event = &event->fse;
        fsnotify_init_event(fsn_event, inode, mask);
        event->wd = i_mark->wd;
+       event->sync_cookie = cookie;
        event->name_len = len;
        if (len)
                strcpy(event->name, file_name);
index 497395c8274bc62cd0fab6c2cf89ce4950fafffc..78a2ca3966c3857a8f4a5bf5369b63ad10ef3380 100644 (file)
@@ -495,7 +495,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
 
        /* Queue ignore event for the watch */
        inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED,
-                            NULL, FSNOTIFY_EVENT_NONE, NULL);
+                            NULL, FSNOTIFY_EVENT_NONE, NULL, 0);
 
        i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
        /* remove this mark from the idr */
@@ -633,11 +633,23 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
 static struct fsnotify_group *inotify_new_group(unsigned int max_events)
 {
        struct fsnotify_group *group;
+       struct inotify_event_info *oevent;
 
        group = fsnotify_alloc_group(&inotify_fsnotify_ops);
        if (IS_ERR(group))
                return group;
 
+       oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL);
+       if (unlikely(!oevent)) {
+               fsnotify_destroy_group(group);
+               return ERR_PTR(-ENOMEM);
+       }
+       group->overflow_event = &oevent->fse;
+       fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+       oevent->wd = -1;
+       oevent->sync_cookie = 0;
+       oevent->name_len = 0;
+
        group->max_events = max_events;
 
        spin_lock_init(&group->inotify_data.idr_lock);
index 18b3c4427dcac0f2c9125581cc171be3f1eb3a9f..1e58402171a56cd9d078ab62307951689a5630df 100644 (file)
@@ -80,7 +80,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
 /*
  * Add an event to the group notification queue.  The group can later pull this
  * event off the queue to deal with.  The function returns 0 if the event was
- * added to the queue, 1 if the event was merged with some other queued event.
+ * added to the queue, 1 if the event was merged with some other queued event,
+ * 2 if the queue of events has overflown.
  */
 int fsnotify_add_notify_event(struct fsnotify_group *group,
                              struct fsnotify_event *event,
@@ -95,10 +96,14 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
        mutex_lock(&group->notification_mutex);
 
        if (group->q_len >= group->max_events) {
+               ret = 2;
                /* Queue overflow event only if it isn't already queued */
-               if (list_empty(&group->overflow_event.list))
-                       event = &group->overflow_event;
-               ret = 1;
+               if (!list_empty(&group->overflow_event->list)) {
+                       mutex_unlock(&group->notification_mutex);
+                       return ret;
+               }
+               event = group->overflow_event;
+               goto queue;
        }
 
        if (!list_empty(list) && merge) {
@@ -109,6 +114,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
                }
        }
 
+queue:
        group->q_len++;
        list_add_tail(&event->list, list);
        mutex_unlock(&group->notification_mutex);
@@ -132,7 +138,11 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group
 
        event = list_first_entry(&group->notification_list,
                                 struct fsnotify_event, list);
-       list_del(&event->list);
+       /*
+        * We need to init list head for the case of overflow event so that
+        * check in fsnotify_add_notify_events() works
+        */
+       list_del_init(&event->list);
        group->q_len--;
 
        return event;
index aada5801567adc83a38af6946021cd655b06a770..e2edff38be52b6963c32962604b26adfbe682dd4 100644 (file)
@@ -7158,7 +7158,7 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
        if (end > i_size_read(inode))
                end = i_size_read(inode);
 
-       BUG_ON(start >= end);
+       BUG_ON(start > end);
 
        if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) ||
            !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) ||
index d77d71ead8d12071a52b1f0f63c66f1077c93f84..51632c40e896fd0b7c4e4c87b2afc5dc4f418aca 100644 (file)
@@ -185,6 +185,9 @@ static int ocfs2_sync_file(struct file *file, loff_t start, loff_t end,
                              file->f_path.dentry->d_name.name,
                              (unsigned long long)datasync);
 
+       if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+               return -EROFS;
+
        err = filemap_write_and_wait_range(inode->i_mapping, start, end);
        if (err)
                return err;
@@ -474,11 +477,6 @@ static int ocfs2_truncate_file(struct inode *inode,
                goto bail;
        }
 
-       /* lets handle the simple truncate cases before doing any more
-        * cluster locking. */
-       if (new_i_size == le64_to_cpu(fe->i_size))
-               goto bail;
-
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
        ocfs2_resv_discard(&osb->osb_la_resmap,
@@ -718,7 +716,8 @@ leave:
  * While a write will already be ordering the data, a truncate will not.
  * Thus, we need to explicitly order the zeroed pages.
  */
-static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode)
+static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode,
+                                               struct buffer_head *di_bh)
 {
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        handle_t *handle = NULL;
@@ -735,7 +734,14 @@ static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode)
        }
 
        ret = ocfs2_jbd2_file_inode(handle, inode);
-       if (ret < 0)
+       if (ret < 0) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
+                                     OCFS2_JOURNAL_ACCESS_WRITE);
+       if (ret)
                mlog_errno(ret);
 
 out:
@@ -751,7 +757,7 @@ out:
  * to be too fragile to do exactly what we need without us having to
  * worry about recursive locking in ->write_begin() and ->write_end(). */
 static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
-                                u64 abs_to)
+                                u64 abs_to, struct buffer_head *di_bh)
 {
        struct address_space *mapping = inode->i_mapping;
        struct page *page;
@@ -759,6 +765,7 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
        handle_t *handle = NULL;
        int ret = 0;
        unsigned zero_from, zero_to, block_start, block_end;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
 
        BUG_ON(abs_from >= abs_to);
        BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT));
@@ -801,7 +808,8 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
                }
 
                if (!handle) {
-                       handle = ocfs2_zero_start_ordered_transaction(inode);
+                       handle = ocfs2_zero_start_ordered_transaction(inode,
+                                                                     di_bh);
                        if (IS_ERR(handle)) {
                                ret = PTR_ERR(handle);
                                handle = NULL;
@@ -818,8 +826,22 @@ static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
                        ret = 0;
        }
 
-       if (handle)
+       if (handle) {
+               /*
+                * fs-writeback will release the dirty pages without page lock
+                * whose offset are over inode size, the release happens at
+                * block_write_full_page_endio().
+                */
+               i_size_write(inode, abs_to);
+               inode->i_blocks = ocfs2_inode_sector_count(inode);
+               di->i_size = cpu_to_le64((u64)i_size_read(inode));
+               inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+               di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
+               di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
+               di->i_mtime_nsec = di->i_ctime_nsec;
+               ocfs2_journal_dirty(handle, di_bh);
                ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+       }
 
 out_unlock:
        unlock_page(page);
@@ -915,7 +937,7 @@ out:
  * has made sure that the entire range needs zeroing.
  */
 static int ocfs2_zero_extend_range(struct inode *inode, u64 range_start,
-                                  u64 range_end)
+                                  u64 range_end, struct buffer_head *di_bh)
 {
        int rc = 0;
        u64 next_pos;
@@ -931,7 +953,7 @@ static int ocfs2_zero_extend_range(struct inode *inode, u64 range_start,
                next_pos = (zero_pos & PAGE_CACHE_MASK) + PAGE_CACHE_SIZE;
                if (next_pos > range_end)
                        next_pos = range_end;
-               rc = ocfs2_write_zero_page(inode, zero_pos, next_pos);
+               rc = ocfs2_write_zero_page(inode, zero_pos, next_pos, di_bh);
                if (rc < 0) {
                        mlog_errno(rc);
                        break;
@@ -977,7 +999,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
                        range_end = zero_to_size;
 
                ret = ocfs2_zero_extend_range(inode, range_start,
-                                             range_end);
+                                             range_end, di_bh);
                if (ret) {
                        mlog_errno(ret);
                        break;
@@ -1145,14 +1167,14 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
                goto bail_unlock_rw;
        }
 
-       if (size_change && attr->ia_size != i_size_read(inode)) {
+       if (size_change) {
                status = inode_newsize_ok(inode, attr->ia_size);
                if (status)
                        goto bail_unlock;
 
                inode_dio_wait(inode);
 
-               if (i_size_read(inode) > attr->ia_size) {
+               if (i_size_read(inode) >= attr->ia_size) {
                        if (ocfs2_should_order_data(inode)) {
                                status = ocfs2_begin_ordered_truncate(inode,
                                                                      attr->ia_size);
@@ -2371,8 +2393,8 @@ out_dio:
 
        if (((file->f_flags & O_DSYNC) && !direct_io) || IS_SYNC(inode) ||
            ((file->f_flags & O_DIRECT) && !direct_io)) {
-               ret = filemap_fdatawrite_range(file->f_mapping, pos,
-                                              pos + count - 1);
+               ret = filemap_fdatawrite_range(file->f_mapping, *ppos,
+                                              *ppos + count - 1);
                if (ret < 0)
                        written = ret;
 
@@ -2385,8 +2407,8 @@ out_dio:
                }
 
                if (!ret)
-                       ret = filemap_fdatawait_range(file->f_mapping, pos,
-                                                     pos + count - 1);
+                       ret = filemap_fdatawait_range(file->f_mapping, *ppos,
+                                                     *ppos + count - 1);
        }
 
        /*
index f4d609be940086794ff8e64b1ed7cd832ba517f5..3683643f3f0ecf4410e0d85549ca4494f60af7fb 100644 (file)
@@ -664,6 +664,7 @@ static int ocfs2_link(struct dentry *old_dentry,
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
        struct ocfs2_dir_lookup_result lookup = { NULL, };
        sigset_t oldset;
+       u64 old_de_ino;
 
        trace_ocfs2_link((unsigned long long)OCFS2_I(inode)->ip_blkno,
                         old_dentry->d_name.len, old_dentry->d_name.name,
@@ -686,6 +687,22 @@ static int ocfs2_link(struct dentry *old_dentry,
                goto out;
        }
 
+       err = ocfs2_lookup_ino_from_name(dir, old_dentry->d_name.name,
+                       old_dentry->d_name.len, &old_de_ino);
+       if (err) {
+               err = -ENOENT;
+               goto out;
+       }
+
+       /*
+        * Check whether another node removed the source inode while we
+        * were in the vfs.
+        */
+       if (old_de_ino != OCFS2_I(inode)->ip_blkno) {
+               err = -ENOENT;
+               goto out;
+       }
+
        err = ocfs2_check_dir_for_entry(dir, dentry->d_name.name,
                                        dentry->d_name.len);
        if (err)
index aaa50611ec66c27f2b6cd9a67a039a05e0253787..d7b5108789e2e7d8a26049b7dc6a01f8a0ff2d6f 100644 (file)
@@ -717,6 +717,12 @@ static int ocfs2_release_dquot(struct dquot *dquot)
         */
        if (status < 0)
                mlog_errno(status);
+       /*
+        * Clear dq_off so that we search for the structure in quota file next
+        * time we acquire it. The structure might be deleted and reallocated
+        * elsewhere by another node while our dquot structure is on freelist.
+        */
+       dquot->dq_off = 0;
        clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
 out_trans:
        ocfs2_commit_trans(osb, handle);
@@ -756,16 +762,17 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
        status = ocfs2_lock_global_qf(info, 1);
        if (status < 0)
                goto out;
-       if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
-               status = ocfs2_qinfo_lock(info, 0);
-               if (status < 0)
-                       goto out_dq;
-               status = qtree_read_dquot(&info->dqi_gi, dquot);
-               ocfs2_qinfo_unlock(info, 0);
-               if (status < 0)
-                       goto out_dq;
-       }
-       set_bit(DQ_READ_B, &dquot->dq_flags);
+       status = ocfs2_qinfo_lock(info, 0);
+       if (status < 0)
+               goto out_dq;
+       /*
+        * We always want to read dquot structure from disk because we don't
+        * know what happened with it while it was on freelist.
+        */
+       status = qtree_read_dquot(&info->dqi_gi, dquot);
+       ocfs2_qinfo_unlock(info, 0);
+       if (status < 0)
+               goto out_dq;
 
        OCFS2_DQUOT(dquot)->dq_use_count++;
        OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
index 2e4344be3b962b40a6cd4e5743a87f088b7abe63..2001862bf2b1cfbb20ed78bd9febeacbc96b42a4 100644 (file)
@@ -1303,10 +1303,6 @@ int ocfs2_local_release_dquot(handle_t *handle, struct dquot *dquot)
        ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
 
 out:
-       /* Clear the read bit so that next time someone uses this
-        * dquot he reads fresh info from disk and allocates local
-        * dquot structure */
-       clear_bit(DQ_READ_B, &dquot->dq_flags);
        return status;
 }
 
index 1324e6600e57378b8e4d1624dc1366af57fde7b2..ca5ce14cbddcef81498305f8ccbccc978750faed 100644 (file)
@@ -346,7 +346,9 @@ int ocfs2_cluster_connect(const char *stack_name,
 
        strlcpy(new_conn->cc_name, group, GROUP_NAME_MAX + 1);
        new_conn->cc_namelen = grouplen;
-       strlcpy(new_conn->cc_cluster_name, cluster_name, CLUSTER_NAME_MAX + 1);
+       if (cluster_name_len)
+               strlcpy(new_conn->cc_cluster_name, cluster_name,
+                       CLUSTER_NAME_MAX + 1);
        new_conn->cc_cluster_name_len = cluster_name_len;
        new_conn->cc_recovery_handler = recovery_handler;
        new_conn->cc_recovery_data = recovery_data;
index 4b3e1edf2fe4d917e69e56b3e268e32f2ae7301a..b9ed8b25c108c69d68889b5b6eadac9878eb7bd9 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -705,6 +705,10 @@ static int do_dentry_open(struct file *f,
                return 0;
        }
 
+       /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
+       if (S_ISREG(inode->i_mode))
+               f->f_mode |= FMODE_ATOMIC_POS;
+
        f->f_op = fops_get(inode->i_fop);
        if (unlikely(WARN_ON(!f->f_op))) {
                error = -ENODEV;
index 51507065263b29e3b915a6aa2238630fe3f7ac67..b9760628e1fde7b9a5c681798a65185144abeb92 100644 (file)
@@ -1824,6 +1824,7 @@ static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
        if (rc)
                goto out_mmput;
 
+       rc = -ENOENT;
        down_read(&mm->mmap_sem);
        vma = find_exact_vma(mm, vm_start, vm_end);
        if (vma && vma->vm_file) {
index 02174a610315ebb218880a8744e05b2244b6d26f..e647c55275d9ff9f96b92ac859e65c10fc03d318 100644 (file)
@@ -121,9 +121,8 @@ u64 stable_page_flags(struct page *page)
         * just checks PG_head/PG_tail, so we need to check PageLRU/PageAnon
         * to make sure a given page is a thp, not a non-huge compound page.
         */
-       else if (PageTransCompound(page) &&
-                (PageLRU(compound_trans_head(page)) ||
-                 PageAnon(compound_trans_head(page))))
+       else if (PageTransCompound(page) && (PageLRU(compound_head(page)) ||
+                                            PageAnon(compound_head(page))))
                u |= 1 << KPF_THP;
 
        /*
index 2ca7ba047f04b658028e1e8c9cd9f5ba746d9946..88d4585b30f1531b6e609825315d0868cc2edbe6 100644 (file)
@@ -468,17 +468,24 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
                        return rc;
                }
                nhdr_ptr = notes_section;
-               while (real_sz < max_sz) {
-                       if (nhdr_ptr->n_namesz == 0)
-                               break;
+               while (nhdr_ptr->n_namesz != 0) {
                        sz = sizeof(Elf64_Nhdr) +
                                ((nhdr_ptr->n_namesz + 3) & ~3) +
                                ((nhdr_ptr->n_descsz + 3) & ~3);
+                       if ((real_sz + sz) > max_sz) {
+                               pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
+                                       nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
+                               break;
+                       }
                        real_sz += sz;
                        nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
                }
                kfree(notes_section);
                phdr_ptr->p_memsz = real_sz;
+               if (real_sz == 0) {
+                       pr_warn("Warning: Zero PT_NOTE entries found\n");
+                       return -EINVAL;
+               }
        }
 
        return 0;
@@ -648,17 +655,24 @@ static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
                        return rc;
                }
                nhdr_ptr = notes_section;
-               while (real_sz < max_sz) {
-                       if (nhdr_ptr->n_namesz == 0)
-                               break;
+               while (nhdr_ptr->n_namesz != 0) {
                        sz = sizeof(Elf32_Nhdr) +
                                ((nhdr_ptr->n_namesz + 3) & ~3) +
                                ((nhdr_ptr->n_descsz + 3) & ~3);
+                       if ((real_sz + sz) > max_sz) {
+                               pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
+                                       nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
+                               break;
+                       }
                        real_sz += sz;
                        nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
                }
                kfree(notes_section);
                phdr_ptr->p_memsz = real_sz;
+               if (real_sz == 0) {
+                       pr_warn("Warning: Zero PT_NOTE entries found\n");
+                       return -EINVAL;
+               }
        }
 
        return 0;
index 831d49a4111f8405716d96ff6a451fc9ebd59e91..cfc8dcc160437c0daacd234f43d29faeb9b2fd33 100644 (file)
@@ -581,9 +581,17 @@ int dquot_scan_active(struct super_block *sb,
                dqstats_inc(DQST_LOOKUPS);
                dqput(old_dquot);
                old_dquot = dquot;
-               ret = fn(dquot, priv);
-               if (ret < 0)
-                       goto out;
+               /*
+                * ->release_dquot() can be racing with us. Our reference
+                * protects us from new calls to it so just wait for any
+                * outstanding call and recheck the DQ_ACTIVE_B after that.
+                */
+               wait_on_dquot(dquot);
+               if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+                       ret = fn(dquot, priv);
+                       if (ret < 0)
+                               goto out;
+               }
                spin_lock(&dq_list_lock);
                /* We are safe to continue now because our dquot could not
                 * be moved out of the inuse list while we hold the reference */
index edc5746a902a090ce4dbda6b8b1205e729dff5b3..28cc9c810744a748d3a071b536c36547be87aa14 100644 (file)
@@ -264,10 +264,22 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(vfs_llseek);
 
+static inline struct fd fdget_pos(int fd)
+{
+       return __to_fd(__fdget_pos(fd));
+}
+
+static inline void fdput_pos(struct fd f)
+{
+       if (f.flags & FDPUT_POS_UNLOCK)
+               mutex_unlock(&f.file->f_pos_lock);
+       fdput(f);
+}
+
 SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
 {
        off_t retval;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -278,7 +290,7 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
                if (res != (loff_t)retval)
                        retval = -EOVERFLOW;    /* LFS: should only happen on 32 bit platforms */
        }
-       fdput(f);
+       fdput_pos(f);
        return retval;
 }
 
@@ -295,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                unsigned int, whence)
 {
        int retval;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        loff_t offset;
 
        if (!f.file)
@@ -315,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high,
                        retval = 0;
        }
 out_putf:
-       fdput(f);
+       fdput_pos(f);
        return retval;
 }
 #endif
@@ -498,7 +510,7 @@ static inline void file_pos_write(struct file *file, loff_t pos)
 
 SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -506,7 +518,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
                ret = vfs_read(f.file, buf, count, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
        return ret;
 }
@@ -514,7 +526,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
 SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
                size_t, count)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -522,7 +534,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
                ret = vfs_write(f.file, buf, count, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        return ret;
@@ -797,7 +809,7 @@ EXPORT_SYMBOL(vfs_writev);
 SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -805,7 +817,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
                ret = vfs_readv(f.file, vec, vlen, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        if (ret > 0)
@@ -817,7 +829,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec,
 SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                unsigned long, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret = -EBADF;
 
        if (f.file) {
@@ -825,7 +837,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec,
                ret = vfs_writev(f.file, vec, vlen, &pos);
                if (ret >= 0)
                        file_pos_write(f.file, pos);
-               fdput(f);
+               fdput_pos(f);
        }
 
        if (ret > 0)
@@ -968,7 +980,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
                compat_ulong_t, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret;
        loff_t pos;
 
@@ -978,7 +990,7 @@ COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
        ret = compat_readv(f.file, vec, vlen, &pos);
        if (ret >= 0)
                f.file->f_pos = pos;
-       fdput(f);
+       fdput_pos(f);
        return ret;
 }
 
@@ -1035,7 +1047,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
                const struct compat_iovec __user *, vec,
                compat_ulong_t, vlen)
 {
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        ssize_t ret;
        loff_t pos;
 
@@ -1045,7 +1057,7 @@ COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
        ret = compat_writev(f.file, vec, vlen, &pos);
        if (ret >= 0)
                f.file->f_pos = pos;
-       fdput(f);
+       fdput_pos(f);
        return ret;
 }
 
index 2b7882b508db4ce66486455d22f812e83809e77f..9a3c68cf6026ae0405ef91c07f3ec9ef02854f1a 100644 (file)
@@ -324,23 +324,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                        switch (flag) {
                        case M_INSERT:  /* insert item into L[0] */
 
-                               if (item_pos == tb->lnum[0] - 1
-                                   && tb->lbytes != -1) {
+                               if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
                                        /* part of new item falls into L[0] */
                                        int new_item_len;
                                        int version;
 
-                                       ret_val =
-                                           leaf_shift_left(tb, tb->lnum[0] - 1,
-                                                           -1);
+                                       ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, -1);
 
                                        /* Calculate item length to insert to S[0] */
-                                       new_item_len =
-                                           ih_item_len(ih) - tb->lbytes;
+                                       new_item_len = ih_item_len(ih) - tb->lbytes;
                                        /* Calculate and check item length to insert to L[0] */
-                                       put_ih_item_len(ih,
-                                                       ih_item_len(ih) -
-                                                       new_item_len);
+                                       put_ih_item_len(ih, ih_item_len(ih) - new_item_len);
 
                                        RFALSE(ih_item_len(ih) <= 0,
                                               "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
@@ -349,30 +343,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                        /* Insert new item into L[0] */
                                        buffer_info_init_left(tb, &bi);
                                        leaf_insert_into_buf(&bi,
-                                                            n + item_pos -
-                                                            ret_val, ih, body,
-                                                            zeros_num >
-                                                            ih_item_len(ih) ?
-                                                            ih_item_len(ih) :
-                                                            zeros_num);
+                                                       n + item_pos - ret_val, ih, body,
+                                                       zeros_num > ih_item_len(ih) ? ih_item_len(ih) : zeros_num);
 
                                        version = ih_version(ih);
 
                                        /* Calculate key component, item length and body to insert into S[0] */
-                                       set_le_ih_k_offset(ih,
-                                                          le_ih_k_offset(ih) +
-                                                          (tb->
-                                                           lbytes <<
-                                                           (is_indirect_le_ih
-                                                            (ih) ? tb->tb_sb->
-                                                            s_blocksize_bits -
-                                                            UNFM_P_SHIFT :
-                                                            0)));
+                                       set_le_ih_k_offset(ih, le_ih_k_offset(ih) +
+                                                       (tb-> lbytes << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0)));
 
                                        put_ih_item_len(ih, new_item_len);
                                        if (tb->lbytes > zeros_num) {
-                                               body +=
-                                                   (tb->lbytes - zeros_num);
+                                               body += (tb->lbytes - zeros_num);
                                                zeros_num = 0;
                                        } else
                                                zeros_num -= tb->lbytes;
@@ -383,15 +365,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                } else {
                                        /* new item in whole falls into L[0] */
                                        /* Shift lnum[0]-1 items to L[0] */
-                                       ret_val =
-                                           leaf_shift_left(tb, tb->lnum[0] - 1,
-                                                           tb->lbytes);
+                                       ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, tb->lbytes);
                                        /* Insert new item into L[0] */
                                        buffer_info_init_left(tb, &bi);
-                                       leaf_insert_into_buf(&bi,
-                                                            n + item_pos -
-                                                            ret_val, ih, body,
-                                                            zeros_num);
+                                       leaf_insert_into_buf(&bi, n + item_pos - ret_val, ih, body, zeros_num);
                                        tb->insert_size[0] = 0;
                                        zeros_num = 0;
                                }
@@ -399,264 +376,117 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,  /* item h
 
                        case M_PASTE:   /* append item in L[0] */
 
-                               if (item_pos == tb->lnum[0] - 1
-                                   && tb->lbytes != -1) {
+                               if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
                                        /* we must shift the part of the appended item */
-                                       if (is_direntry_le_ih
-                                           (B_N_PITEM_HEAD(tbS0, item_pos))) {
+                                       if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) {
 
                                                RFALSE(zeros_num,
                                                       "PAP-12090: invalid parameter in case of a directory");
                                                /* directory item */
                                                if (tb->lbytes > pos_in_item) {
                                                        /* new directory entry falls into L[0] */
-                                                       struct item_head
-                                                           *pasted;
-                                                       int l_pos_in_item =
-                                                           pos_in_item;
+                                                       struct item_head *pasted;
+                                                       int l_pos_in_item = pos_in_item;
 
                                                        /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
-                                                       ret_val =
-                                                           leaf_shift_left(tb,
-                                                                           tb->
-                                                                           lnum
-                                                                           [0],
-                                                                           tb->
-                                                                           lbytes
-                                                                           -
-                                                                           1);
-                                                       if (ret_val
-                                                           && !item_pos) {
-                                                               pasted =
-                                                                   B_N_PITEM_HEAD
-                                                                   (tb->L[0],
-                                                                    B_NR_ITEMS
-                                                                    (tb->
-                                                                     L[0]) -
-                                                                    1);
-                                                               l_pos_in_item +=
-                                                                   I_ENTRY_COUNT
-                                                                   (pasted) -
-                                                                   (tb->
-                                                                    lbytes -
-                                                                    1);
+                                                       ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes-1);
+                                                       if (ret_val && !item_pos) {
+                                                               pasted = B_N_PITEM_HEAD(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1);
+                                                               l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes -1);
                                                        }
 
                                                        /* Append given directory entry to directory item */
                                                        buffer_info_init_left(tb, &bi);
-                                                       leaf_paste_in_buffer
-                                                           (&bi,
-                                                            n + item_pos -
-                                                            ret_val,
-                                                            l_pos_in_item,
-                                                            tb->insert_size[0],
-                                                            body, zeros_num);
+                                                       leaf_paste_in_buffer(&bi, n + item_pos - ret_val, l_pos_in_item, tb->insert_size[0], body, zeros_num);
 
                                                        /* previous string prepared space for pasting new entry, following string pastes this entry */
 
                                                        /* when we have merge directory item, pos_in_item has been changed too */
 
                                                        /* paste new directory entry. 1 is entry number */
-                                                       leaf_paste_entries(&bi,
-                                                                          n +
-                                                                          item_pos
-                                                                          -
-                                                                          ret_val,
-                                                                          l_pos_in_item,
-                                                                          1,
-                                                                          (struct
-                                                                           reiserfs_de_head
-                                                                           *)
-                                                                          body,
-                                                                          body
-                                                                          +
-                                                                          DEH_SIZE,
-                                                                          tb->
-                                                                          insert_size
-                                                                          [0]
-                                                           );
+                                                       leaf_paste_entries(&bi, n + item_pos - ret_val, l_pos_in_item,
+                                                                          1, (struct reiserfs_de_head *) body,
+                                                                          body + DEH_SIZE, tb->insert_size[0]);
                                                        tb->insert_size[0] = 0;
                                                } else {
                                                        /* new directory item doesn't fall into L[0] */
                                                        /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
-                                                       leaf_shift_left(tb,
-                                                                       tb->
-                                                                       lnum[0],
-                                                                       tb->
-                                                                       lbytes);
+                                                       leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
                                                }
                                                /* Calculate new position to append in item body */
                                                pos_in_item -= tb->lbytes;
                                        } else {
                                                /* regular object */
-                                               RFALSE(tb->lbytes <= 0,
-                                                      "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
-                                                      tb->lbytes);
-                                               RFALSE(pos_in_item !=
-                                                      ih_item_len
-                                                      (B_N_PITEM_HEAD
-                                                       (tbS0, item_pos)),
+                                               RFALSE(tb->lbytes <= 0, "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", tb->lbytes);
+                                               RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),
                                                       "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
-                                                      ih_item_len
-                                                      (B_N_PITEM_HEAD
-                                                       (tbS0, item_pos)),
-                                                      pos_in_item);
+                                                      ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),pos_in_item);
 
                                                if (tb->lbytes >= pos_in_item) {
                                                        /* appended item will be in L[0] in whole */
                                                        int l_n;
 
                                                        /* this bytes number must be appended to the last item of L[h] */
-                                                       l_n =
-                                                           tb->lbytes -
-                                                           pos_in_item;
+                                                       l_n = tb->lbytes - pos_in_item;
 
                                                        /* Calculate new insert_size[0] */
-                                                       tb->insert_size[0] -=
-                                                           l_n;
+                                                       tb->insert_size[0] -= l_n;
 
-                                                       RFALSE(tb->
-                                                              insert_size[0] <=
-                                                              0,
+                                                       RFALSE(tb->insert_size[0] <= 0,
                                                               "PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
-                                                              tb->
-                                                              insert_size[0]);
-                                                       ret_val =
-                                                           leaf_shift_left(tb,
-                                                                           tb->
-                                                                           lnum
-                                                                           [0],
-                                                                           ih_item_len
-                                                                           (B_N_PITEM_HEAD
-                                                                            (tbS0,
-                                                                             item_pos)));
+                                                              tb->insert_size[0]);
+                                                       ret_val = leaf_shift_left(tb, tb->lnum[0], ih_item_len
+                                                                           (B_N_PITEM_HEAD(tbS0, item_pos)));
                                                        /* Append to body of item in L[0] */
                                                        buffer_info_init_left(tb, &bi);
                                                        leaf_paste_in_buffer
-                                                           (&bi,
-                                                            n + item_pos -
-                                                            ret_val,
-                                                            ih_item_len
-                                                            (B_N_PITEM_HEAD
-                                                             (tb->L[0],
-                                                              n + item_pos -
-                                                              ret_val)), l_n,
-                                                            body,
-                                                            zeros_num >
-                                                            l_n ? l_n :
-                                                            zeros_num);
+                                                           (&bi, n + item_pos - ret_val, ih_item_len
+                                                            (B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val)),
+                                                            l_n, body,
+                                                            zeros_num > l_n ? l_n : zeros_num);
                                                        /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
                                                        {
                                                                int version;
-                                                               int temp_l =
-                                                                   l_n;
-
-                                                               RFALSE
-                                                                   (ih_item_len
-                                                                    (B_N_PITEM_HEAD
-                                                                     (tbS0,
-                                                                      0)),
+                                                               int temp_l = l_n;
+
+                                                               RFALSE(ih_item_len(B_N_PITEM_HEAD(tbS0, 0)),
                                                                     "PAP-12106: item length must be 0");
-                                                               RFALSE
-                                                                   (comp_short_le_keys
-                                                                    (B_N_PKEY
-                                                                     (tbS0, 0),
-                                                                     B_N_PKEY
-                                                                     (tb->L[0],
-                                                                      n +
-                                                                      item_pos
-                                                                      -
-                                                                      ret_val)),
+                                                               RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY
+                                                                     (tb->L[0], n + item_pos - ret_val)),
                                                                     "PAP-12107: items must be of the same file");
                                                                if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) {
-                                                                       temp_l =
-                                                                           l_n
-                                                                           <<
-                                                                           (tb->
-                                                                            tb_sb->
-                                                                            s_blocksize_bits
-                                                                            -
-                                                                            UNFM_P_SHIFT);
+                                                                       temp_l = l_n << (tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT);
                                                                }
                                                                /* update key of first item in S0 */
-                                                               version =
-                                                                   ih_version
-                                                                   (B_N_PITEM_HEAD
-                                                                    (tbS0, 0));
-                                                               set_le_key_k_offset
-                                                                   (version,
-                                                                    B_N_PKEY
-                                                                    (tbS0, 0),
-                                                                    le_key_k_offset
-                                                                    (version,
-                                                                     B_N_PKEY
-                                                                     (tbS0,
-                                                                      0)) +
-                                                                    temp_l);
+                                                               version = ih_version(B_N_PITEM_HEAD(tbS0, 0));
+                                                               set_le_key_k_offset(version, B_N_PKEY(tbS0, 0),
+                                                                    le_key_k_offset(version,B_N_PKEY(tbS0, 0)) + temp_l);
                                                                /* update left delimiting key */
-                                                               set_le_key_k_offset
-                                                                   (version,
-                                                                    B_N_PDELIM_KEY
-                                                                    (tb->
-                                                                     CFL[0],
-                                                                     tb->
-                                                                     lkey[0]),
-                                                                    le_key_k_offset
-                                                                    (version,
-                                                                     B_N_PDELIM_KEY
-                                                                     (tb->
-                                                                      CFL[0],
-                                                                      tb->
-                                                                      lkey[0]))
-                                                                    + temp_l);
+                                                               set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]),
+                                                                    le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0])) + temp_l);
                                                        }
 
                                                        /* Calculate new body, position in item and insert_size[0] */
                                                        if (l_n > zeros_num) {
-                                                               body +=
-                                                                   (l_n -
-                                                                    zeros_num);
+                                                               body += (l_n - zeros_num);
                                                                zeros_num = 0;
                                                        } else
-                                                               zeros_num -=
-                                                                   l_n;
+                                                               zeros_num -= l_n;
                                                        pos_in_item = 0;
 
-                                                       RFALSE
-                                                           (comp_short_le_keys
-                                                            (B_N_PKEY(tbS0, 0),
-                                                             B_N_PKEY(tb->L[0],
-                                                                      B_NR_ITEMS
-                                                                      (tb->
-                                                                       L[0]) -
-                                                                      1))
-                                                            ||
-                                                            !op_is_left_mergeable
-                                                            (B_N_PKEY(tbS0, 0),
-                                                             tbS0->b_size)
-                                                            ||
-                                                            !op_is_left_mergeable
-                                                            (B_N_PDELIM_KEY
-                                                             (tb->CFL[0],
-                                                              tb->lkey[0]),
-                                                             tbS0->b_size),
+                                                       RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1))
+                                                            || !op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)
+                                                            || !op_is_left_mergeable(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), tbS0->b_size),
                                                             "PAP-12120: item must be merge-able with left neighboring item");
                                                } else {        /* only part of the appended item will be in L[0] */
 
                                                        /* Calculate position in item for append in S[0] */
-                                                       pos_in_item -=
-                                                           tb->lbytes;
+                                                       pos_in_item -= tb->lbytes;
 
-                                                       RFALSE(pos_in_item <= 0,
-                                                              "PAP-12125: no place for paste. pos_in_item=%d",
-                                                              pos_in_item);
+                                                       RFALSE(pos_in_item <= 0, "PAP-12125: no place for paste. pos_in_item=%d", pos_in_item);
 
                                                        /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
-                                                       leaf_shift_left(tb,
-                                                                       tb->
-                                                                       lnum[0],
-                                                                       tb->
-                                                                       lbytes);
+                                                       leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
                                                }
                                        }
                                } else {        /* appended item will be in L[0] in whole */
@@ -665,52 +495,30 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
 
                                        if (!item_pos && op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) {       /* if we paste into first item of S[0] and it is left mergable */
                                                /* then increment pos_in_item by the size of the last item in L[0] */
-                                               pasted =
-                                                   B_N_PITEM_HEAD(tb->L[0],
-                                                                  n - 1);
+                                               pasted = B_N_PITEM_HEAD(tb->L[0], n - 1);
                                                if (is_direntry_le_ih(pasted))
-                                                       pos_in_item +=
-                                                           ih_entry_count
-                                                           (pasted);
+                                                       pos_in_item += ih_entry_count(pasted);
                                                else
-                                                       pos_in_item +=
-                                                           ih_item_len(pasted);
+                                                       pos_in_item += ih_item_len(pasted);
                                        }
 
                                        /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
-                                       ret_val =
-                                           leaf_shift_left(tb, tb->lnum[0],
-                                                           tb->lbytes);
+                                       ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
                                        /* Append to body of item in L[0] */
                                        buffer_info_init_left(tb, &bi);
-                                       leaf_paste_in_buffer(&bi,
-                                                            n + item_pos -
-                                                            ret_val,
+                                       leaf_paste_in_buffer(&bi, n + item_pos - ret_val,
                                                             pos_in_item,
                                                             tb->insert_size[0],
                                                             body, zeros_num);
 
                                        /* if appended item is directory, paste entry */
-                                       pasted =
-                                           B_N_PITEM_HEAD(tb->L[0],
-                                                          n + item_pos -
-                                                          ret_val);
+                                       pasted = B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val);
                                        if (is_direntry_le_ih(pasted))
-                                               leaf_paste_entries(&bi,
-                                                                  n +
-                                                                  item_pos -
-                                                                  ret_val,
-                                                                  pos_in_item,
-                                                                  1,
-                                                                  (struct
-                                                                   reiserfs_de_head
-                                                                   *)body,
-                                                                  body +
-                                                                  DEH_SIZE,
-                                                                  tb->
-                                                                  insert_size
-                                                                  [0]
-                                                   );
+                                               leaf_paste_entries(&bi, n + item_pos - ret_val,
+                                                                  pos_in_item, 1,
+                                                                  (struct reiserfs_de_head *) body,
+                                                                  body + DEH_SIZE,
+                                                                  tb->insert_size[0]);
                                        /* if appended item is indirect item, put unformatted node into un list */
                                        if (is_indirect_le_ih(pasted))
                                                set_ih_free_space(pasted, 0);
@@ -722,13 +530,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                reiserfs_panic(tb->tb_sb, "PAP-12130",
                                               "lnum > 0: unexpected mode: "
                                               " %s(%d)",
-                                              (flag ==
-                                               M_DELETE) ? "DELETE" : ((flag ==
-                                                                        M_CUT)
-                                                                       ? "CUT"
-                                                                       :
-                                                                       "UNKNOWN"),
-                                              flag);
+                                              (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
                        }
                } else {
                        /* new item doesn't fall into L[0] */
@@ -748,14 +550,12 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                case M_INSERT:  /* insert item */
                        if (n - tb->rnum[0] < item_pos) {       /* new item or its part falls to R[0] */
                                if (item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) {      /* part of new item falls into R[0] */
-                                       loff_t old_key_comp, old_len,
-                                           r_zeros_number;
+                                       loff_t old_key_comp, old_len, r_zeros_number;
                                        const char *r_body;
                                        int version;
                                        loff_t offset;
 
-                                       leaf_shift_right(tb, tb->rnum[0] - 1,
-                                                        -1);
+                                       leaf_shift_right(tb, tb->rnum[0] - 1, -1);
 
                                        version = ih_version(ih);
                                        /* Remember key component and item length */
@@ -763,29 +563,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                        old_len = ih_item_len(ih);
 
                                        /* Calculate key component and item length to insert into R[0] */
-                                       offset =
-                                           le_ih_k_offset(ih) +
-                                           ((old_len -
-                                             tb->
-                                             rbytes) << (is_indirect_le_ih(ih)
-                                                         ? tb->tb_sb->
-                                                         s_blocksize_bits -
-                                                         UNFM_P_SHIFT : 0));
+                                       offset = le_ih_k_offset(ih) + ((old_len - tb->rbytes) << (is_indirect_le_ih(ih) ? tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT : 0));
                                        set_le_ih_k_offset(ih, offset);
                                        put_ih_item_len(ih, tb->rbytes);
                                        /* Insert part of the item into R[0] */
                                        buffer_info_init_right(tb, &bi);
                                        if ((old_len - tb->rbytes) > zeros_num) {
                                                r_zeros_number = 0;
-                                               r_body =
-                                                   body + (old_len -
-                                                           tb->rbytes) -
-                                                   zeros_num;
+                                               r_body = body + (old_len - tb->rbytes) - zeros_num;
                                        } else {
                                                r_body = body;
-                                               r_zeros_number =
-                                                   zeros_num - (old_len -
-                                                                tb->rbytes);
+                                               r_zeros_number = zeros_num - (old_len - tb->rbytes);
                                                zeros_num -= r_zeros_number;
                                        }
 
@@ -798,25 +586,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
 
                                        /* Calculate key component and item length to insert into S[0] */
                                        set_le_ih_k_offset(ih, old_key_comp);
-                                       put_ih_item_len(ih,
-                                                       old_len - tb->rbytes);
+                                       put_ih_item_len(ih, old_len - tb->rbytes);
 
                                        tb->insert_size[0] -= tb->rbytes;
 
                                } else {        /* whole new item falls into R[0] */
 
                                        /* Shift rnum[0]-1 items to R[0] */
-                                       ret_val =
-                                           leaf_shift_right(tb,
-                                                            tb->rnum[0] - 1,
-                                                            tb->rbytes);
+                                       ret_val = leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes);
                                        /* Insert new item into R[0] */
                                        buffer_info_init_right(tb, &bi);
-                                       leaf_insert_into_buf(&bi,
-                                                            item_pos - n +
-                                                            tb->rnum[0] - 1,
-                                                            ih, body,
-                                                            zeros_num);
+                                       leaf_insert_into_buf(&bi, item_pos - n + tb->rnum[0] - 1,
+                                                            ih, body, zeros_num);
 
                                        if (item_pos - n + tb->rnum[0] - 1 == 0) {
                                                replace_key(tb, tb->CFR[0],
@@ -841,200 +622,97 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
 
                                                RFALSE(zeros_num,
                                                       "PAP-12145: invalid parameter in case of a directory");
-                                               entry_count =
-                                                   I_ENTRY_COUNT(B_N_PITEM_HEAD
-                                                                 (tbS0,
-                                                                  item_pos));
+                                               entry_count = I_ENTRY_COUNT(B_N_PITEM_HEAD
+                                                                 (tbS0, item_pos));
                                                if (entry_count - tb->rbytes <
                                                    pos_in_item)
                                                        /* new directory entry falls into R[0] */
                                                {
                                                        int paste_entry_position;
 
-                                                       RFALSE(tb->rbytes - 1 >=
-                                                              entry_count
-                                                              || !tb->
-                                                              insert_size[0],
+                                                       RFALSE(tb->rbytes - 1 >= entry_count || !tb-> insert_size[0],
                                                               "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
-                                                              tb->rbytes,
-                                                              entry_count);
+                                                              tb->rbytes, entry_count);
                                                        /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
-                                                       leaf_shift_right(tb,
-                                                                        tb->
-                                                                        rnum
-                                                                        [0],
-                                                                        tb->
-                                                                        rbytes
-                                                                        - 1);
+                                                       leaf_shift_right(tb, tb->rnum[0], tb->rbytes - 1);
                                                        /* Paste given directory entry to directory item */
-                                                       paste_entry_position =
-                                                           pos_in_item -
-                                                           entry_count +
-                                                           tb->rbytes - 1;
+                                                       paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1;
                                                        buffer_info_init_right(tb, &bi);
-                                                       leaf_paste_in_buffer
-                                                           (&bi, 0,
-                                                            paste_entry_position,
-                                                            tb->insert_size[0],
-                                                            body, zeros_num);
+                                                       leaf_paste_in_buffer(&bi, 0, paste_entry_position, tb->insert_size[0], body, zeros_num);
                                                        /* paste entry */
-                                                       leaf_paste_entries(&bi,
-                                                                          0,
-                                                                          paste_entry_position,
-                                                                          1,
-                                                                          (struct
-                                                                           reiserfs_de_head
-                                                                           *)
-                                                                          body,
-                                                                          body
-                                                                          +
-                                                                          DEH_SIZE,
-                                                                          tb->
-                                                                          insert_size
-                                                                          [0]
-                                                           );
-
-                                                       if (paste_entry_position
-                                                           == 0) {
+                                                       leaf_paste_entries(&bi, 0, paste_entry_position, 1,
+                                                                          (struct reiserfs_de_head *) body,
+                                                                          body + DEH_SIZE, tb->insert_size[0]);
+
+                                                       if (paste_entry_position == 0) {
                                                                /* change delimiting keys */
-                                                               replace_key(tb,
-                                                                           tb->
-                                                                           CFR
-                                                                           [0],
-                                                                           tb->
-                                                                           rkey
-                                                                           [0],
-                                                                           tb->
-                                                                           R
-                                                                           [0],
-                                                                           0);
+                                                               replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0],0);
                                                        }
 
                                                        tb->insert_size[0] = 0;
                                                        pos_in_item++;
                                                } else {        /* new directory entry doesn't fall into R[0] */
 
-                                                       leaf_shift_right(tb,
-                                                                        tb->
-                                                                        rnum
-                                                                        [0],
-                                                                        tb->
-                                                                        rbytes);
+                                                       leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
                                                }
                                        } else {        /* regular object */
 
-                                               int n_shift, n_rem,
-                                                   r_zeros_number;
+                                               int n_shift, n_rem, r_zeros_number;
                                                const char *r_body;
 
                                                /* Calculate number of bytes which must be shifted from appended item */
-                                               if ((n_shift =
-                                                    tb->rbytes -
-                                                    tb->insert_size[0]) < 0)
+                                               if ((n_shift = tb->rbytes - tb->insert_size[0]) < 0)
                                                        n_shift = 0;
 
-                                               RFALSE(pos_in_item !=
-                                                      ih_item_len
-                                                      (B_N_PITEM_HEAD
-                                                       (tbS0, item_pos)),
+                                               RFALSE(pos_in_item != ih_item_len
+                                                      (B_N_PITEM_HEAD(tbS0, item_pos)),
                                                       "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
-                                                      pos_in_item,
-                                                      ih_item_len
-                                                      (B_N_PITEM_HEAD
-                                                       (tbS0, item_pos)));
-
-                                               leaf_shift_right(tb,
-                                                                tb->rnum[0],
-                                                                n_shift);
+                                                      pos_in_item, ih_item_len
+                                                      (B_N_PITEM_HEAD(tbS0, item_pos)));
+
+                                               leaf_shift_right(tb, tb->rnum[0], n_shift);
                                                /* Calculate number of bytes which must remain in body after appending to R[0] */
-                                               if ((n_rem =
-                                                    tb->insert_size[0] -
-                                                    tb->rbytes) < 0)
+                                               if ((n_rem = tb->insert_size[0] - tb->rbytes) < 0)
                                                        n_rem = 0;
 
                                                {
                                                        int version;
-                                                       unsigned long temp_rem =
-                                                           n_rem;
-
-                                                       version =
-                                                           ih_version
-                                                           (B_N_PITEM_HEAD
-                                                            (tb->R[0], 0));
-                                                       if (is_indirect_le_key
-                                                           (version,
-                                                            B_N_PKEY(tb->R[0],
-                                                                     0))) {
-                                                               temp_rem =
-                                                                   n_rem <<
-                                                                   (tb->tb_sb->
-                                                                    s_blocksize_bits
-                                                                    -
-                                                                    UNFM_P_SHIFT);
+                                                       unsigned long temp_rem = n_rem;
+
+                                                       version = ih_version(B_N_PITEM_HEAD(tb->R[0], 0));
+                                                       if (is_indirect_le_key(version, B_N_PKEY(tb->R[0], 0))) {
+                                                               temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT);
                                                        }
-                                                       set_le_key_k_offset
-                                                           (version,
-                                                            B_N_PKEY(tb->R[0],
-                                                                     0),
-                                                            le_key_k_offset
-                                                            (version,
-                                                             B_N_PKEY(tb->R[0],
-                                                                      0)) +
-                                                            temp_rem);
-                                                       set_le_key_k_offset
-                                                           (version,
-                                                            B_N_PDELIM_KEY(tb->
-                                                                           CFR
-                                                                           [0],
-                                                                           tb->
-                                                                           rkey
-                                                                           [0]),
-                                                            le_key_k_offset
-                                                            (version,
-                                                             B_N_PDELIM_KEY
-                                                             (tb->CFR[0],
-                                                              tb->rkey[0])) +
-                                                            temp_rem);
+                                                       set_le_key_k_offset(version, B_N_PKEY(tb->R[0], 0),
+                                                            le_key_k_offset(version, B_N_PKEY(tb->R[0], 0)) + temp_rem);
+                                                       set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]),
+                                                            le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0])) + temp_rem);
                                                }
 /*               k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
                  k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
-                                               do_balance_mark_internal_dirty
-                                                   (tb, tb->CFR[0], 0);
+                                               do_balance_mark_internal_dirty(tb, tb->CFR[0], 0);
 
                                                /* Append part of body into R[0] */
                                                buffer_info_init_right(tb, &bi);
                                                if (n_rem > zeros_num) {
                                                        r_zeros_number = 0;
-                                                       r_body =
-                                                           body + n_rem -
-                                                           zeros_num;
+                                                       r_body = body + n_rem - zeros_num;
                                                } else {
                                                        r_body = body;
-                                                       r_zeros_number =
-                                                           zeros_num - n_rem;
-                                                       zeros_num -=
-                                                           r_zeros_number;
+                                                       r_zeros_number = zeros_num - n_rem;
+                                                       zeros_num -= r_zeros_number;
                                                }
 
-                                               leaf_paste_in_buffer(&bi, 0,
-                                                                    n_shift,
-                                                                    tb->
-                                                                    insert_size
-                                                                    [0] -
-                                                                    n_rem,
-                                                                    r_body,
-                                                                    r_zeros_number);
-
-                                               if (is_indirect_le_ih
-                                                   (B_N_PITEM_HEAD
-                                                    (tb->R[0], 0))) {
+                                               leaf_paste_in_buffer(&bi, 0, n_shift,
+                                                                    tb->insert_size[0] - n_rem,
+                                                                    r_body, r_zeros_number);
+
+                                               if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->R[0], 0))) {
 #if 0
                                                        RFALSE(n_rem,
                                                               "PAP-12160: paste more than one unformatted node pointer");
 #endif
-                                                       set_ih_free_space
-                                                           (B_N_PITEM_HEAD
-                                                            (tb->R[0], 0), 0);
+                                                       set_ih_free_space(B_N_PITEM_HEAD(tb->R[0], 0), 0);
                                                }
                                                tb->insert_size[0] = n_rem;
                                                if (!n_rem)
@@ -1044,58 +722,28 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
 
                                        struct item_head *pasted;
 
-                                       ret_val =
-                                           leaf_shift_right(tb, tb->rnum[0],
-                                                            tb->rbytes);
+                                       ret_val = leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
                                        /* append item in R[0] */
                                        if (pos_in_item >= 0) {
                                                buffer_info_init_right(tb, &bi);
-                                               leaf_paste_in_buffer(&bi,
-                                                                    item_pos -
-                                                                    n +
-                                                                    tb->
-                                                                    rnum[0],
-                                                                    pos_in_item,
-                                                                    tb->
-                                                                    insert_size
-                                                                    [0], body,
-                                                                    zeros_num);
+                                               leaf_paste_in_buffer(&bi, item_pos - n + tb->rnum[0], pos_in_item,
+                                                                    tb->insert_size[0], body, zeros_num);
                                        }
 
                                        /* paste new entry, if item is directory item */
-                                       pasted =
-                                           B_N_PITEM_HEAD(tb->R[0],
-                                                          item_pos - n +
-                                                          tb->rnum[0]);
-                                       if (is_direntry_le_ih(pasted)
-                                           && pos_in_item >= 0) {
-                                               leaf_paste_entries(&bi,
-                                                                  item_pos -
-                                                                  n +
-                                                                  tb->rnum[0],
-                                                                  pos_in_item,
-                                                                  1,
-                                                                  (struct
-                                                                   reiserfs_de_head
-                                                                   *)body,
-                                                                  body +
-                                                                  DEH_SIZE,
-                                                                  tb->
-                                                                  insert_size
-                                                                  [0]
-                                                   );
+                                       pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]);
+                                       if (is_direntry_le_ih(pasted) && pos_in_item >= 0) {
+                                               leaf_paste_entries(&bi, item_pos - n + tb->rnum[0],
+                                                                  pos_in_item, 1,
+                                                                  (struct reiserfs_de_head *) body,
+                                                                  body + DEH_SIZE, tb->insert_size[0]);
                                                if (!pos_in_item) {
 
-                                                       RFALSE(item_pos - n +
-                                                              tb->rnum[0],
+                                                       RFALSE(item_pos - n + tb->rnum[0],
                                                               "PAP-12165: directory item must be first item of node when pasting is in 0th position");
 
                                                        /* update delimiting keys */
-                                                       replace_key(tb,
-                                                                   tb->CFR[0],
-                                                                   tb->rkey[0],
-                                                                   tb->R[0],
-                                                                   0);
+                                                       replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
                                                }
                                        }
 
@@ -1111,22 +759,16 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                default:        /* cases d and t */
                        reiserfs_panic(tb->tb_sb, "PAP-12175",
                                       "rnum > 0: unexpected mode: %s(%d)",
-                                      (flag ==
-                                       M_DELETE) ? "DELETE" : ((flag ==
-                                                                M_CUT) ? "CUT"
-                                                               : "UNKNOWN"),
-                                      flag);
+                                      (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
                }
 
        }
 
        /* tb->rnum[0] > 0 */
        RFALSE(tb->blknum[0] > 3,
-              "PAP-12180: blknum can not be %d. It must be <= 3",
-              tb->blknum[0]);
+              "PAP-12180: blknum can not be %d. It must be <= 3", tb->blknum[0]);
        RFALSE(tb->blknum[0] < 0,
-              "PAP-12185: blknum can not be %d. It must be >= 0",
-              tb->blknum[0]);
+              "PAP-12185: blknum can not be %d. It must be >= 0", tb->blknum[0]);
 
        /* if while adding to a node we discover that it is possible to split
           it in two, and merge the left part into the left neighbor and the
@@ -1177,8 +819,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
 
                        if (n - snum[i] < item_pos) {   /* new item or it's part falls to first new node S_new[i] */
                                if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) {   /* part of new item falls into S_new[i] */
-                                       int old_key_comp, old_len,
-                                           r_zeros_number;
+                                       int old_key_comp, old_len, r_zeros_number;
                                        const char *r_body;
                                        int version;
 
@@ -1192,15 +833,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                        old_len = ih_item_len(ih);
 
                                        /* Calculate key component and item length to insert into S_new[i] */
-                                       set_le_ih_k_offset(ih,
-                                                          le_ih_k_offset(ih) +
-                                                          ((old_len -
-                                                            sbytes[i]) <<
-                                                           (is_indirect_le_ih
-                                                            (ih) ? tb->tb_sb->
-                                                            s_blocksize_bits -
-                                                            UNFM_P_SHIFT :
-                                                            0)));
+                                       set_le_ih_k_offset(ih, le_ih_k_offset(ih) +
+                                                          ((old_len - sbytes[i]) << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0)));
 
                                        put_ih_item_len(ih, sbytes[i]);
 
@@ -1209,39 +843,29 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
 
                                        if ((old_len - sbytes[i]) > zeros_num) {
                                                r_zeros_number = 0;
-                                               r_body =
-                                                   body + (old_len -
-                                                           sbytes[i]) -
-                                                   zeros_num;
+                                               r_body = body + (old_len - sbytes[i]) - zeros_num;
                                        } else {
                                                r_body = body;
-                                               r_zeros_number =
-                                                   zeros_num - (old_len -
-                                                                sbytes[i]);
+                                               r_zeros_number = zeros_num - (old_len - sbytes[i]);
                                                zeros_num -= r_zeros_number;
                                        }
 
-                                       leaf_insert_into_buf(&bi, 0, ih, r_body,
-                                                            r_zeros_number);
+                                       leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeros_number);
 
                                        /* Calculate key component and item length to insert into S[i] */
                                        set_le_ih_k_offset(ih, old_key_comp);
-                                       put_ih_item_len(ih,
-                                                       old_len - sbytes[i]);
+                                       put_ih_item_len(ih, old_len - sbytes[i]);
                                        tb->insert_size[0] -= sbytes[i];
                                } else {        /* whole new item falls into S_new[i] */
 
                                        /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
                                        leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
-                                                       snum[i] - 1, sbytes[i],
-                                                       S_new[i]);
+                                                       snum[i] - 1, sbytes[i], S_new[i]);
 
                                        /* Insert new item into S_new[i] */
                                        buffer_info_init_bh(tb, &bi, S_new[i]);
-                                       leaf_insert_into_buf(&bi,
-                                                            item_pos - n +
-                                                            snum[i] - 1, ih,
-                                                            body, zeros_num);
+                                       leaf_insert_into_buf(&bi, item_pos - n + snum[i] - 1,
+                                                            ih, body, zeros_num);
 
                                        zeros_num = tb->insert_size[0] = 0;
                                }
@@ -1268,150 +892,73 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,  /* item h
 
                                                int entry_count;
 
-                                               entry_count =
-                                                   ih_entry_count(aux_ih);
+                                               entry_count = ih_entry_count(aux_ih);
 
-                                               if (entry_count - sbytes[i] <
-                                                   pos_in_item
-                                                   && pos_in_item <=
-                                                   entry_count) {
+                                               if (entry_count - sbytes[i] < pos_in_item && pos_in_item <= entry_count) {
                                                        /* new directory entry falls into S_new[i] */
 
-                                                       RFALSE(!tb->
-                                                              insert_size[0],
-                                                              "PAP-12215: insert_size is already 0");
-                                                       RFALSE(sbytes[i] - 1 >=
-                                                              entry_count,
+                                                       RFALSE(!tb->insert_size[0], "PAP-12215: insert_size is already 0");
+                                                       RFALSE(sbytes[i] - 1 >= entry_count,
                                                               "PAP-12220: there are no so much entries (%d), only %d",
-                                                              sbytes[i] - 1,
-                                                              entry_count);
+                                                              sbytes[i] - 1, entry_count);
 
                                                        /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
-                                                       leaf_move_items
-                                                           (LEAF_FROM_S_TO_SNEW,
-                                                            tb, snum[i],
-                                                            sbytes[i] - 1,
-                                                            S_new[i]);
+                                                       leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i] - 1, S_new[i]);
                                                        /* Paste given directory entry to directory item */
                                                        buffer_info_init_bh(tb, &bi, S_new[i]);
-                                                       leaf_paste_in_buffer
-                                                           (&bi, 0,
-                                                            pos_in_item -
-                                                            entry_count +
-                                                            sbytes[i] - 1,
-                                                            tb->insert_size[0],
-                                                            body, zeros_num);
+                                                       leaf_paste_in_buffer(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1,
+                                                            tb->insert_size[0], body, zeros_num);
                                                        /* paste new directory entry */
-                                                       leaf_paste_entries(&bi,
-                                                                          0,
-                                                                          pos_in_item
-                                                                          -
-                                                                          entry_count
-                                                                          +
-                                                                          sbytes
-                                                                          [i] -
-                                                                          1, 1,
-                                                                          (struct
-                                                                           reiserfs_de_head
-                                                                           *)
-                                                                          body,
-                                                                          body
-                                                                          +
-                                                                          DEH_SIZE,
-                                                                          tb->
-                                                                          insert_size
-                                                                          [0]
-                                                           );
+                                                       leaf_paste_entries(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, 1,
+                                                                          (struct reiserfs_de_head *) body,
+                                                                          body + DEH_SIZE, tb->insert_size[0]);
                                                        tb->insert_size[0] = 0;
                                                        pos_in_item++;
                                                } else {        /* new directory entry doesn't fall into S_new[i] */
-                                                       leaf_move_items
-                                                           (LEAF_FROM_S_TO_SNEW,
-                                                            tb, snum[i],
-                                                            sbytes[i],
-                                                            S_new[i]);
+                                                       leaf_move_items(LEAF_FROM_S_TO_SNEW,tb, snum[i], sbytes[i], S_new[i]);
                                                }
                                        } else {        /* regular object */
 
-                                               int n_shift, n_rem,
-                                                   r_zeros_number;
+                                               int n_shift, n_rem, r_zeros_number;
                                                const char *r_body;
 
-                                               RFALSE(pos_in_item !=
-                                                      ih_item_len
-                                                      (B_N_PITEM_HEAD
-                                                       (tbS0, item_pos))
-                                                      || tb->insert_size[0] <=
-                                                      0,
+                                               RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)) || tb->insert_size[0] <= 0,
                                                       "PAP-12225: item too short or insert_size <= 0");
 
                                                /* Calculate number of bytes which must be shifted from appended item */
-                                               n_shift =
-                                                   sbytes[i] -
-                                                   tb->insert_size[0];
+                                               n_shift = sbytes[i] - tb->insert_size[0];
                                                if (n_shift < 0)
                                                        n_shift = 0;
-                                               leaf_move_items
-                                                   (LEAF_FROM_S_TO_SNEW, tb,
-                                                    snum[i], n_shift,
-                                                    S_new[i]);
+                                               leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]);
 
                                                /* Calculate number of bytes which must remain in body after append to S_new[i] */
-                                               n_rem =
-                                                   tb->insert_size[0] -
-                                                   sbytes[i];
+                                               n_rem = tb->insert_size[0] - sbytes[i];
                                                if (n_rem < 0)
                                                        n_rem = 0;
                                                /* Append part of body into S_new[0] */
                                                buffer_info_init_bh(tb, &bi, S_new[i]);
                                                if (n_rem > zeros_num) {
                                                        r_zeros_number = 0;
-                                                       r_body =
-                                                           body + n_rem -
-                                                           zeros_num;
+                                                       r_body = body + n_rem - zeros_num;
                                                } else {
                                                        r_body = body;
-                                                       r_zeros_number =
-                                                           zeros_num - n_rem;
-                                                       zeros_num -=
-                                                           r_zeros_number;
+                                                       r_zeros_number = zeros_num - n_rem;
+                                                       zeros_num -= r_zeros_number;
                                                }
 
-                                               leaf_paste_in_buffer(&bi, 0,
-                                                                    n_shift,
-                                                                    tb->
-                                                                    insert_size
-                                                                    [0] -
-                                                                    n_rem,
-                                                                    r_body,
-                                                                    r_zeros_number);
+                                               leaf_paste_in_buffer(&bi, 0, n_shift,
+                                                                    tb->insert_size[0] - n_rem,
+                                                                    r_body, r_zeros_number);
                                                {
                                                        struct item_head *tmp;
 
-                                                       tmp =
-                                                           B_N_PITEM_HEAD(S_new
-                                                                          [i],
-                                                                          0);
+                                                       tmp = B_N_PITEM_HEAD(S_new[i], 0);
                                                        if (is_indirect_le_ih
                                                            (tmp)) {
-                                                               set_ih_free_space
-                                                                   (tmp, 0);
-                                                               set_le_ih_k_offset
-                                                                   (tmp,
-                                                                    le_ih_k_offset
-                                                                    (tmp) +
-                                                                    (n_rem <<
-                                                                     (tb->
-                                                                      tb_sb->
-                                                                      s_blocksize_bits
-                                                                      -
-                                                                      UNFM_P_SHIFT)));
+                                                               set_ih_free_space(tmp, 0);
+                                                               set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT)));
                                                        } else {
-                                                               set_le_ih_k_offset
-                                                                   (tmp,
-                                                                    le_ih_k_offset
-                                                                    (tmp) +
-                                                                    n_rem);
+                                                               set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + n_rem);
                                                        }
                                                }
 
@@ -1426,8 +973,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                        struct item_head *pasted;
 
 #ifdef CONFIG_REISERFS_CHECK
-                                       struct item_head *ih_check =
-                                           B_N_PITEM_HEAD(tbS0, item_pos);
+                                       struct item_head *ih_check = B_N_PITEM_HEAD(tbS0, item_pos);
 
                                        if (!is_direntry_le_ih(ih_check)
                                            && (pos_in_item != ih_item_len(ih_check)
@@ -1439,8 +985,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,     /* item h
                                                             "to ih_item_len");
 #endif                         /* CONFIG_REISERFS_CHECK */
 
-                                       leaf_mi =
-                                           leaf_move_items(LEAF_FROM_S_TO_SNEW,
+                                       leaf_mi = leaf_move_items(LEAF_FROM_S_TO_SNEW,
                                                            tb, snum[i],
                                                            sbytes[i],
                                                            S_new[i]);
@@ -1452,30 +997,19 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                        /* paste into item */
                                        buffer_info_init_bh(tb, &bi, S_new[i]);
                                        leaf_paste_in_buffer(&bi,
-                                                            item_pos - n +
-                                                            snum[i],
+                                                            item_pos - n + snum[i],
                                                             pos_in_item,
                                                             tb->insert_size[0],
                                                             body, zeros_num);
 
-                                       pasted =
-                                           B_N_PITEM_HEAD(S_new[i],
-                                                          item_pos - n +
-                                                          snum[i]);
+                                       pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]);
                                        if (is_direntry_le_ih(pasted)) {
                                                leaf_paste_entries(&bi,
-                                                                  item_pos -
-                                                                  n + snum[i],
-                                                                  pos_in_item,
-                                                                  1,
-                                                                  (struct
-                                                                   reiserfs_de_head
-                                                                   *)body,
-                                                                  body +
-                                                                  DEH_SIZE,
-                                                                  tb->
-                                                                  insert_size
-                                                                  [0]
+                                                                  item_pos - n + snum[i],
+                                                                  pos_in_item, 1,
+                                                                  (struct reiserfs_de_head *)body,
+                                                                  body + DEH_SIZE,
+                                                                  tb->insert_size[0]
                                                    );
                                        }
 
@@ -1495,11 +1029,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                default:        /* cases d and t */
                        reiserfs_panic(tb->tb_sb, "PAP-12245",
                                       "blknum > 2: unexpected mode: %s(%d)",
-                                      (flag ==
-                                       M_DELETE) ? "DELETE" : ((flag ==
-                                                                M_CUT) ? "CUT"
-                                                               : "UNKNOWN"),
-                                      flag);
+                                      (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
                }
 
                memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE);
@@ -1524,9 +1054,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                        /* If we insert the first key change the delimiting key */
                        if (item_pos == 0) {
                                if (tb->CFL[0]) /* can be 0 in reiserfsck */
-                                       replace_key(tb, tb->CFL[0], tb->lkey[0],
-                                                   tbS0, 0);
-
+                                       replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
                        }
                        break;
 
@@ -1536,53 +1064,27 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,  /* item h
                                pasted = B_N_PITEM_HEAD(tbS0, item_pos);
                                /* when directory, may be new entry already pasted */
                                if (is_direntry_le_ih(pasted)) {
-                                       if (pos_in_item >= 0 &&
-                                           pos_in_item <=
-                                           ih_entry_count(pasted)) {
+                                       if (pos_in_item >= 0 && pos_in_item <= ih_entry_count(pasted)) {
 
                                                RFALSE(!tb->insert_size[0],
                                                       "PAP-12260: insert_size is 0 already");
 
                                                /* prepare space */
                                                buffer_info_init_tbS0(tb, &bi);
-                                               leaf_paste_in_buffer(&bi,
-                                                                    item_pos,
-                                                                    pos_in_item,
-                                                                    tb->
-                                                                    insert_size
-                                                                    [0], body,
+                                               leaf_paste_in_buffer(&bi, item_pos, pos_in_item,
+                                                                    tb->insert_size[0], body,
                                                                     zeros_num);
 
                                                /* paste entry */
-                                               leaf_paste_entries(&bi,
-                                                                  item_pos,
-                                                                  pos_in_item,
-                                                                  1,
-                                                                  (struct
-                                                                   reiserfs_de_head
-                                                                   *)body,
-                                                                  body +
-                                                                  DEH_SIZE,
-                                                                  tb->
-                                                                  insert_size
-                                                                  [0]
-                                                   );
+                                               leaf_paste_entries(&bi, item_pos, pos_in_item, 1,
+                                                                  (struct reiserfs_de_head *)body,
+                                                                  body + DEH_SIZE,
+                                                                  tb->insert_size[0]);
                                                if (!item_pos && !pos_in_item) {
-                                                       RFALSE(!tb->CFL[0]
-                                                              || !tb->L[0],
+                                                       RFALSE(!tb->CFL[0] || !tb->L[0],
                                                               "PAP-12270: CFL[0]/L[0] must be specified");
-                                                       if (tb->CFL[0]) {
-                                                               replace_key(tb,
-                                                                           tb->
-                                                                           CFL
-                                                                           [0],
-                                                                           tb->
-                                                                           lkey
-                                                                           [0],
-                                                                           tbS0,
-                                                                           0);
-
-                                                       }
+                                                       if (tb->CFL[0])
+                                                               replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
                                                }
                                                tb->insert_size[0] = 0;
                                        }
@@ -1593,13 +1095,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,   /* item h
                                                       "PAP-12275: insert size must not be %d",
                                                       tb->insert_size[0]);
                                                buffer_info_init_tbS0(tb, &bi);
-                                               leaf_paste_in_buffer(&bi,
-                                                                    item_pos,
-                                                                    pos_in_item,
-                                                                    tb->
-                                                                    insert_size
-                                                                    [0], body,
-                                                                    zeros_num);
+                                               leaf_paste_in_buffer(&bi, item_pos, pos_in_item,
+                                                                    tb->insert_size[0], body, zeros_num);
 
                                                if (is_indirect_le_ih(pasted)) {
 #if 0
@@ -1611,8 +1108,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                                               tb->
                                                               insert_size[0]);
 #endif
-                                                       set_ih_free_space
-                                                           (pasted, 0);
+                                                       set_ih_free_space(pasted, 0);
                                                }
                                                tb->insert_size[0] = 0;
                                        }
@@ -1620,8 +1116,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih,    /* item h
                                        else {
                                                if (tb->insert_size[0]) {
                                                        print_cur_tb("12285");
-                                                       reiserfs_panic(tb->
-                                                                      tb_sb,
+                                                       reiserfs_panic(tb->tb_sb,
                                                            "PAP-12285",
                                                            "insert_size "
                                                            "must be 0 "
index e8ba024a055b5a55d6320ba38edf1338c7d90e65..b28d1dd10e8b70194a604a1fca654237edd817be 100644 (file)
--- a/fs/sync.c
+++ b/fs/sync.c
  * wait == 1 case since in that case write_inode() functions do
  * sync_dirty_buffer() and thus effectively write one block at a time.
  */
-static int __sync_filesystem(struct super_block *sb, int wait,
-                            unsigned long start)
+static int __sync_filesystem(struct super_block *sb, int wait)
 {
        if (wait)
-               sync_inodes_sb(sb, start);
+               sync_inodes_sb(sb);
        else
                writeback_inodes_sb(sb, WB_REASON_SYNC);
 
@@ -48,7 +47,6 @@ static int __sync_filesystem(struct super_block *sb, int wait,
 int sync_filesystem(struct super_block *sb)
 {
        int ret;
-       unsigned long start = jiffies;
 
        /*
         * We need to be protected against the filesystem going from
@@ -62,17 +60,17 @@ int sync_filesystem(struct super_block *sb)
        if (sb->s_flags & MS_RDONLY)
                return 0;
 
-       ret = __sync_filesystem(sb, 0, start);
+       ret = __sync_filesystem(sb, 0);
        if (ret < 0)
                return ret;
-       return __sync_filesystem(sb, 1, start);
+       return __sync_filesystem(sb, 1);
 }
 EXPORT_SYMBOL_GPL(sync_filesystem);
 
 static void sync_inodes_one_sb(struct super_block *sb, void *arg)
 {
        if (!(sb->s_flags & MS_RDONLY))
-               sync_inodes_sb(sb, *((unsigned long *)arg));
+               sync_inodes_sb(sb);
 }
 
 static void sync_fs_one_sb(struct super_block *sb, void *arg)
@@ -104,10 +102,9 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg)
 SYSCALL_DEFINE0(sync)
 {
        int nowait = 0, wait = 1;
-       unsigned long start = jiffies;
 
        wakeup_flusher_threads(0, WB_REASON_SYNC);
-       iterate_supers(sync_inodes_one_sb, &start);
+       iterate_supers(sync_inodes_one_sb, NULL);
        iterate_supers(sync_fs_one_sb, &nowait);
        iterate_supers(sync_fs_one_sb, &wait);
        iterate_bdevs(fdatawrite_one_bdev, NULL);
index 6211230814fd89dcc1a0a4b0acbabe000428e5b8..3eaf5c6622eb4fafc82137bc501aac803d7952f4 100644 (file)
@@ -27,6 +27,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 {
        struct dentry *root;
        void *ns;
+       bool new_sb;
 
        if (!(flags & MS_KERNMOUNT)) {
                if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
@@ -37,8 +38,8 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
        }
 
        ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
-       root = kernfs_mount_ns(fs_type, flags, sysfs_root, ns);
-       if (IS_ERR(root))
+       root = kernfs_mount_ns(fs_type, flags, sysfs_root, &new_sb, ns);
+       if (IS_ERR(root) || !new_sb)
                kobj_ns_drop(KOBJ_NS_TYPE_NET, ns);
        return root;
 }
index c02a27a19c6df0984eb3ea13fc5a06c5e251aaa5..1037637957c7670e1a66e6bf1a8e51c80fbcc49d 100644 (file)
@@ -144,6 +144,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        size_t count = iocb->ki_nbytes;
        struct udf_inode_info *iinfo = UDF_I(inode);
 
+       mutex_lock(&inode->i_mutex);
        down_write(&iinfo->i_data_sem);
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
                if (file->f_flags & O_APPEND)
@@ -156,6 +157,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                                                pos + count)) {
                        err = udf_expand_file_adinicb(inode);
                        if (err) {
+                               mutex_unlock(&inode->i_mutex);
                                udf_debug("udf_expand_adinicb: err=%d\n", err);
                                return err;
                        }
@@ -169,9 +171,17 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        } else
                up_write(&iinfo->i_data_sem);
 
-       retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
-       if (retval > 0)
+       retval = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
+       mutex_unlock(&inode->i_mutex);
+
+       if (retval > 0) {
+               ssize_t err;
+
                mark_inode_dirty(inode);
+               err = generic_write_sync(file, iocb->ki_pos - retval, retval);
+               if (err < 0)
+                       retval = err;
+       }
 
        return retval;
 }
index 062b7925bca04c02949919ac37aab790d7b982a2..982ce05c87ed61c86dfc9200731a28f2db44b70b 100644 (file)
@@ -265,6 +265,7 @@ int udf_expand_file_adinicb(struct inode *inode)
                .nr_to_write = 1,
        };
 
+       WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
        if (!iinfo->i_lenAlloc) {
                if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
                        iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
index f35d5c953ff953dcde133c4b55568d1920db3589..9ddfb8190ca1cd56b5f1cd2247e9f54925fce68f 100644 (file)
@@ -705,7 +705,6 @@ xfs_setattr_size(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct inode            *inode = VFS_I(ip);
-       int                     mask = iattr->ia_valid;
        xfs_off_t               oldsize, newsize;
        struct xfs_trans        *tp;
        int                     error;
@@ -726,8 +725,8 @@ xfs_setattr_size(
 
        ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
        ASSERT(S_ISREG(ip->i_d.di_mode));
-       ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
-                       ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
+       ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
+               ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
 
        oldsize = inode->i_size;
        newsize = iattr->ia_size;
@@ -736,7 +735,7 @@ xfs_setattr_size(
         * Short circuit the truncate case for zero length files.
         */
        if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) {
-               if (!(mask & (ATTR_CTIME|ATTR_MTIME)))
+               if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME)))
                        return 0;
 
                /*
@@ -824,10 +823,11 @@ xfs_setattr_size(
         * these flags set.  For all other operations the VFS set these flags
         * explicitly if it wants a timestamp update.
         */
-       if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
+       if (newsize != oldsize &&
+           !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) {
                iattr->ia_ctime = iattr->ia_mtime =
                        current_fs_time(inode->i_sb);
-               mask |= ATTR_CTIME | ATTR_MTIME;
+               iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME;
        }
 
        /*
@@ -863,9 +863,9 @@ xfs_setattr_size(
                xfs_inode_clear_eofblocks_tag(ip);
        }
 
-       if (mask & ATTR_MODE)
+       if (iattr->ia_valid & ATTR_MODE)
                xfs_setattr_mode(ip, iattr);
-       if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
+       if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
                xfs_setattr_time(ip, iattr);
 
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
index cdebd832c3dba1fcd937869d1cedcebe09113c25..4ef6fdbced78b7e99680f9e4e8afbb502a7bce92 100644 (file)
@@ -205,16 +205,25 @@ xlog_cil_insert_format_items(
                /*
                 * We 64-bit align the length of each iovec so that the start
                 * of the next one is naturally aligned.  We'll need to
-                * account for that slack space here.
+                * account for that slack space here. Then round nbytes up
+                * to 64-bit alignment so that the initial buffer alignment is
+                * easy to calculate and verify.
                 */
                nbytes += niovecs * sizeof(uint64_t);
+               nbytes = round_up(nbytes, sizeof(uint64_t));
 
                /* grab the old item if it exists for reservation accounting */
                old_lv = lip->li_lv;
 
-               /* calc buffer size */
-               buf_size = sizeof(struct xfs_log_vec) + nbytes +
-                               niovecs * sizeof(struct xfs_log_iovec);
+               /*
+                * The data buffer needs to start 64-bit aligned, so round up
+                * that space to ensure we can align it appropriately and not
+                * overrun the buffer.
+                */
+               buf_size = nbytes +
+                          round_up((sizeof(struct xfs_log_vec) +
+                                    niovecs * sizeof(struct xfs_log_iovec)),
+                                   sizeof(uint64_t));
 
                /* compare to existing item size */
                if (lip->li_lv && buf_size <= lip->li_lv->lv_size) {
@@ -251,6 +260,8 @@ xlog_cil_insert_format_items(
                /* The allocated data region lies beyond the iovec region */
                lv->lv_buf_len = 0;
                lv->lv_buf = (char *)lv + buf_size - nbytes;
+               ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t)));
+
                lip->li_ops->iop_format(lip, lv);
 insert:
                ASSERT(lv->lv_buf_len <= nbytes);
index 02df7b408a2623d6a32e7a2bc8285be9348ca646..f96c05669a9e06298980bd14e377e34536d0119b 100644 (file)
@@ -282,22 +282,29 @@ xfs_readsb(
        struct xfs_sb   *sbp = &mp->m_sb;
        int             error;
        int             loud = !(flags & XFS_MFSI_QUIET);
+       const struct xfs_buf_ops *buf_ops;
 
        ASSERT(mp->m_sb_bp == NULL);
        ASSERT(mp->m_ddev_targp != NULL);
 
+       /*
+        * For the initial read, we must guess at the sector
+        * size based on the block device.  It's enough to
+        * get the sb_sectsize out of the superblock and
+        * then reread with the proper length.
+        * We don't verify it yet, because it may not be complete.
+        */
+       sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
+       buf_ops = NULL;
+
        /*
         * Allocate a (locked) buffer to hold the superblock.
         * This will be kept around at all times to optimize
         * access to the superblock.
         */
-       sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
-
 reread:
        bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
-                                  BTOBB(sector_size), 0,
-                                  loud ? &xfs_sb_buf_ops
-                                       : &xfs_sb_quiet_buf_ops);
+                                  BTOBB(sector_size), 0, buf_ops);
        if (!bp) {
                if (loud)
                        xfs_warn(mp, "SB buffer read failed");
@@ -328,12 +335,13 @@ reread:
        }
 
        /*
-        * If device sector size is smaller than the superblock size,
-        * re-read the superblock so the buffer is correctly sized.
+        * Re-read the superblock so the buffer is correctly sized,
+        * and properly verified.
         */
-       if (sector_size < sbp->sb_sectsize) {
+       if (buf_ops == NULL) {
                xfs_buf_relse(bp);
                sector_size = sbp->sb_sectsize;
+               buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops;
                goto reread;
        }
 
index b7c9aea77f8fd2e7ca88537df77536eca8148418..1e116794bb6622d686487f36a461f8f644fd27c2 100644 (file)
@@ -295,8 +295,7 @@ xfs_mount_validate_sb(
            sbp->sb_dblocks == 0                                        ||
            sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)                      ||
            sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
-               XFS_CORRUPTION_ERROR("SB sanity check failed",
-                               XFS_ERRLEVEL_LOW, mp, sbp);
+               xfs_notice(mp, "SB sanity check failed");
                return XFS_ERROR(EFSCORRUPTED);
        }
 
@@ -611,10 +610,10 @@ xfs_sb_read_verify(
                                                XFS_SB_VERSION_5) ||
             dsb->sb_crc != 0)) {
 
-               if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
+               if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
                                      offsetof(struct xfs_sb, sb_crc))) {
                        /* Only fail bad secondaries on a known V5 filesystem */
-                       if (bp->b_bn != XFS_SB_DADDR &&
+                       if (bp->b_bn == XFS_SB_DADDR ||
                            xfs_sb_version_hascrc(&mp->m_sb)) {
                                error = EFSCORRUPTED;
                                goto out_error;
@@ -625,7 +624,7 @@ xfs_sb_read_verify(
 
 out_error:
        if (error) {
-               if (error != EWRONGFS)
+               if (error == EFSCORRUPTED)
                        XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
                                             mp, bp->b_addr);
                xfs_buf_ioerror(bp, error);
@@ -644,7 +643,6 @@ xfs_sb_quiet_read_verify(
 {
        struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
 
-
        if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
                /* XFS filesystem, verify noisily! */
                xfs_sb_read_verify(bp);
index f317488263dd975eb85eb44d9746abfb974ef46f..d971f4932b5d8bb92d5efe645f372462abfbbe81 100644 (file)
@@ -913,7 +913,7 @@ xfs_flush_inodes(
        struct super_block      *sb = mp->m_super;
 
        if (down_read_trylock(&sb->s_umount)) {
-               sync_inodes_sb(sb, jiffies);
+               sync_inodes_sb(sb);
                up_read(&sb->s_umount);
        }
 }
index 8e4f41d9af4d47279e13a33edd317ce5de32e451..34c7bdc06014c0b5c787ec2faa85ab4d2b388096 100644 (file)
@@ -701,6 +701,18 @@ static inline pte_t pte_mknuma(pte_t pte)
 }
 #endif
 
+#ifndef ptep_set_numa
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+                                pte_t *ptep)
+{
+       pte_t ptent = *ptep;
+
+       ptent = pte_mknuma(ptent);
+       set_pte_at(mm, addr, ptep, ptent);
+       return;
+}
+#endif
+
 #ifndef pmd_mknuma
 static inline pmd_t pmd_mknuma(pmd_t pmd)
 {
@@ -708,6 +720,18 @@ static inline pmd_t pmd_mknuma(pmd_t pmd)
        return pmd_clear_flags(pmd, _PAGE_PRESENT);
 }
 #endif
+
+#ifndef pmdp_set_numa
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+                                pmd_t *pmdp)
+{
+       pmd_t pmd = *pmdp;
+
+       pmd = pmd_mknuma(pmd);
+       set_pmd_at(mm, addr, pmdp, pmd);
+       return;
+}
+#endif
 #else
 extern int pte_numa(pte_t pte);
 extern int pmd_numa(pmd_t pmd);
@@ -715,6 +739,8 @@ extern pte_t pte_mknonnuma(pte_t pte);
 extern pmd_t pmd_mknonnuma(pmd_t pmd);
 extern pte_t pte_mknuma(pte_t pte);
 extern pmd_t pmd_mknuma(pmd_t pmd);
+extern void ptep_set_numa(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+extern void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp);
 #endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */
 #else
 static inline int pmd_numa(pmd_t pmd)
@@ -742,10 +768,23 @@ static inline pte_t pte_mknuma(pte_t pte)
        return pte;
 }
 
+static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr,
+                                pte_t *ptep)
+{
+       return;
+}
+
+
 static inline pmd_t pmd_mknuma(pmd_t pmd)
 {
        return pmd;
 }
+
+static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr,
+                                pmd_t *pmdp)
+{
+       return ;
+}
 #endif /* CONFIG_NUMA_BALANCING */
 
 #endif /* CONFIG_MMU */
index 04086c5be930e2941f8be91cb0a47107da73ad08..04a7f31301f8fda61ab05cf42a3bea5c28431178 100644 (file)
@@ -199,6 +199,9 @@ int drm_err(const char *func, const char *format, ...);
 #define DRM_INFO(fmt, ...)                             \
        printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
 
+#define DRM_INFO_ONCE(fmt, ...)                                \
+       printk_once(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
+
 /**
  * Debug output.
  *
index 71727b6210ae57d5b064be1cab19a4dc660df6f8..8f3dee09757999c7c959e284250142c143d37d7d 100644 (file)
@@ -907,6 +907,9 @@ struct drm_mode_config {
 
        /* whether async page flip is supported or not */
        bool async_page_flip;
+
+       /* cursor size */
+       uint32_t cursor_width, cursor_height;
 };
 
 #define obj_to_crtc(x) container_of(x, struct drm_crtc, base)
index d1f61bfe0ebe49841cc5f249c8307b75973b98a7..49a828425fa2d984615b6352812681a455d7d99b 100644 (file)
@@ -29,6 +29,8 @@
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_memory.h>
 
+struct device;
+
 /**
  * Initialize pool allocator.
  */
index a1116a3b54ef106b610e74cc54ac0326b76805f6..8c1603b10665d141a2b0cb67e2643c0db7452146 100644 (file)
 #define TEGRA124_CLK_PWM 17
 #define TEGRA124_CLK_I2S2 18
 /* 20 (register bit affects vi and vi_sensor) */
-#define TEGRA124_CLK_GR_2D 21
+/* 21 */
 #define TEGRA124_CLK_USBD 22
 #define TEGRA124_CLK_ISP 23
-#define TEGRA124_CLK_GR_3D 24
+/* 26 */
 /* 25 */
 #define TEGRA124_CLK_DISP2 26
 #define TEGRA124_CLK_DISP1 27
index be85127bfed3a2da2a58a3284a48b7e72094ca91..f27000f55a83d6a27921372f9890520e492a747b 100644 (file)
@@ -171,6 +171,11 @@ static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 add
        return 0;
 }
 
+static inline int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
+{
+       return -ENXIO;
+}
+
 static inline int kvm_vgic_init(struct kvm *kvm)
 {
        return 0;
index aa865a9a4c4f862b4aa693ed9918399b338e7696..ec1464df4c60930a7fde38f1bc6f35a35b7f79d3 100644 (file)
@@ -43,6 +43,7 @@ struct mq_attr;
 struct mqstat;
 struct audit_watch;
 struct audit_tree;
+struct sk_buff;
 
 struct audit_krule {
        int                     vers_ops;
@@ -463,7 +464,7 @@ extern int audit_filter_user(int type);
 extern int audit_filter_type(int type);
 extern int audit_rule_change(int type, __u32 portid, int seq,
                                void *data, size_t datasz);
-extern int audit_list_rules_send(__u32 portid, int seq);
+extern int audit_list_rules_send(struct sk_buff *request_skb, int seq);
 
 extern u32 audit_enabled;
 #else /* CONFIG_AUDIT */
index 70654521dab69fb03443723550e9b9f8c64a6533..5a4d39b4686be4fb1f78c06442f29d4d955297d7 100644 (file)
@@ -250,6 +250,17 @@ static inline unsigned bio_segments(struct bio *bio)
        struct bio_vec bv;
        struct bvec_iter iter;
 
+       /*
+        * We special case discard/write same, because they interpret bi_size
+        * differently:
+        */
+
+       if (bio->bi_rw & REQ_DISCARD)
+               return 1;
+
+       if (bio->bi_rw & REQ_WRITE_SAME)
+               return 1;
+
        bio_for_each_segment(bv, bio, iter)
                segs++;
 
@@ -332,6 +343,7 @@ extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *);
 extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs);
 
 extern struct bio_set *fs_bio_set;
+unsigned int bio_integrity_tag_size(struct bio *bio);
 
 static inline struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs)
 {
index 161b23105b1ec9d90f3520f08fb66d0d9be66358..2ff2e8d982bea9b689050a2802fba5ec29e44b81 100644 (file)
@@ -83,6 +83,8 @@ struct blk_mq_ops {
         */
        rq_timed_out_fn         *timeout;
 
+       softirq_done_fn         *complete;
+
        /*
         * Override for hctx allocations (should probably go)
         */
@@ -119,11 +121,11 @@ void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struc
 
 void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule);
 
-void blk_mq_insert_request(struct request_queue *, struct request *, bool);
+void blk_mq_insert_request(struct request *, bool, bool, bool);
 void blk_mq_run_queues(struct request_queue *q, bool async);
 void blk_mq_free_request(struct request *rq);
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *);
-struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp, bool reserved);
+struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp);
 struct request *blk_mq_alloc_reserved_request(struct request_queue *q, int rw, gfp_t gfp);
 struct request *blk_mq_rq_from_tag(struct request_queue *q, unsigned int tag);
 
@@ -131,7 +133,15 @@ struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_ind
 struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_reg *, unsigned int);
 void blk_mq_free_single_hw_queue(struct blk_mq_hw_ctx *, unsigned int);
 
-void blk_mq_end_io(struct request *rq, int error);
+bool blk_mq_end_io_partial(struct request *rq, int error,
+               unsigned int nr_bytes);
+static inline void blk_mq_end_io(struct request *rq, int error)
+{
+       bool done = !blk_mq_end_io_partial(rq, error, blk_rq_bytes(rq));
+       BUG_ON(!done);
+}
+
+void blk_mq_complete_request(struct request *rq);
 
 void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx);
 void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx);
index 8678c4322b4462357266397c5455bc9c6be04fd6..4afa4f8f60909f6e53416c60682c02b35408c66e 100644 (file)
@@ -98,7 +98,7 @@ struct request {
        struct list_head queuelist;
        union {
                struct call_single_data csd;
-               struct work_struct mq_flush_data;
+               struct work_struct mq_flush_work;
        };
 
        struct request_queue *q;
@@ -448,13 +448,8 @@ struct request_queue {
        unsigned long           flush_pending_since;
        struct list_head        flush_queue[2];
        struct list_head        flush_data_in_flight;
-       union {
-               struct request  flush_rq;
-               struct {
-                       spinlock_t mq_flush_lock;
-                       struct work_struct mq_flush_work;
-               };
-       };
+       struct request          *flush_rq;
+       spinlock_t              mq_flush_lock;
 
        struct mutex            sysfs_lock;
 
index 677b4f01b2d0bfd2dd1619d930ec92992bcd1d7d..6f76277baf391733a3f9303f4f740b7151c5e96b 100644 (file)
 #define PHY_ID_BCM5461                 0x002060c0
 #define PHY_ID_BCM57780                        0x03625d90
 
+#define PHY_ID_BCM7366                 0x600d8490
+#define PHY_ID_BCM7439                 0x600d8480
+#define PHY_ID_BCM7445                 0x600d8510
+#define PHY_ID_BCM7XXX_28              0x600d8400
+
 #define PHY_BCM_OUI_MASK               0xfffffc00
 #define PHY_BCM_OUI_1                  0x00206000
 #define PHY_BCM_OUI_2                  0x0143bc00
 #define PHY_BCM_OUI_3                  0x03625c00
+#define PHY_BCM_OUI_4                  0x600d0000
+#define PHY_BCM_OUI_5                  0x03625e00
 
 
 #define PHY_BCM_FLAGS_MODE_COPPER      0x00000001
 #define PHY_BRCM_EXT_IBND_TX_ENABLE    0x00002000
 #define PHY_BRCM_CLEAR_RGMII_MODE      0x00004000
 #define PHY_BRCM_DIS_TXCRXC_NOENRGY    0x00008000
+/* Broadcom BCM7xxx specific workarounds */
+#define PHY_BRCM_100MBPS_WAR           0x00010000
 #define PHY_BCM_FLAGS_VALID            0x80000000
 
+/* Broadcom BCM54XX register definitions, common to most Broadcom PHYs */
+#define MII_BCM54XX_ECR                0x10    /* BCM54xx extended control register */
+#define MII_BCM54XX_ECR_IM     0x1000  /* Interrupt mask */
+#define MII_BCM54XX_ECR_IF     0x0800  /* Interrupt force */
+
+#define MII_BCM54XX_ESR                0x11    /* BCM54xx extended status register */
+#define MII_BCM54XX_ESR_IS     0x1000  /* Interrupt status */
+
+#define MII_BCM54XX_EXP_DATA   0x15    /* Expansion register data */
+#define MII_BCM54XX_EXP_SEL    0x17    /* Expansion register select */
+#define MII_BCM54XX_EXP_SEL_SSD        0x0e00  /* Secondary SerDes select */
+#define MII_BCM54XX_EXP_SEL_ER 0x0f00  /* Expansion register select */
+
+#define MII_BCM54XX_AUX_CTL    0x18    /* Auxiliary control register */
+#define MII_BCM54XX_ISR                0x1a    /* BCM54xx interrupt status register */
+#define MII_BCM54XX_IMR                0x1b    /* BCM54xx interrupt mask register */
+#define MII_BCM54XX_INT_CRCERR 0x0001  /* CRC error */
+#define MII_BCM54XX_INT_LINK   0x0002  /* Link status changed */
+#define MII_BCM54XX_INT_SPEED  0x0004  /* Link speed change */
+#define MII_BCM54XX_INT_DUPLEX 0x0008  /* Duplex mode changed */
+#define MII_BCM54XX_INT_LRS    0x0010  /* Local receiver status changed */
+#define MII_BCM54XX_INT_RRS    0x0020  /* Remote receiver status changed */
+#define MII_BCM54XX_INT_SSERR  0x0040  /* Scrambler synchronization error */
+#define MII_BCM54XX_INT_UHCD   0x0080  /* Unsupported HCD negotiated */
+#define MII_BCM54XX_INT_NHCD   0x0100  /* No HCD */
+#define MII_BCM54XX_INT_NHCDL  0x0200  /* No HCD link */
+#define MII_BCM54XX_INT_ANPR   0x0400  /* Auto-negotiation page received */
+#define MII_BCM54XX_INT_LC     0x0800  /* All counters below 128 */
+#define MII_BCM54XX_INT_HC     0x1000  /* Counter above 32768 */
+#define MII_BCM54XX_INT_MDIX   0x2000  /* MDIX status change */
+#define MII_BCM54XX_INT_PSERR  0x4000  /* Pair swap error */
+
+#define MII_BCM54XX_SHD                0x1c    /* 0x1c shadow registers */
+#define MII_BCM54XX_SHD_WRITE  0x8000
+#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10)
+#define MII_BCM54XX_SHD_DATA(x)        ((x & 0x3ff) << 0)
+
+/*
+ * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
+ */
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
+#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB         0x0400
+#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA      0x0800
+
+#define MII_BCM54XX_AUXCTL_MISC_WREN   0x8000
+#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX    0x0200
+#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC     0x7000
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC        0x0007
+
+#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL      0x0000
+
 #endif /* _LINUX_BRCMPHY_H */
index fb0ab651a04196ac247b718221cd857de0cc5365..3ce5e526525f852f37ea242700363036c85068ca 100644 (file)
@@ -33,8 +33,9 @@ enum can_mode {
 struct can_priv {
        struct can_device_stats can_stats;
 
-       struct can_bittiming bittiming;
-       const struct can_bittiming_const *bittiming_const;
+       struct can_bittiming bittiming, data_bittiming;
+       const struct can_bittiming_const *bittiming_const,
+               *data_bittiming_const;
        struct can_clock clock;
 
        enum can_state state;
@@ -45,6 +46,7 @@ struct can_priv {
        struct timer_list restart_timer;
 
        int (*do_set_bittiming)(struct net_device *dev);
+       int (*do_set_data_bittiming)(struct net_device *dev);
        int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
        int (*do_get_state)(const struct net_device *dev,
                            enum can_state *state);
@@ -111,6 +113,7 @@ struct can_priv *safe_candev_priv(struct net_device *dev);
 
 int open_candev(struct net_device *dev);
 void close_candev(struct net_device *dev);
+int can_change_mtu(struct net_device *dev, int new_mtu);
 
 int register_candev(struct net_device *dev);
 void unregister_candev(struct net_device *dev);
@@ -124,6 +127,8 @@ unsigned int can_get_echo_skb(struct net_device *dev, unsigned int idx);
 void can_free_echo_skb(struct net_device *dev, unsigned int idx);
 
 struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf);
+struct sk_buff *alloc_canfd_skb(struct net_device *dev,
+                               struct canfd_frame **cfd);
 struct sk_buff *alloc_can_err_skb(struct net_device *dev,
                                  struct can_frame **cf);
 
index 2f0543f7510c65aa71c5b5de43315da8d64c51aa..f9bbbb472663af08aef78ac152e8293f36736ea4 100644 (file)
@@ -11,7 +11,9 @@
 #define CAN_SKB_H
 
 #include <linux/types.h>
+#include <linux/skbuff.h>
 #include <linux/can.h>
+#include <net/sock.h>
 
 /*
  * The struct can_skb_priv is used to transport additional information along
@@ -42,4 +44,40 @@ static inline void can_skb_reserve(struct sk_buff *skb)
        skb_reserve(skb, sizeof(struct can_skb_priv));
 }
 
+static inline void can_skb_destructor(struct sk_buff *skb)
+{
+       sock_put(skb->sk);
+}
+
+static inline void can_skb_set_owner(struct sk_buff *skb, struct sock *sk)
+{
+       if (sk) {
+               sock_hold(sk);
+               skb->destructor = can_skb_destructor;
+               skb->sk = sk;
+       }
+}
+
+/*
+ * returns an unshared skb owned by the original sock to be echo'ed back
+ */
+static inline struct sk_buff *can_create_echo_skb(struct sk_buff *skb)
+{
+       if (skb_shared(skb)) {
+               struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+               if (likely(nskb)) {
+                       can_skb_set_owner(nskb, skb->sk);
+                       consume_skb(skb);
+                       return nskb;
+               } else {
+                       kfree_skb(skb);
+                       return NULL;
+               }
+       }
+
+       /* we can assume to have an unshared skb with proper owner */
+       return skb;
+}
+
 #endif /* CAN_SKB_H */
index 2623cffc73a17b32cf9660bf67cf05bd9ae4b45f..25bfb0eff7720b459ffefa45ec035ec0229c8b1c 100644 (file)
@@ -373,8 +373,9 @@ extern const char *ceph_mds_op_name(int op);
 /*
  * Ceph setxattr request flags.
  */
-#define CEPH_XATTR_CREATE  1
-#define CEPH_XATTR_REPLACE 2
+#define CEPH_XATTR_CREATE  (1 << 0)
+#define CEPH_XATTR_REPLACE (1 << 1)
+#define CEPH_XATTR_REMOVE  (1 << 31)
 
 union ceph_mds_request_args {
        struct {
index 5c097596104b80535a0a00bdd45b4a2441fac889..9450f025fe0c01ac52bf78caccf114c30312a2e4 100644 (file)
@@ -166,6 +166,8 @@ struct cgroup {
         *
         * The ID of the root cgroup is always 0, and a new cgroup
         * will be assigned with a smallest available ID.
+        *
+        * Allocating/Removing ID must be protected by cgroup_mutex.
         */
        int id;
 
index 092b64168d7fa6935dfe476f1657af9dda620a7a..4a21a872dbbd6423025f1a9253832f228cfe1c48 100644 (file)
@@ -245,6 +245,10 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
 void omap2_init_clk_clkdm(struct clk_hw *clk);
 unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
                                    unsigned long parent_rate);
+int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long parent_rate);
+long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
+               unsigned long *prate);
 int omap2_clkops_enable_clkdm(struct clk_hw *hw);
 void omap2_clkops_disable_clkdm(struct clk_hw *hw);
 int omap2_clk_disable_autoidle_all(void);
index ded429966c1f447db9106359b174fb742fd3fe54..2507fd2a1eb4f9d4971b9de5344e8f250570c012 100644 (file)
  *
  * (asm goto is automatically volatile - the naming reflects this.)
  */
-#if GCC_VERSION <= 40801
-# define asm_volatile_goto(x...)       do { asm goto(x); asm (""); } while (0)
-#else
-# define asm_volatile_goto(x...)       do { asm goto(x); } while (0)
-#endif
+#define asm_volatile_goto(x...)        do { asm goto(x); asm (""); } while (0)
 
 #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
 #if GCC_VERSION >= 40400
index dfac5ed311205d2469628273b161e4008fcfcbfb..f886985a28b2d5c0db1f1a798817eb167d2cb23c 100644 (file)
@@ -171,7 +171,7 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
                               size_t size, int flags, const char *);
 
 #define dma_buf_export(priv, ops, size, flags) \
-       dma_buf_export_named(priv, ops, size, flags, __FILE__)
+       dma_buf_export_named(priv, ops, size, flags, KBUILD_MODNAME)
 
 int dma_buf_fd(struct dma_buf *dmabuf, int flags);
 struct dma_buf *dma_buf_get(int fd);
index c8e3e7e39c6bf26ffbfe534cdfa83f59ad561372..0a114d05f68d35bd275924a7290a6c3b75ef17fd 100644 (file)
@@ -183,6 +183,9 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
  * hold the RTNL lock.
  *
  * See the structures used by these operations for further documentation.
+ * Note that for all operations using a structure ending with a zero-
+ * length array, the array is allocated separately in the kernel and
+ * is passed to the driver as an additional parameter.
  *
  * See &struct net_device and &struct net_device_ops for documentation
  * of the generic netdev features interface.
index cbacf4faf447a9dd2b3fd50d3dc2e4f86a120e67..4d69123377a2b4e0a7869ba38cc91ceb4fd1c7b7 100644 (file)
@@ -28,33 +28,36 @@ static inline void fput_light(struct file *file, int fput_needed)
 
 struct fd {
        struct file *file;
-       int need_put;
+       unsigned int flags;
 };
+#define FDPUT_FPUT       1
+#define FDPUT_POS_UNLOCK 2
 
 static inline void fdput(struct fd fd)
 {
-       if (fd.need_put)
+       if (fd.flags & FDPUT_FPUT)
                fput(fd.file);
 }
 
 extern struct file *fget(unsigned int fd);
-extern struct file *fget_light(unsigned int fd, int *fput_needed);
+extern struct file *fget_raw(unsigned int fd);
+extern unsigned long __fdget(unsigned int fd);
+extern unsigned long __fdget_raw(unsigned int fd);
+extern unsigned long __fdget_pos(unsigned int fd);
 
-static inline struct fd fdget(unsigned int fd)
+static inline struct fd __to_fd(unsigned long v)
 {
-       int b;
-       struct file *f = fget_light(fd, &b);
-       return (struct fd){f,b};
+       return (struct fd){(struct file *)(v & ~3),v & 3};
 }
 
-extern struct file *fget_raw(unsigned int fd);
-extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
+static inline struct fd fdget(unsigned int fd)
+{
+       return __to_fd(__fdget(fd));
+}
 
 static inline struct fd fdget_raw(unsigned int fd)
 {
-       int b;
-       struct file *f = fget_raw_light(fd, &b);
-       return (struct fd){f,b};
+       return __to_fd(__fdget_raw(fd));
 }
 
 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
index e568c8ef896bf170de5578d7d898343a457b7724..262dcbb75ffe3b343ae1513d715e2eae5fd1d902 100644 (file)
@@ -9,28 +9,81 @@
 #include <linux/workqueue.h>
 #include <uapi/linux/filter.h>
 
-#ifdef CONFIG_COMPAT
-/*
- * A struct sock_filter is architecture independent.
+/* Internally used and optimized filter representation with extended
+ * instruction set based on top of classic BPF.
  */
+
+/* instruction classes */
+#define BPF_ALU64      0x07    /* alu mode in double word width */
+
+/* ld/ldx fields */
+#define BPF_DW         0x18    /* double word */
+#define BPF_XADD       0xc0    /* exclusive add */
+
+/* alu/jmp fields */
+#define BPF_MOV                0xb0    /* mov reg to reg */
+#define BPF_ARSH       0xc0    /* sign extending arithmetic shift right */
+
+/* change endianness of a register */
+#define BPF_END                0xd0    /* flags for endianness conversion: */
+#define BPF_TO_LE      0x00    /* convert to little-endian */
+#define BPF_TO_BE      0x08    /* convert to big-endian */
+#define BPF_FROM_LE    BPF_TO_LE
+#define BPF_FROM_BE    BPF_TO_BE
+
+#define BPF_JNE                0x50    /* jump != */
+#define BPF_JSGT       0x60    /* SGT is signed '>', GT in x86 */
+#define BPF_JSGE       0x70    /* SGE is signed '>=', GE in x86 */
+#define BPF_CALL       0x80    /* function call */
+#define BPF_EXIT       0x90    /* function return */
+
+/* BPF has 10 general purpose 64-bit registers and stack frame. */
+#define MAX_BPF_REG    11
+
+/* BPF program can access up to 512 bytes of stack space. */
+#define MAX_BPF_STACK  512
+
+/* Arg1, context and stack frame pointer register positions. */
+#define ARG1_REG       1
+#define CTX_REG                6
+#define FP_REG         10
+
+struct sock_filter_int {
+       __u8    code;           /* opcode */
+       __u8    a_reg:4;        /* dest register */
+       __u8    x_reg:4;        /* source register */
+       __s16   off;            /* signed offset */
+       __s32   imm;            /* signed immediate constant */
+};
+
+#ifdef CONFIG_COMPAT
+/* A struct sock_filter is architecture independent. */
 struct compat_sock_fprog {
        u16             len;
-       compat_uptr_t   filter;         /* struct sock_filter * */
+       compat_uptr_t   filter; /* struct sock_filter * */
 };
 #endif
 
+struct sock_fprog_kern {
+       u16                     len;
+       struct sock_filter      *filter;
+};
+
 struct sk_buff;
 struct sock;
+struct seccomp_data;
 
-struct sk_filter
-{
+struct sk_filter {
        atomic_t                refcnt;
-       unsigned int            len;    /* Number of filter blocks */
+       u32                     jited:1,        /* Is our filter JIT'ed? */
+                               len:31;         /* Number of filter blocks */
+       struct sock_fprog_kern  *orig_prog;     /* Original BPF program */
        struct rcu_head         rcu;
        unsigned int            (*bpf_func)(const struct sk_buff *skb,
-                                           const struct sock_filter *filter);
+                                           const struct sock_filter_int *filter);
        union {
-               struct sock_filter      insns[0];
+               struct sock_filter      insns[0];
+               struct sock_filter_int  insnsi[0];
                struct work_struct      work;
        };
 };
@@ -41,25 +94,44 @@ static inline unsigned int sk_filter_size(unsigned int proglen)
                   offsetof(struct sk_filter, insns[proglen]));
 }
 
-extern int sk_filter(struct sock *sk, struct sk_buff *skb);
-extern unsigned int sk_run_filter(const struct sk_buff *skb,
-                                 const struct sock_filter *filter);
-extern int sk_unattached_filter_create(struct sk_filter **pfp,
-                                      struct sock_fprog *fprog);
-extern void sk_unattached_filter_destroy(struct sk_filter *fp);
-extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
-extern int sk_detach_filter(struct sock *sk);
-extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
-extern int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned len);
-extern void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to);
+#define sk_filter_proglen(fprog)                       \
+               (fprog->len * sizeof(fprog->filter[0]))
+
+#define SK_RUN_FILTER(filter, ctx)                     \
+               (*filter->bpf_func)(ctx, filter->insnsi)
+
+int sk_filter(struct sock *sk, struct sk_buff *skb);
+
+u32 sk_run_filter_int_seccomp(const struct seccomp_data *ctx,
+                             const struct sock_filter_int *insni);
+u32 sk_run_filter_int_skb(const struct sk_buff *ctx,
+                         const struct sock_filter_int *insni);
+
+int sk_convert_filter(struct sock_filter *prog, int len,
+                     struct sock_filter_int *new_prog, int *new_len);
+
+int sk_unattached_filter_create(struct sk_filter **pfp,
+                               struct sock_fprog *fprog);
+void sk_unattached_filter_destroy(struct sk_filter *fp);
+
+int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+int sk_detach_filter(struct sock *sk);
+
+int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
+int sk_get_filter(struct sock *sk, struct sock_filter __user *filter,
+                 unsigned int len);
+void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to);
+
+void sk_filter_charge(struct sock *sk, struct sk_filter *fp);
+void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp);
 
 #ifdef CONFIG_BPF_JIT
 #include <stdarg.h>
 #include <linux/linkage.h>
 #include <linux/printk.h>
 
-extern void bpf_jit_compile(struct sk_filter *fp);
-extern void bpf_jit_free(struct sk_filter *fp);
+void bpf_jit_compile(struct sk_filter *fp);
+void bpf_jit_free(struct sk_filter *fp);
 
 static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
                                u32 pass, void *image)
@@ -70,7 +142,6 @@ static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen,
                print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_OFFSET,
                               16, 1, image, proglen, false);
 }
-#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
 #else
 #include <linux/slab.h>
 static inline void bpf_jit_compile(struct sk_filter *fp)
@@ -80,7 +151,6 @@ static inline void bpf_jit_free(struct sk_filter *fp)
 {
        kfree(fp);
 }
-#define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns)
 #endif
 
 static inline int bpf_tell_extensions(void)
index 5d7782e42b8f22f81df12652348ff9a21aebc7e4..c3683bdf28fe4e677959f33d524bd724a9a1d59d 100644 (file)
@@ -200,6 +200,7 @@ struct fw_device {
        unsigned irmc:1;
        unsigned bc_implemented:2;
 
+       work_func_t workfn;
        struct delayed_work work;
        struct fw_attribute_group attribute_group;
 };
index 60829565e5522a2c68f489665909d39f65230a25..23b2a35d712efbec3e31df0cae70b69a17b81616 100644 (file)
@@ -123,6 +123,9 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 /* File is opened with O_PATH; almost nothing can be done with it */
 #define FMODE_PATH             ((__force fmode_t)0x4000)
 
+/* File needs atomic accesses to f_pos */
+#define FMODE_ATOMIC_POS       ((__force fmode_t)0x8000)
+
 /* File was opened by fanotify and shouldn't generate fanotify events */
 #define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
 
@@ -780,13 +783,14 @@ struct file {
        const struct file_operations    *f_op;
 
        /*
-        * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
+        * Protects f_ep_links, f_flags.
         * Must not be taken from IRQ context.
         */
        spinlock_t              f_lock;
        atomic_long_t           f_count;
        unsigned int            f_flags;
        fmode_t                 f_mode;
+       struct mutex            f_pos_lock;
        loff_t                  f_pos;
        struct fown_struct      f_owner;
        const struct cred       *f_cred;
@@ -808,7 +812,7 @@ struct file {
 #ifdef CONFIG_DEBUG_WRITECOUNT
        unsigned long f_mnt_write_state;
 #endif
-};
+} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
 
 struct file_handle {
        __u32 handle_bytes;
index 3d286ff49ab0c82309ec3499bf27cc77f75f3670..64cf3ef50696c7bf50b3c3a3e211cfa9d3accb0d 100644 (file)
@@ -99,7 +99,7 @@ struct fsnotify_ops {
                            struct fsnotify_mark *inode_mark,
                            struct fsnotify_mark *vfsmount_mark,
                            u32 mask, void *data, int data_type,
-                           const unsigned char *file_name);
+                           const unsigned char *file_name, u32 cookie);
        void (*free_group_priv)(struct fsnotify_group *group);
        void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
        void (*free_event)(struct fsnotify_event *event);
@@ -160,7 +160,7 @@ struct fsnotify_group {
 
        struct fasync_struct *fsn_fa;    /* async notification */
 
-       struct fsnotify_event overflow_event;   /* Event we queue when the
+       struct fsnotify_event *overflow_event;  /* Event we queue when the
                                                 * notification list is too
                                                 * full */
 
index 4e4cc28623adff33d7f33bc2f7ceda7269397c62..4cdb3a17bcb5932113020955cf8aa46b7b592f14 100644 (file)
@@ -495,10 +495,6 @@ enum {
        FILTER_TRACE_FN,
 };
 
-#define EVENT_STORAGE_SIZE 128
-extern struct mutex event_storage_mutex;
-extern char event_storage[EVENT_STORAGE_SIZE];
-
 extern int trace_event_raw_init(struct ftrace_event_call *call);
 extern int trace_define_field(struct ftrace_event_call *call, const char *type,
                              const char *name, int offset, int size,
index 0437439bc047bd4a99d7465132b1d9417667934e..39b81dc7d01acdb28e6e888fea3399f7866057f8 100644 (file)
@@ -123,6 +123,10 @@ struct vm_area_struct;
                         __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \
                         __GFP_NO_KSWAPD)
 
+/*
+ * GFP_THISNODE does not perform any reclaim, you most likely want to
+ * use __GFP_THISNODE to allocate from a given node without fallback!
+ */
 #ifdef CONFIG_NUMA
 #define GFP_THISNODE   (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
 #else
index 4d34dbbbad4dde2ce2c1cd820320537661575450..7a8144fef4065fab8505ffcfe2482cc0b60f3cbb 100644 (file)
@@ -4,8 +4,6 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 
-#ifdef CONFIG_GPIOLIB
-
 struct device;
 struct gpio_chip;
 
@@ -18,6 +16,8 @@ struct gpio_chip;
  */
 struct gpio_desc;
 
+#ifdef CONFIG_GPIOLIB
+
 /* Acquire and dispose GPIOs */
 struct gpio_desc *__must_check gpiod_get(struct device *dev,
                                         const char *con_id);
index db512014e061b27abae7d689175e82d74348683b..b826239bdce0b26a614ae0802782860348dd6fc6 100644 (file)
@@ -157,46 +157,6 @@ static inline int hpage_nr_pages(struct page *page)
                return HPAGE_PMD_NR;
        return 1;
 }
-/*
- * compound_trans_head() should be used instead of compound_head(),
- * whenever the "page" passed as parameter could be the tail of a
- * transparent hugepage that could be undergoing a
- * __split_huge_page_refcount(). The page structure layout often
- * changes across releases and it makes extensive use of unions. So if
- * the page structure layout will change in a way that
- * page->first_page gets clobbered by __split_huge_page_refcount, the
- * implementation making use of smp_rmb() will be required.
- *
- * Currently we define compound_trans_head as compound_head, because
- * page->private is in the same union with page->first_page, and
- * page->private isn't clobbered. However this also means we're
- * currently leaving dirt into the page->private field of anonymous
- * pages resulting from a THP split, instead of setting page->private
- * to zero like for every other page that has PG_private not set. But
- * anonymous pages don't use page->private so this is not a problem.
- */
-#if 0
-/* This will be needed if page->private will be clobbered in split_huge_page */
-static inline struct page *compound_trans_head(struct page *page)
-{
-       if (PageTail(page)) {
-               struct page *head;
-               head = page->first_page;
-               smp_rmb();
-               /*
-                * head may be a dangling pointer.
-                * __split_huge_page_refcount clears PageTail before
-                * overwriting first_page, so if PageTail is still
-                * there it means the head pointer isn't dangling.
-                */
-               if (PageTail(page))
-                       return head;
-       }
-       return page;
-}
-#else
-#define compound_trans_head(page) compound_head(page)
-#endif
 
 extern int do_huge_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                unsigned long addr, pmd_t pmd, pmd_t *pmdp);
@@ -226,7 +186,6 @@ static inline int split_huge_page(struct page *page)
        do { } while (0)
 #define split_huge_page_pmd_mm(__mm, __address, __pmd) \
        do { } while (0)
-#define compound_trans_head(page) compound_head(page)
 static inline int hugepage_madvise(struct vm_area_struct *vma,
                                   unsigned long *vm_flags, int advice)
 {
index 15da677478ddc353b151d81362043bcbdfc3d089..344883dce5849b62e8f6c0e59e1daed09b5a0f80 100644 (file)
@@ -875,7 +875,7 @@ struct vmbus_channel_relid_released {
 struct vmbus_channel_initiate_contact {
        struct vmbus_channel_message_header header;
        u32 vmbus_version_requested;
-       u32 padding2;
+       u32 target_vcpu; /* The VCPU the host should respond to */
        u64 interrupt_page;
        u64 monitor_page1;
        u64 monitor_page2;
index bbedfb56bd66074545503f12e161ee2cc640eb58..13bbbde00e68de454c8cf30f0581796d55eb0a40 100644 (file)
@@ -110,6 +110,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
                                               __be16 vlan_proto, u16 vlan_id);
 extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
 extern u16 vlan_dev_vlan_id(const struct net_device *dev);
+extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
 
 /**
  *     struct vlan_priority_tci_mapping - vlan egress priority mappings
@@ -216,6 +217,12 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
        return 0;
 }
 
+static inline __be16 vlan_dev_vlan_proto(const struct net_device *dev)
+{
+       BUG();
+       return 0;
+}
+
 static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev,
                                               u32 skprio)
 {
@@ -288,7 +295,7 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
        struct vlan_ethhdr *veth;
 
        if (skb_cow_head(skb, VLAN_HLEN) < 0) {
-               kfree_skb(skb);
+               dev_kfree_skb_any(skb);
                return NULL;
        }
        veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
index 0053adde0ed9a37111ffd273c17f6d19956a6a77..a2678d35b5a2e8fc8f840d91f1ac5c7ec0c97bec 100644 (file)
@@ -158,6 +158,11 @@ devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
                                         devname, dev_id);
 }
 
+extern int __must_check
+devm_request_any_context_irq(struct device *dev, unsigned int irq,
+                irq_handler_t handler, unsigned long irqflags,
+                const char *devname, void *dev_id);
+
 extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
 
 /*
index e7831d20373776f5c3dc80c5a04147e8aa611c85..35e7eca4e33b1fbbde3029b5f3cb2be350d0dafc 100644 (file)
@@ -118,9 +118,7 @@ extern int mq_init_ns(struct ipc_namespace *ns);
  *     the new maximum will handle anyone else.  I may have to revisit this
  *     in the future.
  */
-#define MIN_QUEUESMAX                  1
 #define DFLT_QUEUESMAX               256
-#define HARD_QUEUESMAX              1024
 #define MIN_MSGMAX                     1
 #define DFLT_MSG                      10U
 #define DFLT_MSGMAX                   10
index d5f62bc5f4beb8499983d3c3a682b9c468c74b9e..8e10f57f109f5a9eff472fe7a90dbce48e4a20dc 100644 (file)
@@ -180,9 +180,8 @@ struct ippp_struct {
   struct slcompress *slcomp;
 #endif
 #ifdef CONFIG_IPPP_FILTER
-  struct sock_filter *pass_filter;     /* filter for packets to pass */
-  struct sock_filter *active_filter;   /* filter for pkts to reset idle */
-  unsigned pass_len, active_len;
+  struct sk_filter *pass_filter;   /* filter for packets to pass */
+  struct sk_filter *active_filter; /* filter for pkts to reset idle */
 #endif
   unsigned long debug;
   struct isdn_ppp_compressor *compressor,*decompressor;
index 5be9f0228a3bbc8ddfad7a2fc245f6601cfc1f17..d267623c28cfdaa385ab5f288683c0157f9e8ef4 100644 (file)
@@ -249,7 +249,8 @@ void kernfs_notify(struct kernfs_node *kn);
 
 const void *kernfs_super_ns(struct super_block *sb);
 struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-                              struct kernfs_root *root, const void *ns);
+                              struct kernfs_root *root, bool *new_sb_created,
+                              const void *ns);
 void kernfs_kill_sb(struct super_block *sb);
 
 void kernfs_init(void);
@@ -317,7 +318,7 @@ static inline const void *kernfs_super_ns(struct super_block *sb)
 
 static inline struct dentry *
 kernfs_mount_ns(struct file_system_type *fs_type, int flags,
-               struct kernfs_root *root, const void *ns)
+               struct kernfs_root *root, bool *new_sb_created, const void *ns)
 { return ERR_PTR(-ENOSYS); }
 
 static inline void kernfs_kill_sb(struct super_block *sb) { }
@@ -368,9 +369,9 @@ static inline int kernfs_remove_by_name(struct kernfs_node *parent,
 
 static inline struct dentry *
 kernfs_mount(struct file_system_type *fs_type, int flags,
-            struct kernfs_root *root)
+            struct kernfs_root *root, bool *new_sb_created)
 {
-       return kernfs_mount_ns(fs_type, flags, root, NULL);
+       return kernfs_mount_ns(fs_type, flags, root, new_sb_created, NULL);
 }
 
 #endif /* __LINUX_KERNFS_H */
index ad1ae7f345ad9482df4a47c0ddc4ab11bd34e2ec..78c76cd4d37bdff2d1c56e2a9c1c199af6b7a77d 100644 (file)
@@ -387,7 +387,7 @@ struct max8997_dev {
        struct i2c_client *muic; /* slave addr 0x4a */
        struct mutex iolock;
 
-       int type;
+       unsigned long type;
        struct platform_device *battery; /* battery control (not fuel gauge) */
 
        int irq;
index 4ecb24b4b863be4158263466ce919e78b42714d5..d68ada502ff37c1e08164f723db8ef3e33d96a50 100644 (file)
@@ -163,7 +163,7 @@ struct max8998_dev {
        int ono;
        u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS];
        u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS];
-       int type;
+       unsigned long type;
        bool wakeup;
 };
 
index a5a7f0130e9604837982d4b2f3bb9920fd5d090c..54b5458ec084a50ec06cc9f418d4e623e0aaf7bc 100644 (file)
@@ -252,7 +252,7 @@ struct tps65217_board {
 struct tps65217 {
        struct device *dev;
        struct tps65217_board *pdata;
-       unsigned int id;
+       unsigned long id;
        struct regulator_desc desc[TPS65217_NUM_REGULATOR];
        struct regulator_dev *rdev[TPS65217_NUM_REGULATOR];
        struct regmap *regmap;
@@ -263,7 +263,7 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev)
        return dev_get_drvdata(dev);
 }
 
-static inline int tps65217_chip_id(struct tps65217 *tps65217)
+static inline unsigned long tps65217_chip_id(struct tps65217 *tps65217)
 {
        return tps65217->id;
 }
index 79a34723816895e59c794872f94d03893920c15b..c8450366c13019fe0ec0343487cd5ef6a8e2855f 100644 (file)
@@ -125,6 +125,7 @@ enum {
        /* miscellaneous commands */
        MLX4_CMD_DIAG_RPRT       = 0x30,
        MLX4_CMD_NOP             = 0x31,
+       MLX4_CMD_CONFIG_DEV      = 0x3a,
        MLX4_CMD_ACCESS_MEM      = 0x2e,
        MLX4_CMD_SET_VEP         = 0x52,
 
@@ -240,6 +241,13 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos);
 int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting);
 int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_info *ivf);
 int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_state);
+/*
+ * mlx4_get_slave_default_vlan -
+ * return true if VST ( default vlan)
+ * if VST, will return vlan & qos (if not NULL)
+ */
+bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave,
+                                u16 *vlan, u8 *qos);
 
 #define MLX4_COMM_GET_IF_REV(cmd_chan_ver) (u8)((cmd_chan_ver) >> 8)
 
index 5edd2c68274dd449f34f557296ce789e38578dad..ba87bd21295a533c8d6941bc4c11d29bceba0112 100644 (file)
@@ -48,6 +48,9 @@
 #define MSIX_LEGACY_SZ         4
 #define MIN_MSIX_P_PORT                5
 
+#define MLX4_ROCE_MAX_GIDS     128
+#define MLX4_ROCE_PF_GIDS      16
+
 enum {
        MLX4_FLAG_MSI_X         = 1 << 0,
        MLX4_FLAG_OLD_PORT_CMDS = 1 << 1,
@@ -81,6 +84,7 @@ enum {
 enum {
        MLX4_MAX_NUM_PF         = 16,
        MLX4_MAX_NUM_VF         = 64,
+       MLX4_MAX_NUM_VF_P_PORT  = 64,
        MLX4_MFUNC_MAX          = 80,
        MLX4_MAX_EQ_NUM         = 1024,
        MLX4_MFUNC_EQ_NUM       = 4,
@@ -629,7 +633,8 @@ struct mlx4_eth_av {
        u8              hop_limit;
        __be32          sl_tclass_flowlabel;
        u8              dgid[16];
-       u32             reserved4[2];
+       u8              s_mac[6];
+       u8              reserved4[2];
        __be16          vlan;
        u8              mac[ETH_ALEN];
 };
@@ -660,6 +665,11 @@ struct mlx4_quotas {
        int xrcd;
 };
 
+struct mlx4_vf_dev {
+       u8                      min_port;
+       u8                      n_ports;
+};
+
 struct mlx4_dev {
        struct pci_dev         *pdev;
        unsigned long           flags;
@@ -675,6 +685,7 @@ struct mlx4_dev {
        int                     oper_log_mgm_entry_size;
        u64                     regid_promisc_array[MLX4_MAX_PORTS + 1];
        u64                     regid_allmulti_array[MLX4_MAX_PORTS + 1];
+       struct mlx4_vf_dev     *dev_vfs;
 };
 
 struct mlx4_eqe {
@@ -1131,7 +1142,7 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn,
 int mlx4_SET_PORT_PRIO2TC(struct mlx4_dev *dev, u8 port, u8 *prio2tc);
 int mlx4_SET_PORT_SCHEDULER(struct mlx4_dev *dev, u8 port, u8 *tc_tx_bw,
                u8 *pg, u16 *ratelimit);
-int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering);
+int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable);
 int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx);
 int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx);
 int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index);
@@ -1183,9 +1194,44 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, int
 void mlx4_put_slave_node_guid(struct mlx4_dev *dev, int slave, __be64 guid);
 __be64 mlx4_get_slave_node_guid(struct mlx4_dev *dev, int slave);
 
+int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
+                                int *slave_id);
+int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id,
+                                u8 *gid);
+
 int mlx4_FLOW_STEERING_IB_UC_QP_RANGE(struct mlx4_dev *dev, u32 min_range_qpn,
                                      u32 max_range_qpn);
 
 cycle_t mlx4_read_clock(struct mlx4_dev *dev);
 
+struct mlx4_active_ports {
+       DECLARE_BITMAP(ports, MLX4_MAX_PORTS);
+};
+/* Returns a bitmap of the physical ports which are assigned to slave */
+struct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave);
+
+/* Returns the physical port that represents the virtual port of the slave, */
+/* or a value < 0 in case of an error. If a slave has 2 ports, the identity */
+/* mapping is returned.                                                            */
+int mlx4_slave_convert_port(struct mlx4_dev *dev, int slave, int port);
+
+struct mlx4_slaves_pport {
+       DECLARE_BITMAP(slaves, MLX4_MFUNC_MAX);
+};
+/* Returns a bitmap of all slaves that are assigned to port. */
+struct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev,
+                                                  int port);
+
+/* Returns a bitmap of all slaves that are assigned exactly to all the */
+/* the ports that are set in crit_ports.                              */
+struct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv(
+               struct mlx4_dev *dev,
+               const struct mlx4_active_ports *crit_ports);
+
+/* Returns the slave's virtual port that represents the physical port. */
+int mlx4_phys_to_slave_port(struct mlx4_dev *dev, int slave, int port);
+
+int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port);
+
+int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port);
 #endif /* MLX4_DEVICE_H */
index c257e1b211be813989d1948906a637e358b0910c..022055c8fb2649456b19197f8417f8011ee2dc16 100644 (file)
@@ -64,4 +64,16 @@ void mlx4_unregister_interface(struct mlx4_interface *intf);
 
 void *mlx4_get_protocol_dev(struct mlx4_dev *dev, enum mlx4_protocol proto, int port);
 
+static inline u64 mlx4_mac_to_u64(u8 *addr)
+{
+       u64 mac = 0;
+       int i;
+
+       for (i = 0; i < ETH_ALEN; i++) {
+               mac <<= 8;
+               mac |= addr[i];
+       }
+       return mac;
+}
+
 #endif /* MLX4_DRIVER_H */
index 59f8ba84568bef4a4e17ed21240c163d6953a912..b66e7610d4eec9f4d67e5f8bbd745bb6cbd3c99a 100644 (file)
@@ -270,9 +270,14 @@ enum {
 
 struct mlx4_wqe_ctrl_seg {
        __be32                  owner_opcode;
-       __be16                  vlan_tag;
-       u8                      ins_vlan;
-       u8                      fence_size;
+       union {
+               struct {
+                       __be16                  vlan_tag;
+                       u8                      ins_vlan;
+                       u8                      fence_size;
+               };
+               __be32                  bf_qpn;
+       };
        /*
         * High 24 bits are SRC remote buffer; low 8 bits are flags:
         * [7]   SO (strong ordering)
index 554548cd3dd4683145ce5ef0a4b1e66fb829365d..130bc8d77fa5e38173b90c157092189cb3ff7479 100644 (file)
 #include <linux/pci.h>
 #include <linux/spinlock_types.h>
 #include <linux/semaphore.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/radix-tree.h>
+
 #include <linux/mlx5/device.h>
 #include <linux/mlx5/doorbell.h>
 
@@ -227,6 +229,7 @@ struct mlx5_uuar_info {
         * protect uuar allocation data structs
         */
        struct mutex            lock;
+       u32                     ver;
 };
 
 struct mlx5_bf {
index f28f46eade6a642873246fea247f3f5455a18acb..c1b7414c7bef7c0a2128edd30438e48974af40f3 100644 (file)
@@ -175,7 +175,7 @@ extern unsigned int kobjsize(const void *objp);
  * Special vmas that are non-mergable, non-mlock()able.
  * Note: mm/huge_memory.c VM_NO_THP depends on this definition.
  */
-#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP)
+#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
 
 /*
  * mapping from the currently active vm_flags protection bits (the
@@ -399,8 +399,18 @@ static inline void compound_unlock_irqrestore(struct page *page,
 
 static inline struct page *compound_head(struct page *page)
 {
-       if (unlikely(PageTail(page)))
-               return page->first_page;
+       if (unlikely(PageTail(page))) {
+               struct page *head = page->first_page;
+
+               /*
+                * page->first_page may be a dangling pointer to an old
+                * compound page, so recheck that it is still a tail
+                * page before returning.
+                */
+               smp_rmb();
+               if (likely(PageTail(page)))
+                       return head;
+       }
        return page;
 }
 
@@ -757,7 +767,7 @@ static inline bool __cpupid_match_pid(pid_t task_pid, int cpupid)
 #ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
 static inline int page_cpupid_xchg_last(struct page *page, int cpupid)
 {
-       return xchg(&page->_last_cpupid, cpupid);
+       return xchg(&page->_last_cpupid, cpupid & LAST_CPUPID_MASK);
 }
 
 static inline int page_cpupid_last(struct page *page)
@@ -766,7 +776,7 @@ static inline int page_cpupid_last(struct page *page)
 }
 static inline void page_cpupid_reset_last(struct page *page)
 {
-       page->_last_cpupid = -1;
+       page->_last_cpupid = -1 & LAST_CPUPID_MASK;
 }
 #else
 static inline int page_cpupid_last(struct page *page)
index 5f2052c831547a33b66606d78ac5713086d285e3..9b61b9bf81ac86a90c1ce70d12400b745b7582eb 100644 (file)
@@ -590,10 +590,10 @@ static inline bool zone_is_empty(struct zone *zone)
 
 /*
  * The NUMA zonelists are doubled because we need zonelists that restrict the
- * allocations to a single node for GFP_THISNODE.
+ * allocations to a single node for __GFP_THISNODE.
  *
  * [0] : Zonelist with fallback
- * [1] : No fallback (GFP_THISNODE)
+ * [1] : No fallback (__GFP_THISNODE)
  */
 #define MAX_ZONELISTS 2
 
diff --git a/include/linux/mpls.h b/include/linux/mpls.h
new file mode 100644 (file)
index 0000000..9999145
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _LINUX_MPLS_H
+#define _LINUX_MPLS_H
+
+#include <uapi/linux/mpls.h>
+
+#endif  /* _LINUX_MPLS_H */
index 1005ebf175752774ada359369a313379a82dc85a..5a09a48f2658a64f7149ecddd30abd56c65cf69f 100644 (file)
@@ -163,4 +163,11 @@ enum {
 /* changeable features with no special hardware requirements */
 #define NETIF_F_SOFT_FEATURES  (NETIF_F_GSO | NETIF_F_GRO)
 
+#define NETIF_F_VLAN_FEATURES  (NETIF_F_HW_VLAN_CTAG_FILTER | \
+                                NETIF_F_HW_VLAN_CTAG_RX | \
+                                NETIF_F_HW_VLAN_CTAG_TX | \
+                                NETIF_F_HW_VLAN_STAG_FILTER | \
+                                NETIF_F_HW_VLAN_STAG_RX | \
+                                NETIF_F_HW_VLAN_STAG_TX)
+
 #endif /* _LINUX_NETDEV_FEATURES_H */
index 440a02ee6f92cda68d3438ab88af3896d7c41af2..06287c110241f47ffa4a546abdf17616a0fd7e83 100644 (file)
@@ -752,6 +752,9 @@ struct netdev_phys_port_id {
        unsigned char id_len;
 };
 
+typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
+                                      struct sk_buff *skb);
+
 /*
  * This structure defines the management hooks for network devices.
  * The following hooks can be defined; unless noted otherwise, they are
@@ -783,7 +786,7 @@ struct netdev_phys_port_id {
  *     Required can not be NULL.
  *
  * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb,
- *                         void *accel_priv);
+ *                         void *accel_priv, select_queue_fallback_t fallback);
  *     Called to decide which queue to when device supports multiple
  *     transmit queues.
  *
@@ -1005,7 +1008,8 @@ struct net_device_ops {
                                                   struct net_device *dev);
        u16                     (*ndo_select_queue)(struct net_device *dev,
                                                    struct sk_buff *skb,
-                                                   void *accel_priv);
+                                                   void *accel_priv,
+                                                   select_queue_fallback_t fallback);
        void                    (*ndo_change_rx_flags)(struct net_device *dev,
                                                       int flags);
        void                    (*ndo_set_rx_mode)(struct net_device *dev);
@@ -1033,8 +1037,7 @@ struct net_device_ops {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*ndo_poll_controller)(struct net_device *dev);
        int                     (*ndo_netpoll_setup)(struct net_device *dev,
-                                                    struct netpoll_info *info,
-                                                    gfp_t gfp);
+                                                    struct netpoll_info *info);
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
 #ifdef CONFIG_NET_RX_BUSY_POLL
@@ -1143,6 +1146,89 @@ struct net_device_ops {
                                                        void *priv);
 };
 
+/**
+ * enum net_device_priv_flags - &struct net_device priv_flags
+ *
+ * These are the &struct net_device, they are only set internally
+ * by drivers and used in the kernel. These flags are invisible to
+ * userspace, this means that the order of these flags can change
+ * during any kernel release.
+ *
+ * You should have a pretty good reason to be extending these flags.
+ *
+ * @IFF_802_1Q_VLAN: 802.1Q VLAN device
+ * @IFF_EBRIDGE: Ethernet bridging device
+ * @IFF_SLAVE_INACTIVE: bonding slave not the curr. active
+ * @IFF_MASTER_8023AD: bonding master, 802.3ad
+ * @IFF_MASTER_ALB: bonding master, balance-alb
+ * @IFF_BONDING: bonding master or slave
+ * @IFF_SLAVE_NEEDARP: need ARPs for validation
+ * @IFF_ISATAP: ISATAP interface (RFC4214)
+ * @IFF_MASTER_ARPMON: bonding master, ARP mon in use
+ * @IFF_WAN_HDLC: WAN HDLC device
+ * @IFF_XMIT_DST_RELEASE: dev_hard_start_xmit() is allowed to
+ *     release skb->dst
+ * @IFF_DONT_BRIDGE: disallow bridging this ether dev
+ * @IFF_DISABLE_NETPOLL: disable netpoll at run-time
+ * @IFF_MACVLAN_PORT: device used as macvlan port
+ * @IFF_BRIDGE_PORT: device used as bridge port
+ * @IFF_OVS_DATAPATH: device used as Open vSwitch datapath port
+ * @IFF_TX_SKB_SHARING: The interface supports sharing skbs on transmit
+ * @IFF_UNICAST_FLT: Supports unicast filtering
+ * @IFF_TEAM_PORT: device used as team port
+ * @IFF_SUPP_NOFCS: device supports sending custom FCS
+ * @IFF_LIVE_ADDR_CHANGE: device supports hardware address
+ *     change when it's running
+ * @IFF_MACVLAN: Macvlan device
+ */
+enum netdev_priv_flags {
+       IFF_802_1Q_VLAN                 = 1<<0,
+       IFF_EBRIDGE                     = 1<<1,
+       IFF_SLAVE_INACTIVE              = 1<<2,
+       IFF_MASTER_8023AD               = 1<<3,
+       IFF_MASTER_ALB                  = 1<<4,
+       IFF_BONDING                     = 1<<5,
+       IFF_SLAVE_NEEDARP               = 1<<6,
+       IFF_ISATAP                      = 1<<7,
+       IFF_MASTER_ARPMON               = 1<<8,
+       IFF_WAN_HDLC                    = 1<<9,
+       IFF_XMIT_DST_RELEASE            = 1<<10,
+       IFF_DONT_BRIDGE                 = 1<<11,
+       IFF_DISABLE_NETPOLL             = 1<<12,
+       IFF_MACVLAN_PORT                = 1<<13,
+       IFF_BRIDGE_PORT                 = 1<<14,
+       IFF_OVS_DATAPATH                = 1<<15,
+       IFF_TX_SKB_SHARING              = 1<<16,
+       IFF_UNICAST_FLT                 = 1<<17,
+       IFF_TEAM_PORT                   = 1<<18,
+       IFF_SUPP_NOFCS                  = 1<<19,
+       IFF_LIVE_ADDR_CHANGE            = 1<<20,
+       IFF_MACVLAN                     = 1<<21,
+};
+
+#define IFF_802_1Q_VLAN                        IFF_802_1Q_VLAN
+#define IFF_EBRIDGE                    IFF_EBRIDGE
+#define IFF_SLAVE_INACTIVE             IFF_SLAVE_INACTIVE
+#define IFF_MASTER_8023AD              IFF_MASTER_8023AD
+#define IFF_MASTER_ALB                 IFF_MASTER_ALB
+#define IFF_BONDING                    IFF_BONDING
+#define IFF_SLAVE_NEEDARP              IFF_SLAVE_NEEDARP
+#define IFF_ISATAP                     IFF_ISATAP
+#define IFF_MASTER_ARPMON              IFF_MASTER_ARPMON
+#define IFF_WAN_HDLC                   IFF_WAN_HDLC
+#define IFF_XMIT_DST_RELEASE           IFF_XMIT_DST_RELEASE
+#define IFF_DONT_BRIDGE                        IFF_DONT_BRIDGE
+#define IFF_DISABLE_NETPOLL            IFF_DISABLE_NETPOLL
+#define IFF_MACVLAN_PORT               IFF_MACVLAN_PORT
+#define IFF_BRIDGE_PORT                        IFF_BRIDGE_PORT
+#define IFF_OVS_DATAPATH               IFF_OVS_DATAPATH
+#define IFF_TX_SKB_SHARING             IFF_TX_SKB_SHARING
+#define IFF_UNICAST_FLT                        IFF_UNICAST_FLT
+#define IFF_TEAM_PORT                  IFF_TEAM_PORT
+#define IFF_SUPP_NOFCS                 IFF_SUPP_NOFCS
+#define IFF_LIVE_ADDR_CHANGE           IFF_LIVE_ADDR_CHANGE
+#define IFF_MACVLAN                    IFF_MACVLAN
+
 /*
  *     The DEVICE structure.
  *     Actually, this whole structure is a big mistake.  It mixes I/O
@@ -1224,9 +1310,10 @@ struct net_device {
        int                     iflink;
 
        struct net_device_stats stats;
-       atomic_long_t           rx_dropped; /* dropped packets by core network
-                                            * Do not use this in drivers.
-                                            */
+
+       /* dropped packets by core network, Do not use this in drivers */
+       atomic_long_t           rx_dropped;
+       atomic_long_t           tx_dropped;
 
 #ifdef CONFIG_WIRELESS_EXT
        /* List of functions to handle Wireless Extensions (instead of ioctl).
@@ -1275,6 +1362,10 @@ struct net_device {
                                                 * that share the same link
                                                 * layer address
                                                 */
+       unsigned short          dev_port;       /* Used to differentiate
+                                                * devices that share the same
+                                                * function
+                                                */
        spinlock_t              addr_list_lock;
        struct netdev_hw_addr_list      uc;     /* Unicast mac addresses */
        struct netdev_hw_addr_list      mc;     /* Multicast mac addresses */
@@ -1312,13 +1403,7 @@ struct net_device {
 /*
  * Cache lines mostly used on receive path (including eth_type_trans())
  */
-       unsigned long           last_rx;        /* Time of last Rx
-                                                * This should not be set in
-                                                * drivers, unless really needed,
-                                                * because network stack (bonding)
-                                                * use it if/when necessary, to
-                                                * avoid dirtying this cache line.
-                                                */
+       unsigned long           last_rx;        /* Time of last Rx */
 
        /* Interface address info used in eth_type_trans() */
        unsigned char           *dev_addr;      /* hw address, (before bcast
@@ -1551,7 +1636,6 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
 struct netdev_queue *netdev_pick_tx(struct net_device *dev,
                                    struct sk_buff *skb,
                                    void *accel_priv);
-u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb);
 
 /*
  * Net namespace inlines
@@ -1726,6 +1810,20 @@ struct pcpu_sw_netstats {
        struct u64_stats_sync   syncp;
 };
 
+#define netdev_alloc_pcpu_stats(type)                          \
+({                                                             \
+       typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \
+       if (pcpu_stats) {                                       \
+               int i;                                          \
+               for_each_possible_cpu(i) {                      \
+                       typeof(type) *stat;                     \
+                       stat = per_cpu_ptr(pcpu_stats, i);      \
+                       u64_stats_init(&stat->syncp);           \
+               }                                               \
+       }                                                       \
+       pcpu_stats;                                             \
+})
+
 #include <linux/notifier.h>
 
 /* netdevice notifier chain. Please remember to update the rtnetlink
@@ -1881,9 +1979,6 @@ struct net_device *__dev_get_by_index(struct net *net, int ifindex);
 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
 int netdev_get_name(struct net *net, char *name, int ifindex);
 int dev_restart(struct net_device *dev);
-#ifdef CONFIG_NETPOLL_TRAP
-int netpoll_trap(void);
-#endif
 int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb);
 
 static inline unsigned int skb_gro_offset(const struct sk_buff *skb)
@@ -2088,12 +2183,6 @@ static inline void netif_tx_start_all_queues(struct net_device *dev)
 
 static inline void netif_tx_wake_queue(struct netdev_queue *dev_queue)
 {
-#ifdef CONFIG_NETPOLL_TRAP
-       if (netpoll_trap()) {
-               netif_tx_start_queue(dev_queue);
-               return;
-       }
-#endif
        if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state))
                __netif_schedule(dev_queue->qdisc);
 }
@@ -2275,6 +2364,26 @@ static inline void netdev_reset_queue(struct net_device *dev_queue)
        netdev_tx_reset_queue(netdev_get_tx_queue(dev_queue, 0));
 }
 
+/**
+ *     netdev_cap_txqueue - check if selected tx queue exceeds device queues
+ *     @dev: network device
+ *     @queue_index: given tx queue index
+ *
+ *     Returns 0 if given tx queue index >= number of device tx queues,
+ *     otherwise returns the originally passed tx queue index.
+ */
+static inline u16 netdev_cap_txqueue(struct net_device *dev, u16 queue_index)
+{
+       if (unlikely(queue_index >= dev->real_num_tx_queues)) {
+               net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
+                                    dev->name, queue_index,
+                                    dev->real_num_tx_queues);
+               return 0;
+       }
+
+       return queue_index;
+}
+
 /**
  *     netif_running - test if up
  *     @dev: network device
@@ -2317,10 +2426,6 @@ static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index)
 static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
 {
        struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
-#ifdef CONFIG_NETPOLL_TRAP
-       if (netpoll_trap())
-               return;
-#endif
        netif_tx_stop_queue(txq);
 }
 
@@ -2355,10 +2460,6 @@ static inline bool netif_subqueue_stopped(const struct net_device *dev,
 static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
 {
        struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index);
-#ifdef CONFIG_NETPOLL_TRAP
-       if (netpoll_trap())
-               return;
-#endif
        if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state))
                __netif_schedule(txq->qdisc);
 }
@@ -2808,6 +2909,11 @@ static inline void netif_tx_unlock_bh(struct net_device *dev)
        }                                               \
 }
 
+#define HARD_TX_TRYLOCK(dev, txq)                      \
+       (((dev->features & NETIF_F_LLTX) == 0) ?        \
+               __netif_tx_trylock(txq) :               \
+               true )
+
 #define HARD_TX_UNLOCK(dev, txq) {                     \
        if ((dev->features & NETIF_F_LLTX) == 0) {      \
                __netif_tx_unlock(txq);                 \
@@ -2991,7 +3097,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features)
 {
        return __skb_gso_segment(skb, features, true);
 }
-__be16 skb_network_protocol(struct sk_buff *skb);
+__be16 skb_network_protocol(struct sk_buff *skb, int *depth);
 
 static inline bool can_checksum_protocol(netdev_features_t features,
                                         __be16 protocol)
@@ -3068,7 +3174,12 @@ void netdev_change_features(struct net_device *dev);
 void netif_stacked_transfer_operstate(const struct net_device *rootdev,
                                        struct net_device *dev);
 
-netdev_features_t netif_skb_features(struct sk_buff *skb);
+netdev_features_t netif_skb_dev_features(struct sk_buff *skb,
+                                        const struct net_device *dev);
+static inline netdev_features_t netif_skb_features(struct sk_buff *skb)
+{
+       return netif_skb_dev_features(skb, skb->dev);
+}
 
 static inline bool net_gso_ok(netdev_features_t features, int gso_type)
 {
index 0c7d01eae56cf8626d2d1fc55242b3cbae0ba1ad..96afc29184bee810a1ec550933cfb15998f42efb 100644 (file)
@@ -39,11 +39,13 @@ enum ip_set_feature {
        IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
        IPSET_TYPE_IFACE_FLAG = 5,
        IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
-       IPSET_TYPE_NOMATCH_FLAG = 6,
+       IPSET_TYPE_MARK_FLAG = 6,
+       IPSET_TYPE_MARK = (1 << IPSET_TYPE_MARK_FLAG),
+       IPSET_TYPE_NOMATCH_FLAG = 7,
        IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG),
        /* Strictly speaking not a feature, but a flag for dumping:
         * this settype must be dumped last */
-       IPSET_DUMP_LAST_FLAG = 7,
+       IPSET_DUMP_LAST_FLAG = 8,
        IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
 };
 
@@ -63,6 +65,7 @@ enum ip_set_extension {
 #define SET_WITH_TIMEOUT(s)    ((s)->extensions & IPSET_EXT_TIMEOUT)
 #define SET_WITH_COUNTER(s)    ((s)->extensions & IPSET_EXT_COUNTER)
 #define SET_WITH_COMMENT(s)    ((s)->extensions & IPSET_EXT_COMMENT)
+#define SET_WITH_FORCEADD(s)   ((s)->flags & IPSET_CREATE_FLAG_FORCEADD)
 
 /* Extension id, in size order */
 enum ip_set_ext_id {
@@ -171,8 +174,6 @@ struct ip_set_type {
        char name[IPSET_MAXNAMELEN];
        /* Protocol version */
        u8 protocol;
-       /* Set features to control swapping */
-       u8 features;
        /* Set type dimension */
        u8 dimension;
        /*
@@ -182,6 +183,8 @@ struct ip_set_type {
        u8 family;
        /* Type revisions */
        u8 revision_min, revision_max;
+       /* Set features to control swapping */
+       u16 features;
 
        /* Create set */
        int (*create)(struct net *net, struct ip_set *set,
@@ -217,6 +220,8 @@ struct ip_set {
        u8 revision;
        /* Extensions */
        u8 extensions;
+       /* Create flags */
+       u8 flags;
        /* Default timeout value, if enabled */
        u32 timeout;
        /* Element data size */
@@ -251,6 +256,8 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set)
                cadt_flags |= IPSET_FLAG_WITH_COUNTERS;
        if (SET_WITH_COMMENT(set))
                cadt_flags |= IPSET_FLAG_WITH_COMMENT;
+       if (SET_WITH_FORCEADD(set))
+               cadt_flags |= IPSET_FLAG_WITH_FORCEADD;
 
        if (!cadt_flags)
                return 0;
index 28c74367e900ac679aa5feba98b7629ea6338af3..e955d47306259c5867d80831bd78d99490849b0b 100644 (file)
@@ -44,6 +44,27 @@ int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
 
 void nfnl_lock(__u8 subsys_id);
 void nfnl_unlock(__u8 subsys_id);
+#ifdef CONFIG_PROVE_LOCKING
+int lockdep_nfnl_is_held(__u8 subsys_id);
+#else
+static inline int lockdep_nfnl_is_held(__u8 subsys_id)
+{
+       return 1;
+}
+#endif /* CONFIG_PROVE_LOCKING */
+
+/*
+ * nfnl_dereference - fetch RCU pointer when updates are prevented by subsys mutex
+ *
+ * @p: The pointer to read, prior to dereferencing
+ * @ss: The nfnetlink subsystem ID
+ *
+ * Return the value of the specified RCU-protected pointer, but omit
+ * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because
+ * caller holds the NFNL subsystem mutex.
+ */
+#define nfnl_dereference(p, ss)                                        \
+       rcu_dereference_protected(p, lockdep_nfnl_is_held(ss))
 
 #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
        MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
index fbfdb9d8d3a7f59b4788bdfd1cdb26c86f0a81ca..b25ee9ffdbe67e06a5c70305360cceea3de43aef 100644 (file)
@@ -24,27 +24,20 @@ struct netpoll {
        struct net_device *dev;
        char dev_name[IFNAMSIZ];
        const char *name;
-       void (*rx_skb_hook)(struct netpoll *np, int source, struct sk_buff *skb,
-                           int offset, int len);
 
        union inet_addr local_ip, remote_ip;
        bool ipv6;
        u16 local_port, remote_port;
        u8 remote_mac[ETH_ALEN];
 
-       struct list_head rx; /* rx_np list element */
        struct work_struct cleanup_work;
 };
 
 struct netpoll_info {
        atomic_t refcnt;
 
-       unsigned long rx_flags;
-       spinlock_t rx_lock;
        struct semaphore dev_lock;
-       struct list_head rx_np; /* netpolls that registered an rx_skb_hook */
 
-       struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
        struct sk_buff_head txq;
 
        struct delayed_work tx_work;
@@ -54,24 +47,21 @@ struct netpoll_info {
 };
 
 #ifdef CONFIG_NETPOLL
-extern void netpoll_rx_disable(struct net_device *dev);
-extern void netpoll_rx_enable(struct net_device *dev);
+extern void netpoll_poll_disable(struct net_device *dev);
+extern void netpoll_poll_enable(struct net_device *dev);
 #else
-static inline void netpoll_rx_disable(struct net_device *dev) { return; }
-static inline void netpoll_rx_enable(struct net_device *dev) { return; }
+static inline void netpoll_poll_disable(struct net_device *dev) { return; }
+static inline void netpoll_poll_enable(struct net_device *dev) { return; }
 #endif
 
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
 void netpoll_print_options(struct netpoll *np);
 int netpoll_parse_options(struct netpoll *np, char *opt);
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp);
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev);
 int netpoll_setup(struct netpoll *np);
-int netpoll_trap(void);
-void netpoll_set_trap(int trap);
 void __netpoll_cleanup(struct netpoll *np);
 void __netpoll_free_async(struct netpoll *np);
 void netpoll_cleanup(struct netpoll *np);
-int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo);
 void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                             struct net_device *dev);
 static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
@@ -82,46 +72,7 @@ static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
        local_irq_restore(flags);
 }
 
-
-
 #ifdef CONFIG_NETPOLL
-static inline bool netpoll_rx_on(struct sk_buff *skb)
-{
-       struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
-
-       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
-}
-
-static inline bool netpoll_rx(struct sk_buff *skb)
-{
-       struct netpoll_info *npinfo;
-       unsigned long flags;
-       bool ret = false;
-
-       local_irq_save(flags);
-
-       if (!netpoll_rx_on(skb))
-               goto out;
-
-       npinfo = rcu_dereference_bh(skb->dev->npinfo);
-       spin_lock(&npinfo->rx_lock);
-       /* check rx_flags again with the lock held */
-       if (npinfo->rx_flags && __netpoll_rx(skb, npinfo))
-               ret = true;
-       spin_unlock(&npinfo->rx_lock);
-
-out:
-       local_irq_restore(flags);
-       return ret;
-}
-
-static inline int netpoll_receive_skb(struct sk_buff *skb)
-{
-       if (!list_empty(&skb->dev->napi_list))
-               return netpoll_rx(skb);
-       return 0;
-}
-
 static inline void *netpoll_poll_lock(struct napi_struct *napi)
 {
        struct net_device *dev = napi->dev;
@@ -150,18 +101,6 @@ static inline bool netpoll_tx_running(struct net_device *dev)
 }
 
 #else
-static inline bool netpoll_rx(struct sk_buff *skb)
-{
-       return false;
-}
-static inline bool netpoll_rx_on(struct sk_buff *skb)
-{
-       return false;
-}
-static inline int netpoll_receive_skb(struct sk_buff *skb)
-{
-       return 0;
-}
 static inline void *netpoll_poll_lock(struct napi_struct *napi)
 {
        return NULL;
index b2fb167b2e6d99ed71a1ab6ddeae6c7c3885600a..5624e4e2763c2eb3d73f4e02d2752661ccd9c6b9 100644 (file)
@@ -467,9 +467,14 @@ struct nfs_lockt_res {
 };
 
 struct nfs_release_lockowner_args {
+       struct nfs4_sequence_args       seq_args;
        struct nfs_lowner       lock_owner;
 };
 
+struct nfs_release_lockowner_res {
+       struct nfs4_sequence_res        seq_res;
+};
+
 struct nfs4_delegreturnargs {
        struct nfs4_sequence_args       seq_args;
        const struct nfs_fh *fhandle;
index fd4f2d1cdf6cbfd95a3dd9eba2c10b27eca9d062..e110b8c266f547a884bca0040dd15e3be03f1485 100644 (file)
@@ -70,6 +70,16 @@ enum {
        IEEE802154_ATTR_PHY_NAME,
        IEEE802154_ATTR_DEV_TYPE,
 
+       IEEE802154_ATTR_TXPOWER,
+       IEEE802154_ATTR_LBT_ENABLED,
+       IEEE802154_ATTR_CCA_MODE,
+       IEEE802154_ATTR_CCA_ED_LEVEL,
+       IEEE802154_ATTR_CSMA_RETRIES,
+       IEEE802154_ATTR_CSMA_MIN_BE,
+       IEEE802154_ATTR_CSMA_MAX_BE,
+
+       IEEE802154_ATTR_FRAME_RETRIES,
+
        __IEEE802154_ATTR_MAX,
 };
 
@@ -122,6 +132,8 @@ enum {
        IEEE802154_ADD_IFACE,
        IEEE802154_DEL_IFACE,
 
+       IEEE802154_SET_PHYPARAMS,
+
        __IEEE802154_CMD_MAX,
 };
 
index 70c64ba17fa51f7cca0e232b8f95b7669f5a3075..435cb995904dedc6329916f29cd2378b5e0e7b2e 100644 (file)
@@ -169,35 +169,15 @@ static inline const char *of_node_full_name(const struct device_node *np)
 
 extern struct device_node *of_find_node_by_name(struct device_node *from,
        const char *name);
-#define for_each_node_by_name(dn, name) \
-       for (dn = of_find_node_by_name(NULL, name); dn; \
-            dn = of_find_node_by_name(dn, name))
 extern struct device_node *of_find_node_by_type(struct device_node *from,
        const char *type);
-#define for_each_node_by_type(dn, type) \
-       for (dn = of_find_node_by_type(NULL, type); dn; \
-            dn = of_find_node_by_type(dn, type))
 extern struct device_node *of_find_compatible_node(struct device_node *from,
        const char *type, const char *compat);
-#define for_each_compatible_node(dn, type, compatible) \
-       for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
-            dn = of_find_compatible_node(dn, type, compatible))
 extern struct device_node *of_find_matching_node_and_match(
        struct device_node *from,
        const struct of_device_id *matches,
        const struct of_device_id **match);
-static inline struct device_node *of_find_matching_node(
-       struct device_node *from,
-       const struct of_device_id *matches)
-{
-       return of_find_matching_node_and_match(from, matches, NULL);
-}
-#define for_each_matching_node(dn, matches) \
-       for (dn = of_find_matching_node(NULL, matches); dn; \
-            dn = of_find_matching_node(dn, matches))
-#define for_each_matching_node_and_match(dn, matches, match) \
-       for (dn = of_find_matching_node_and_match(NULL, matches, match); \
-            dn; dn = of_find_matching_node_and_match(dn, matches, match))
+
 extern struct device_node *of_find_node_by_path(const char *path);
 extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_get_parent(const struct device_node *node);
@@ -209,43 +189,11 @@ extern struct device_node *of_get_next_available_child(
 
 extern struct device_node *of_get_child_by_name(const struct device_node *node,
                                        const char *name);
-#define for_each_child_of_node(parent, child) \
-       for (child = of_get_next_child(parent, NULL); child != NULL; \
-            child = of_get_next_child(parent, child))
-
-#define for_each_available_child_of_node(parent, child) \
-       for (child = of_get_next_available_child(parent, NULL); child != NULL; \
-            child = of_get_next_available_child(parent, child))
-
-static inline int of_get_child_count(const struct device_node *np)
-{
-       struct device_node *child;
-       int num = 0;
-
-       for_each_child_of_node(np, child)
-               num++;
-
-       return num;
-}
-
-static inline int of_get_available_child_count(const struct device_node *np)
-{
-       struct device_node *child;
-       int num = 0;
-
-       for_each_available_child_of_node(np, child)
-               num++;
-
-       return num;
-}
 
 /* cache lookup */
 extern struct device_node *of_find_next_cache_node(const struct device_node *);
 extern struct device_node *of_find_node_with_property(
        struct device_node *from, const char *prop_name);
-#define for_each_node_with_property(dn, prop_name) \
-       for (dn = of_find_node_with_property(NULL, prop_name); dn; \
-            dn = of_find_node_with_property(dn, prop_name))
 
 extern struct property *of_find_property(const struct device_node *np,
                                         const char *name,
@@ -367,42 +315,53 @@ static inline struct device_node *of_find_node_by_name(struct device_node *from,
        return NULL;
 }
 
-static inline struct device_node *of_get_parent(const struct device_node *node)
+static inline struct device_node *of_find_node_by_type(struct device_node *from,
+       const char *type)
 {
        return NULL;
 }
 
-static inline bool of_have_populated_dt(void)
+static inline struct device_node *of_find_matching_node_and_match(
+       struct device_node *from,
+       const struct of_device_id *matches,
+       const struct of_device_id **match)
 {
-       return false;
+       return NULL;
 }
 
-/* Kill an unused variable warning on a device_node pointer */
-static inline void __of_use_dn(const struct device_node *np)
+static inline struct device_node *of_get_parent(const struct device_node *node)
 {
+       return NULL;
 }
 
-#define for_each_child_of_node(parent, child) \
-       while (__of_use_dn(parent), __of_use_dn(child), 0)
+static inline struct device_node *of_get_next_child(
+       const struct device_node *node, struct device_node *prev)
+{
+       return NULL;
+}
 
-#define for_each_available_child_of_node(parent, child) \
-       while (0)
+static inline struct device_node *of_get_next_available_child(
+       const struct device_node *node, struct device_node *prev)
+{
+       return NULL;
+}
 
-static inline struct device_node *of_get_child_by_name(
-                                       const struct device_node *node,
-                                       const char *name)
+static inline struct device_node *of_find_node_with_property(
+       struct device_node *from, const char *prop_name)
 {
        return NULL;
 }
 
-static inline int of_get_child_count(const struct device_node *np)
+static inline bool of_have_populated_dt(void)
 {
-       return 0;
+       return false;
 }
 
-static inline int of_get_available_child_count(const struct device_node *np)
+static inline struct device_node *of_get_child_by_name(
+                                       const struct device_node *node,
+                                       const char *name)
 {
-       return 0;
+       return NULL;
 }
 
 static inline int of_device_is_compatible(const struct device_node *device,
@@ -569,6 +528,13 @@ extern int of_node_to_nid(struct device_node *np);
 static inline int of_node_to_nid(struct device_node *device) { return 0; }
 #endif
 
+static inline struct device_node *of_find_matching_node(
+       struct device_node *from,
+       const struct of_device_id *matches)
+{
+       return of_find_matching_node_and_match(from, matches, NULL);
+}
+
 /**
  * of_property_read_bool - Findfrom a property
  * @np:                device node from which the property value is to be read.
@@ -618,6 +584,55 @@ static inline int of_property_read_u32(const struct device_node *np,
                s;                                              \
                s = of_prop_next_string(prop, s))
 
+#define for_each_node_by_name(dn, name) \
+       for (dn = of_find_node_by_name(NULL, name); dn; \
+            dn = of_find_node_by_name(dn, name))
+#define for_each_node_by_type(dn, type) \
+       for (dn = of_find_node_by_type(NULL, type); dn; \
+            dn = of_find_node_by_type(dn, type))
+#define for_each_compatible_node(dn, type, compatible) \
+       for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
+            dn = of_find_compatible_node(dn, type, compatible))
+#define for_each_matching_node(dn, matches) \
+       for (dn = of_find_matching_node(NULL, matches); dn; \
+            dn = of_find_matching_node(dn, matches))
+#define for_each_matching_node_and_match(dn, matches, match) \
+       for (dn = of_find_matching_node_and_match(NULL, matches, match); \
+            dn; dn = of_find_matching_node_and_match(dn, matches, match))
+
+#define for_each_child_of_node(parent, child) \
+       for (child = of_get_next_child(parent, NULL); child != NULL; \
+            child = of_get_next_child(parent, child))
+#define for_each_available_child_of_node(parent, child) \
+       for (child = of_get_next_available_child(parent, NULL); child != NULL; \
+            child = of_get_next_available_child(parent, child))
+
+#define for_each_node_with_property(dn, prop_name) \
+       for (dn = of_find_node_with_property(NULL, prop_name); dn; \
+            dn = of_find_node_with_property(dn, prop_name))
+
+static inline int of_get_child_count(const struct device_node *np)
+{
+       struct device_node *child;
+       int num = 0;
+
+       for_each_child_of_node(np, child)
+               num++;
+
+       return num;
+}
+
+static inline int of_get_available_child_count(const struct device_node *np)
+{
+       struct device_node *child;
+       int num = 0;
+
+       for_each_available_child_of_node(np, child)
+               num++;
+
+       return num;
+}
+
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
 extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
index 8d7dd6768cb760e5ec987ddbbc1e393319d53de0..ef370210ffb25ead579f83591b3ce152d3fc80d8 100644 (file)
@@ -78,11 +78,13 @@ static inline int of_device_uevent_modalias(struct device *dev,
 
 static inline void of_device_node_put(struct device *dev) { }
 
-static inline const struct of_device_id *of_match_device(
+static inline const struct of_device_id *__of_match_device(
                const struct of_device_id *matches, const struct device *dev)
 {
        return NULL;
 }
+#define of_match_device(matches, dev)  \
+       __of_match_device(of_match_ptr(matches), (dev))
 
 static inline struct device_node *of_cpu_device_node_get(int cpu)
 {
index fb57c892b214d6b3482c63a28061130f3a700a9c..33aa2caf0f0c9e5bd9e7cf07c8d92b08207be959 100644 (file)
@@ -1169,8 +1169,23 @@ void msi_remove_pci_irq_vectors(struct pci_dev *dev);
 void pci_restore_msi_state(struct pci_dev *dev);
 int pci_msi_enabled(void);
 int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec);
+static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+{
+       int rc = pci_enable_msi_range(dev, nvec, nvec);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
 int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
                          int minvec, int maxvec);
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+                                       struct msix_entry *entries, int nvec)
+{
+       int rc = pci_enable_msix_range(dev, entries, nvec, nvec);
+       if (rc < 0)
+               return rc;
+       return 0;
+}
 #else
 static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; }
 static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec)
@@ -1189,9 +1204,14 @@ static inline int pci_msi_enabled(void) { return 0; }
 static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec,
                                       int maxvec)
 { return -ENOSYS; }
+static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec)
+{ return -ENOSYS; }
 static inline int pci_enable_msix_range(struct pci_dev *dev,
                      struct msix_entry *entries, int minvec, int maxvec)
 { return -ENOSYS; }
+static inline int pci_enable_msix_exact(struct pci_dev *dev,
+                     struct msix_entry *entries, int nvec)
+{ return -ENOSYS; }
 #endif
 
 #ifdef CONFIG_PCIEPORTBUS
index 565188ca328f31841a4c8b718db2c4fd08238278..24126c4b27b58e443fe3569fa7143e256466ce84 100644 (file)
@@ -74,8 +74,53 @@ typedef enum {
        PHY_INTERFACE_MODE_RTBI,
        PHY_INTERFACE_MODE_SMII,
        PHY_INTERFACE_MODE_XGMII,
+       PHY_INTERFACE_MODE_MOCA,
+       PHY_INTERFACE_MODE_MAX,
 } phy_interface_t;
 
+/**
+ * It maps 'enum phy_interface_t' found in include/linux/phy.h
+ * into the device tree binding of 'phy-mode', so that Ethernet
+ * device driver can get phy interface from device tree.
+ */
+static inline const char *phy_modes(phy_interface_t interface)
+{
+       switch (interface) {
+       case PHY_INTERFACE_MODE_NA:
+               return "";
+       case PHY_INTERFACE_MODE_MII:
+               return "mii";
+       case PHY_INTERFACE_MODE_GMII:
+               return "gmii";
+       case PHY_INTERFACE_MODE_SGMII:
+               return "sgmii";
+       case PHY_INTERFACE_MODE_TBI:
+               return "tbi";
+       case PHY_INTERFACE_MODE_REVMII:
+               return "rev-mii";
+       case PHY_INTERFACE_MODE_RMII:
+               return "rmii";
+       case PHY_INTERFACE_MODE_RGMII:
+               return "rgmii";
+       case PHY_INTERFACE_MODE_RGMII_ID:
+               return "rgmii-id";
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+               return "rgmii-rxid";
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               return "rgmii-txid";
+       case PHY_INTERFACE_MODE_RTBI:
+               return "rtbi";
+       case PHY_INTERFACE_MODE_SMII:
+               return "smii";
+       case PHY_INTERFACE_MODE_XGMII:
+               return "xgmii";
+       case PHY_INTERFACE_MODE_MOCA:
+               return "moca";
+       default:
+               return "unknown";
+       }
+}
+
 
 #define PHY_INIT_TIMEOUT       100000
 #define PHY_STATE_TIME         1
@@ -308,6 +353,7 @@ struct phy_device {
        struct phy_c45_device_ids c45_ids;
        bool is_c45;
        bool is_internal;
+       bool has_fixups;
 
        enum phy_state state;
 
@@ -393,6 +439,11 @@ struct phy_driver {
        u32 features;
        u32 flags;
 
+       /*
+        * Called to issue a PHY software reset
+        */
+       int (*soft_reset)(struct phy_device *phydev);
+
        /*
         * Called to initialize the PHY,
         * including after a reset
@@ -417,6 +468,9 @@ struct phy_driver {
         */
        int (*config_aneg)(struct phy_device *phydev);
 
+       /* Determines the auto negotiation result */
+       int (*aneg_done)(struct phy_device *phydev);
+
        /* Determines the negotiated speed and duplex */
        int (*read_status)(struct phy_device *phydev);
 
@@ -612,10 +666,12 @@ static inline int phy_read_status(struct phy_device *phydev)
 int genphy_setup_forced(struct phy_device *phydev);
 int genphy_restart_aneg(struct phy_device *phydev);
 int genphy_config_aneg(struct phy_device *phydev);
+int genphy_aneg_done(struct phy_device *phydev);
 int genphy_update_link(struct phy_device *phydev);
 int genphy_read_status(struct phy_device *phydev);
 int genphy_suspend(struct phy_device *phydev);
 int genphy_resume(struct phy_device *phydev);
+int genphy_soft_reset(struct phy_device *phydev);
 void phy_driver_unregister(struct phy_driver *drv);
 void phy_drivers_unregister(struct phy_driver *drv, int n);
 int phy_driver_register(struct phy_driver *new_driver);
index e273e5ac19c9ca068825aa27fc01eca365a3f248..3f83459dbb20b557ec067b9d14d8dbf1f1e56ba3 100644 (file)
@@ -146,7 +146,9 @@ static inline void phy_set_bus_width(struct phy *phy, int bus_width)
        phy->attrs.bus_width = bus_width;
 }
 struct phy *phy_get(struct device *dev, const char *string);
+struct phy *phy_optional_get(struct device *dev, const char *string);
 struct phy *devm_phy_get(struct device *dev, const char *string);
+struct phy *devm_phy_optional_get(struct device *dev, const char *string);
 void phy_put(struct phy *phy);
 void devm_phy_put(struct device *dev, struct phy *phy);
 struct phy *of_phy_simple_xlate(struct device *dev,
@@ -232,11 +234,23 @@ static inline struct phy *phy_get(struct device *dev, const char *string)
        return ERR_PTR(-ENOSYS);
 }
 
+static inline struct phy *phy_optional_get(struct device *dev,
+                                          const char *string)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
 static inline struct phy *devm_phy_get(struct device *dev, const char *string)
 {
        return ERR_PTR(-ENOSYS);
 }
 
+static inline struct phy *devm_phy_optional_get(struct device *dev,
+                                               const char *string)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
 static inline void phy_put(struct phy *phy)
 {
 }
index 1dc420ba213a52624920184c620441516270c6bf..6d3b0a2ef9ce851f299c03b3f83fcd5a8e4d4952 100644 (file)
 #include <linux/if_vlan.h>
 #include <linux/ip.h>
 #include <linux/filter.h>
-#ifdef __KERNEL__
 #include <linux/in.h>
-#else
-#include <netinet/in.h>
-#endif
 
 #define PTP_CLASS_NONE  0x00 /* not a PTP event message */
 #define PTP_CLASS_V1    0x01 /* protocol version 1 */
 #define OP_RETA        (BPF_RET | BPF_A)
 #define OP_RETK        (BPF_RET | BPF_K)
 
-static inline int ptp_filter_init(struct sock_filter *f, int len)
-{
-       if (OP_LDH == f[0].code)
-               return sk_chk_filter(f, len);
-       else
-               return 0;
-}
-
 #define PTP_FILTER \
        {OP_LDH,        0,   0, OFF_ETYPE               }, /*              */ \
        {OP_JEQ,        0,  12, ETH_P_IP                }, /* f goto L20   */ \
@@ -137,4 +125,6 @@ static inline int ptp_filter_init(struct sock_filter *f, int len)
        {OP_RETA,       0,   0, 0                       }, /*              */ \
 /*L6x*/        {OP_RETK,       0,   0, PTP_CLASS_NONE          },
 
+unsigned int ptp_classify_raw(const struct sk_buff *skb);
+
 #endif
index 38a99350832744231042de3d1d45f0fc11f3471f..0d8ff3fb84baf1778fccd81cf4caa7c4a87ac2d8 100644 (file)
@@ -49,7 +49,11 @@ struct ptp_clock_request {
  * @n_alarm:   The number of programmable alarms.
  * @n_ext_ts:  The number of external time stamp channels.
  * @n_per_out: The number of programmable periodic signals.
+ * @n_pins:    The number of programmable pins.
  * @pps:       Indicates whether the clock supports a PPS callback.
+ * @pin_config: Array of length 'n_pins'. If the number of
+ *              programmable pins is nonzero, then drivers must
+ *              allocate and initialize this array.
  *
  * clock operations
  *
@@ -70,6 +74,18 @@ struct ptp_clock_request {
  *            parameter request: Desired resource to enable or disable.
  *            parameter on: Caller passes one to enable or zero to disable.
  *
+ * @verify:   Confirm that a pin can perform a given function. The PTP
+ *            Hardware Clock subsystem maintains the 'pin_config'
+ *            array on behalf of the drivers, but the PHC subsystem
+ *            assumes that every pin can perform every function. This
+ *            hook gives drivers a way of telling the core about
+ *            limitations on specific pins. This function must return
+ *            zero if the function can be assigned to this pin, and
+ *            nonzero otherwise.
+ *            parameter pin: index of the pin in question.
+ *            parameter func: the desired function to use.
+ *            parameter chan: the function channel index to use.
+ *
  * Drivers should embed their ptp_clock_info within a private
  * structure, obtaining a reference to it using container_of().
  *
@@ -83,13 +99,17 @@ struct ptp_clock_info {
        int n_alarm;
        int n_ext_ts;
        int n_per_out;
+       int n_pins;
        int pps;
+       struct ptp_pin_desc *pin_config;
        int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
        int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
        int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts);
        int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts);
        int (*enable)(struct ptp_clock_info *ptp,
                      struct ptp_clock_request *request, int on);
+       int (*verify)(struct ptp_clock_info *ptp, unsigned int pin,
+                     enum ptp_pin_function func, unsigned int chan);
 };
 
 struct ptp_clock;
@@ -156,4 +176,17 @@ extern void ptp_clock_event(struct ptp_clock *ptp,
 
 extern int ptp_clock_index(struct ptp_clock *ptp);
 
+/**
+ * ptp_find_pin() - obtain the pin index of a given auxiliary function
+ *
+ * @ptp:    The clock obtained from ptp_clock_register().
+ * @func:   One of the ptp_pin_function enumerated values.
+ * @chan:   The particular functional channel to find.
+ * Return:  Pin index in the range of zero to ptp_clock_caps.n_pins - 1,
+ *          or -1 if the auxiliary function cannot be found.
+ */
+
+int ptp_find_pin(struct ptp_clock *ptp,
+                enum ptp_pin_function func, unsigned int chan);
+
 #endif
index 1da693d51255d974c60ba4b50527fe3e1808c03d..b66c2110cb1ff045dec9e7b23ba15a142e0f84fb 100644 (file)
@@ -250,8 +250,7 @@ struct rmap_walk_control {
        int (*rmap_one)(struct page *page, struct vm_area_struct *vma,
                                        unsigned long addr, void *arg);
        int (*done)(struct page *page);
-       int (*file_nonlinear)(struct page *, struct address_space *,
-                                       struct vm_area_struct *vma);
+       int (*file_nonlinear)(struct page *, struct address_space *, void *arg);
        struct anon_vma *(*anon_lock)(struct page *page);
        bool (*invalid_vma)(struct vm_area_struct *vma, void *arg);
 };
index 6f19cfd1840e4adea37b84dea76175361d3187bc..4054b0994071cada2d95bdbe0964a3b22cfe2590 100644 (file)
@@ -76,7 +76,6 @@ static inline int seccomp_mode(struct seccomp *s)
 #ifdef CONFIG_SECCOMP_FILTER
 extern void put_seccomp_filter(struct task_struct *tsk);
 extern void get_seccomp_filter(struct task_struct *tsk);
-extern u32 seccomp_bpf_load(int off);
 #else  /* CONFIG_SECCOMP_FILTER */
 static inline void put_seccomp_filter(struct task_struct *tsk)
 {
index 5623a7f965b7bbb07ab94a72351aec027ef4adb7..2fc42d191f79f77236b843a70775129c01207333 100644 (file)
@@ -1040,6 +1040,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Allocate a security structure to the xp->security field; the security
  *     field is initialized to NULL when the xfrm_policy is allocated.
  *     Return 0 if operation was successful (memory to allocate, legal context)
+ *     @gfp is to specify the context for the allocation
  * @xfrm_policy_clone_security:
  *     @old_ctx contains an existing xfrm_sec_ctx.
  *     @new_ctxp contains a new xfrm_sec_ctx being cloned from old.
@@ -1683,7 +1684,7 @@ struct security_operations {
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
        int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp,
-                       struct xfrm_user_sec_ctx *sec_ctx);
+                       struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
        int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
        void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
        int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
@@ -2859,7 +2860,8 @@ static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 
-int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx);
+int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                              struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
 int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp);
 void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
 int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
@@ -2877,7 +2879,9 @@ void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl);
 
 #else  /* CONFIG_SECURITY_NETWORK_XFRM */
 
-static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                                            struct xfrm_user_sec_ctx *sec_ctx,
+                                            gfp_t gfp)
 {
        return 0;
 }
index f589c9af8cbf1250da1945bac436f27d92987e80..18ef0224fb6a353a6cc584c3a4f38d5f1ccc4301 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/hrtimer.h>
 #include <linux/dma-mapping.h>
 #include <linux/netdev_features.h>
+#include <linux/sched.h>
 #include <net/flow_keys.h>
 
 /* A. Checksumming of received packets by device.
@@ -356,11 +357,62 @@ typedef unsigned int sk_buff_data_t;
 typedef unsigned char *sk_buff_data_t;
 #endif
 
+/**
+ * struct skb_mstamp - multi resolution time stamps
+ * @stamp_us: timestamp in us resolution
+ * @stamp_jiffies: timestamp in jiffies
+ */
+struct skb_mstamp {
+       union {
+               u64             v64;
+               struct {
+                       u32     stamp_us;
+                       u32     stamp_jiffies;
+               };
+       };
+};
+
+/**
+ * skb_mstamp_get - get current timestamp
+ * @cl: place to store timestamps
+ */
+static inline void skb_mstamp_get(struct skb_mstamp *cl)
+{
+       u64 val = local_clock();
+
+       do_div(val, NSEC_PER_USEC);
+       cl->stamp_us = (u32)val;
+       cl->stamp_jiffies = (u32)jiffies;
+}
+
+/**
+ * skb_mstamp_delta - compute the difference in usec between two skb_mstamp
+ * @t1: pointer to newest sample
+ * @t0: pointer to oldest sample
+ */
+static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1,
+                                     const struct skb_mstamp *t0)
+{
+       s32 delta_us = t1->stamp_us - t0->stamp_us;
+       u32 delta_jiffies = t1->stamp_jiffies - t0->stamp_jiffies;
+
+       /* If delta_us is negative, this might be because interval is too big,
+        * or local_clock() drift is too big : fallback using jiffies.
+        */
+       if (delta_us <= 0 ||
+           delta_jiffies >= (INT_MAX / (USEC_PER_SEC / HZ)))
+
+               delta_us = jiffies_to_usecs(delta_jiffies);
+
+       return delta_us;
+}
+
+
 /** 
  *     struct sk_buff - socket buffer
  *     @next: Next buffer in list
  *     @prev: Previous buffer in list
- *     @tstamp: Time we arrived
+ *     @tstamp: Time we arrived/left
  *     @sk: Socket we are owned by
  *     @dev: Device we arrived on/are leaving by
  *     @cb: Control buffer. Free for use by every layer. Put private vars here
@@ -392,11 +444,11 @@ typedef unsigned char *sk_buff_data_t;
  *     @skb_iif: ifindex of device we arrived on
  *     @tc_index: Traffic control index
  *     @tc_verd: traffic control verdict
- *     @rxhash: the packet hash computed on receive
+ *     @hash: the packet hash
  *     @queue_mapping: Queue mapping for multiqueue devices
  *     @ndisc_nodetype: router type (from link layer)
  *     @ooo_okay: allow the mapping of a socket to a queue to be changed
- *     @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport
+ *     @l4_hash: indicate hash is a canonical 4-tuple hash over transport
  *             ports.
  *     @wifi_acked_valid: wifi_acked was set
  *     @wifi_acked: whether frame was acked on wifi or not
@@ -429,7 +481,10 @@ struct sk_buff {
        struct sk_buff          *next;
        struct sk_buff          *prev;
 
-       ktime_t                 tstamp;
+       union {
+               ktime_t         tstamp;
+               struct skb_mstamp skb_mstamp;
+       };
 
        struct sock             *sk;
        struct net_device       *dev;
@@ -482,7 +537,7 @@ struct sk_buff {
 
        int                     skb_iif;
 
-       __u32                   rxhash;
+       __u32                   hash;
 
        __be16                  vlan_proto;
        __u16                   vlan_tci;
@@ -501,7 +556,7 @@ struct sk_buff {
 #endif
        __u8                    pfmemalloc:1;
        __u8                    ooo_okay:1;
-       __u8                    l4_rxhash:1;
+       __u8                    l4_hash:1;
        __u8                    wifi_acked_valid:1;
        __u8                    wifi_acked:1;
        __u8                    no_fcs:1;
@@ -691,6 +746,8 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
                                     unsigned int headroom);
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom,
                                int newtailroom, gfp_t priority);
+int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
+                       int offset, int len);
 int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset,
                 int len);
 int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
@@ -758,40 +815,40 @@ enum pkt_hash_types {
 static inline void
 skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
 {
-       skb->l4_rxhash = (type == PKT_HASH_TYPE_L4);
-       skb->rxhash = hash;
+       skb->l4_hash = (type == PKT_HASH_TYPE_L4);
+       skb->hash = hash;
 }
 
 void __skb_get_hash(struct sk_buff *skb);
 static inline __u32 skb_get_hash(struct sk_buff *skb)
 {
-       if (!skb->l4_rxhash)
+       if (!skb->l4_hash)
                __skb_get_hash(skb);
 
-       return skb->rxhash;
+       return skb->hash;
 }
 
 static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
 {
-       return skb->rxhash;
+       return skb->hash;
 }
 
 static inline void skb_clear_hash(struct sk_buff *skb)
 {
-       skb->rxhash = 0;
-       skb->l4_rxhash = 0;
+       skb->hash = 0;
+       skb->l4_hash = 0;
 }
 
 static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
 {
-       if (!skb->l4_rxhash)
+       if (!skb->l4_hash)
                skb_clear_hash(skb);
 }
 
 static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from)
 {
-       to->rxhash = from->rxhash;
-       to->l4_rxhash = from->l4_rxhash;
+       to->hash = from->hash;
+       to->l4_hash = from->l4_hash;
 };
 
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
@@ -2451,8 +2508,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
                    unsigned int flags);
 void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
 unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
-void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
-                 int len, int hlen);
+int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
+                int len, int hlen);
 void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 void skb_scrub_packet(struct sk_buff *skb, bool xnet);
@@ -2725,7 +2782,7 @@ static inline void nf_reset(struct sk_buff *skb)
 
 static inline void nf_reset_trace(struct sk_buff *skb)
 {
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
        skb->nf_trace = 0;
 #endif
 }
@@ -2742,6 +2799,9 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
        dst->nf_bridge  = src->nf_bridge;
        nf_bridge_get(src->nf_bridge);
 #endif
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES)
+       dst->nf_trace = src->nf_trace;
+#endif
 }
 
 static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
@@ -2916,5 +2976,22 @@ static inline bool skb_head_is_locked(const struct sk_buff *skb)
 {
        return !skb->head_frag || skb_cloned(skb);
 }
+
+/**
+ * skb_gso_network_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_network_seglen is used to determine the real size of the
+ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
+ *
+ * The MAC/L2 header is not accounted for.
+ */
+static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
+{
+       unsigned int hdr_len = skb_transport_header(skb) -
+                              skb_network_header(skb);
+       return hdr_len + skb_gso_transport_seglen(skb);
+}
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SKBUFF_H */
index 9260abdd67df801e002f18faf3f17bd00d494867..b5b2df60299e25c5c33b3be39ff90090c974689f 100644 (file)
@@ -410,7 +410,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
  *
  * %GFP_NOWAIT - Allocation will not sleep.
  *
- * %GFP_THISNODE - Allocate node-local memory only.
+ * %__GFP_THISNODE - Allocate node-local memory only.
  *
  * %GFP_DMA - Allocation suitable for DMA.
  *   Should only be used for kmalloc() caches. Otherwise, use a
index 3834f43f9993183cf180d1639d1d9d02c3b2721c..6ae004e437eadade24c8fac3bd6b5efc27c57744 100644 (file)
@@ -188,6 +188,9 @@ static inline void kick_all_cpus_sync(void) {  }
  */
 extern void arch_disable_smp_support(void);
 
+extern void arch_enable_nonboot_cpus_begin(void);
+extern void arch_enable_nonboot_cpus_end(void);
+
 void smp_setup_processor_id(void);
 
 #endif /* __LINUX_SMP_H */
index a1d4ca290862d766d5460f198503ae4530df3f45..4203c66d88033269692fa38ce50aebe17fee9419 100644 (file)
@@ -273,7 +273,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *     message while queuing transfers that arrive in the meantime. When the
  *     driver is finished with this message, it must call
  *     spi_finalize_current_message() so the subsystem can issue the next
- *     transfer
+ *     message
  * @unprepare_transfer_hardware: there are currently no more messages on the
  *     queue so the subsystem notifies the driver that it may relax the
  *     hardware by issuing this call
@@ -287,7 +287,10 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *                  - return 1 if the transfer is still in progress. When
  *                    the driver is finished with this transfer it must
  *                    call spi_finalize_current_transfer() so the subsystem
- *                    can issue the next transfer
+ *                    can issue the next transfer. Note: transfer_one and
+ *                    transfer_one_message are mutually exclusive; when both
+ *                    are set, the generic subsystem does not call your
+ *                    transfer_one callback.
  * @unprepare_message: undo any work done by prepare_message().
  * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
  *     number. Any individual value may be -ENOENT for CS lines that
diff --git a/include/linux/sxgbe_platform.h b/include/linux/sxgbe_platform.h
new file mode 100644 (file)
index 0000000..a62442c
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 10G controller driver for Samsung EXYNOS SoCs
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Siva Reddy Kallam <siva.kallam@samsung.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 __SXGBE_PLATFORM_H__
+#define __SXGBE_PLATFORM_H__
+
+/* MDC Clock Selection define*/
+#define SXGBE_CSR_100_150M     0x0     /* MDC = clk_scr_i/62 */
+#define SXGBE_CSR_150_250M     0x1     /* MDC = clk_scr_i/102 */
+#define SXGBE_CSR_250_300M     0x2     /* MDC = clk_scr_i/122 */
+#define SXGBE_CSR_300_350M     0x3     /* MDC = clk_scr_i/142 */
+#define SXGBE_CSR_350_400M     0x4     /* MDC = clk_scr_i/162 */
+#define SXGBE_CSR_400_500M     0x5     /* MDC = clk_scr_i/202 */
+
+/* Platfrom data for platform device structure's
+ * platform_data field
+ */
+struct sxgbe_mdio_bus_data {
+       unsigned int phy_mask;
+       int *irqs;
+       int probed_phy_irq;
+};
+
+struct sxgbe_dma_cfg {
+       int pbl;
+       int fixed_burst;
+       int burst_map;
+       int adv_addr_mode;
+};
+
+struct sxgbe_plat_data {
+       char *phy_bus_name;
+       int bus_id;
+       int phy_addr;
+       int interface;
+       struct sxgbe_mdio_bus_data *mdio_bus_data;
+       struct sxgbe_dma_cfg *dma_cfg;
+       int clk_csr;
+       int pmt;
+       int force_sf_dma_mode;
+       int force_thresh_dma_mode;
+       int riwt_off;
+};
+
+#endif /* __SXGBE_PLATFORM_H__ */
index 40ed9e9a77e53c77448104a921c0595f2a7927eb..a747a77ea584aafb124ae230862360c8dd0b6073 100644 (file)
@@ -281,13 +281,15 @@ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
 asmlinkage long sys_sched_setparam(pid_t pid,
                                        struct sched_param __user *param);
 asmlinkage long sys_sched_setattr(pid_t pid,
-                                       struct sched_attr __user *attr);
+                                       struct sched_attr __user *attr,
+                                       unsigned int flags);
 asmlinkage long sys_sched_getscheduler(pid_t pid);
 asmlinkage long sys_sched_getparam(pid_t pid,
                                        struct sched_param __user *param);
 asmlinkage long sys_sched_getattr(pid_t pid,
                                        struct sched_attr __user *attr,
-                                       unsigned int size);
+                                       unsigned int size,
+                                       unsigned int flags);
 asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
                                        unsigned long __user *user_mask_ptr);
 asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len,
index 4ad0706d40ebecf98e1ca95483a79f9dd44e903c..239946868142cec2893e89259555d3b86884d616 100644 (file)
@@ -201,10 +201,10 @@ struct tcp_sock {
        u32     tlp_high_seq;   /* snd_nxt at the time of TLP retransmit. */
 
 /* RTT measurement */
-       u32     srtt;           /* smoothed round trip time << 3        */
-       u32     mdev;           /* medium deviation                     */
-       u32     mdev_max;       /* maximal mdev for the last rtt period */
-       u32     rttvar;         /* smoothed mdev_max                    */
+       u32     srtt_us;        /* smoothed round trip time << 3 in usecs */
+       u32     mdev_us;        /* medium deviation                     */
+       u32     mdev_max_us;    /* maximal mdev for the last rtt period */
+       u32     rttvar_us;      /* smoothed mdev_max                    */
        u32     rtt_seq;        /* sequence number to update rttvar     */
 
        u32     packets_out;    /* Packets which are "in flight"        */
index accc497f8d729160b0234756e96d99607cf67f33..7159a0a933df2b016db23cdcd87487c19d5829d0 100644 (file)
@@ -60,6 +60,12 @@ struct tp_module {
        unsigned int num_tracepoints;
        struct tracepoint * const *tracepoints_ptrs;
 };
+bool trace_module_has_bad_taint(struct module *mod);
+#else
+static inline bool trace_module_has_bad_taint(struct module *mod)
+{
+       return false;
+}
 #endif /* CONFIG_MODULES */
 
 struct tracepoint_iter {
index 7bfabd20204c150afa40a7249932519c0e770267..4b4439e75f45f8e915f0ffb6b855be5f1113a04f 100644 (file)
@@ -27,8 +27,8 @@
  *    (On UP, there is no seqcount_t protection, a reader allowing interrupts could
  *     read partial values)
  *
- * 7) For softirq uses, readers can use u64_stats_fetch_begin_bh() and
- *    u64_stats_fetch_retry_bh() helpers
+ * 7) For irq and softirq uses, readers can use u64_stats_fetch_begin_irq() and
+ *    u64_stats_fetch_retry_irq() helpers
  *
  * Usage :
  *
@@ -114,31 +114,31 @@ static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
 }
 
 /*
- * In case softirq handlers can update u64 counters, readers can use following helpers
+ * In case irq handlers can update u64 counters, readers can use following helpers
  * - SMP 32bit arches use seqcount protection, irq safe.
- * - UP 32bit must disable BH.
+ * - UP 32bit must disable irqs.
  * - 64bit have no problem atomically reading u64 values, irq safe.
  */
-static inline unsigned int u64_stats_fetch_begin_bh(const struct u64_stats_sync *syncp)
+static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp)
 {
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
        return read_seqcount_begin(&syncp->seq);
 #else
 #if BITS_PER_LONG==32
-       local_bh_disable();
+       local_irq_disable();
 #endif
        return 0;
 #endif
 }
 
-static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
+static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp,
                                         unsigned int start)
 {
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
        return read_seqcount_retry(&syncp->seq, start);
 #else
 #if BITS_PER_LONG==32
-       local_bh_enable();
+       local_irq_enable();
 #endif
        return false;
 #endif
index c716da18c668fe37c4fe91dde3c6385cc81e2d21..7f6eb859873e4a24bcb5ebf30bf8b4485e61a622 100644 (file)
@@ -1265,8 +1265,6 @@ typedef void (*usb_complete_t)(struct urb *);
  * @sg: scatter gather buffer list, the buffer size of each element in
  *     the list (except the last) must be divisible by the endpoint's
  *     max packet size if no_sg_constraint isn't set in 'struct usb_bus'
- *     (FIXME: scatter-gather under xHCI is broken for periodic transfers.
- *     Do not use urb->sg for interrupt endpoints for now, only bulk.)
  * @num_mapped_sgs: (internal) number of mapped sg entries
  * @num_sgs: number of entries in the sg list
  * @transfer_buffer_length: How big is transfer_buffer.  The transfer may
index c3fa807459967286c0407c18da294ca6d95ced42..44b38b92236a5834f022185e99707ea9ac6edc39 100644 (file)
 #define cdc_ncm_data_intf_is_mbim(x)  ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
 
 struct cdc_ncm_ctx {
+       struct usb_cdc_ncm_ntb_parameters ncm_parm;
        struct hrtimer tx_timer;
        struct tasklet_struct bh;
 
        const struct usb_cdc_ncm_desc *func_desc;
        const struct usb_cdc_mbim_desc *mbim_desc;
+       const struct usb_cdc_mbim_extended_desc *mbim_extended_desc;
        const struct usb_cdc_ether_desc *ether_desc;
 
        struct usb_interface *control;
index e303eef94dd5cea92d16d7ae63aa35f5c3f1d4bb..0662e98fef72b21fdabb7d14ac1fd71f2066a140 100644 (file)
@@ -30,7 +30,7 @@ struct usbnet {
        struct driver_info      *driver_info;
        const char              *driver_name;
        void                    *driver_priv;
-       wait_queue_head_t       *wait;
+       wait_queue_head_t       wait;
        struct mutex            phy_mutex;
        unsigned char           suspend_count;
        unsigned char           pkt_cnt, pkt_err;
index 594521ba0d43f73e887375968006429c9ec19502..704f4f652d0af8b28406154678ee38b5f98298bf 100644 (file)
@@ -419,10 +419,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
        static struct lock_class_key __key;                             \
        const char *__lock_name;                                        \
                                                                        \
-       if (__builtin_constant_p(fmt))                                  \
-               __lock_name = (fmt);                                    \
-       else                                                            \
-               __lock_name = #fmt;                                     \
+       __lock_name = #fmt#args;                                        \
                                                                        \
        __alloc_workqueue_key((fmt), (flags), (max_active),             \
                              &__key, __lock_name, ##args);             \
index fc0e4320aa6d50d0e5f966e3f8b649506d461ac7..021b8a319b9e2cf7f0f60a5f6fedcfe3367f8016 100644 (file)
@@ -97,7 +97,7 @@ void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
 int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
 int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
                                  enum wb_reason reason);
-void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this);
+void sync_inodes_sb(struct super_block *);
 void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
 void inode_wait_for_writeback(struct inode *inode);
 
diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
new file mode 100644 (file)
index 0000000..f7d372b
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Copyright 2011, Siemens AG
+ * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+/*
+ * Based on patches from Jon Smirl <jonsmirl@gmail.com>
+ * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Jon's code is based on 6lowpan implementation for Contiki which is:
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __6LOWPAN_H__
+#define __6LOWPAN_H__
+
+#include <net/ipv6.h>
+
+#define UIP_802154_SHORTADDR_LEN       2  /* compressed ipv6 address length */
+#define UIP_IPH_LEN                    40 /* ipv6 fixed header size */
+#define UIP_PROTO_UDP                  17 /* ipv6 next header value for UDP */
+#define UIP_FRAGH_LEN                  8  /* ipv6 fragment header size */
+
+/*
+ * ipv6 address based on mac
+ * second bit-flip (Universe/Local) is done according RFC2464
+ */
+#define is_addr_mac_addr_based(a, m) \
+       ((((a)->s6_addr[8])  == (((m)[0]) ^ 0x02)) &&   \
+        (((a)->s6_addr[9])  == (m)[1]) &&              \
+        (((a)->s6_addr[10]) == (m)[2]) &&              \
+        (((a)->s6_addr[11]) == (m)[3]) &&              \
+        (((a)->s6_addr[12]) == (m)[4]) &&              \
+        (((a)->s6_addr[13]) == (m)[5]) &&              \
+        (((a)->s6_addr[14]) == (m)[6]) &&              \
+        (((a)->s6_addr[15]) == (m)[7]))
+
+/* ipv6 address is unspecified */
+#define is_addr_unspecified(a)         \
+       ((((a)->s6_addr32[0]) == 0) &&  \
+        (((a)->s6_addr32[1]) == 0) &&  \
+        (((a)->s6_addr32[2]) == 0) &&  \
+        (((a)->s6_addr32[3]) == 0))
+
+/* compare ipv6 addresses prefixes */
+#define ipaddr_prefixcmp(addr1, addr2, length) \
+       (memcmp(addr1, addr2, length >> 3) == 0)
+
+/* local link, i.e. FE80::/10 */
+#define is_addr_link_local(a) (((a)->s6_addr16[0]) == htons(0xFE80))
+
+/*
+ * check whether we can compress the IID to 16 bits,
+ * it's possible for unicast adresses with first 49 bits are zero only.
+ */
+#define lowpan_is_iid_16_bit_compressable(a)   \
+       ((((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr[10]) == 0) &&           \
+        (((a)->s6_addr[11]) == 0xff) &&        \
+        (((a)->s6_addr[12]) == 0xfe) &&        \
+        (((a)->s6_addr[13]) == 0))
+
+/* multicast address */
+#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF)
+
+/* check whether the 112-bit gid of the multicast address is mappable to: */
+
+/* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */
+#define lowpan_is_mcast_addr_compressable(a)   \
+       ((((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr16[5]) == 0) &&          \
+        (((a)->s6_addr16[6]) == 0) &&          \
+        (((a)->s6_addr[14])  == 0) &&          \
+        ((((a)->s6_addr[15]) == 1) || (((a)->s6_addr[15]) == 2)))
+
+/* 48 bits, FFXX::00XX:XXXX:XXXX */
+#define lowpan_is_mcast_addr_compressable48(a) \
+       ((((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr[10]) == 0))
+
+/* 32 bits, FFXX::00XX:XXXX */
+#define lowpan_is_mcast_addr_compressable32(a) \
+       ((((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr16[5]) == 0) &&          \
+        (((a)->s6_addr[12]) == 0))
+
+/* 8 bits, FF02::00XX */
+#define lowpan_is_mcast_addr_compressable8(a)  \
+       ((((a)->s6_addr[1])  == 2) &&           \
+        (((a)->s6_addr16[1]) == 0) &&          \
+        (((a)->s6_addr16[2]) == 0) &&          \
+        (((a)->s6_addr16[3]) == 0) &&          \
+        (((a)->s6_addr16[4]) == 0) &&          \
+        (((a)->s6_addr16[5]) == 0) &&          \
+        (((a)->s6_addr16[6]) == 0) &&          \
+        (((a)->s6_addr[14]) == 0))
+
+#define lowpan_is_addr_broadcast(a)    \
+       ((((a)[0]) == 0xFF) &&  \
+        (((a)[1]) == 0xFF) &&  \
+        (((a)[2]) == 0xFF) &&  \
+        (((a)[3]) == 0xFF) &&  \
+        (((a)[4]) == 0xFF) &&  \
+        (((a)[5]) == 0xFF) &&  \
+        (((a)[6]) == 0xFF) &&  \
+        (((a)[7]) == 0xFF))
+
+#define LOWPAN_DISPATCH_IPV6   0x41 /* 01000001 = 65 */
+#define LOWPAN_DISPATCH_HC1    0x42 /* 01000010 = 66 */
+#define LOWPAN_DISPATCH_IPHC   0x60 /* 011xxxxx = ... */
+#define LOWPAN_DISPATCH_FRAG1  0xc0 /* 11000xxx */
+#define LOWPAN_DISPATCH_FRAGN  0xe0 /* 11100xxx */
+
+#define LOWPAN_DISPATCH_MASK   0xf8 /* 11111000 */
+
+#define LOWPAN_FRAG_TIMEOUT    (HZ * 60)       /* time-out 60 sec */
+
+#define LOWPAN_FRAG1_HEAD_SIZE 0x4
+#define LOWPAN_FRAGN_HEAD_SIZE 0x5
+
+/*
+ * According IEEE802.15.4 standard:
+ *   - MTU is 127 octets
+ *   - maximum MHR size is 37 octets
+ *   - MFR size is 2 octets
+ *
+ * so minimal payload size that we may guarantee is:
+ *   MTU - MHR - MFR = 88 octets
+ */
+#define LOWPAN_FRAG_SIZE       88
+
+/*
+ * Values of fields within the IPHC encoding first byte
+ * (C stands for compressed and I for inline)
+ */
+#define LOWPAN_IPHC_TF         0x18
+
+#define LOWPAN_IPHC_FL_C       0x10
+#define LOWPAN_IPHC_TC_C       0x08
+#define LOWPAN_IPHC_NH_C       0x04
+#define LOWPAN_IPHC_TTL_1      0x01
+#define LOWPAN_IPHC_TTL_64     0x02
+#define LOWPAN_IPHC_TTL_255    0x03
+#define LOWPAN_IPHC_TTL_I      0x00
+
+
+/* Values of fields within the IPHC encoding second byte */
+#define LOWPAN_IPHC_CID                0x80
+
+#define LOWPAN_IPHC_ADDR_00    0x00
+#define LOWPAN_IPHC_ADDR_01    0x01
+#define LOWPAN_IPHC_ADDR_02    0x02
+#define LOWPAN_IPHC_ADDR_03    0x03
+
+#define LOWPAN_IPHC_SAC                0x40
+#define LOWPAN_IPHC_SAM                0x30
+
+#define LOWPAN_IPHC_SAM_BIT    4
+
+#define LOWPAN_IPHC_M          0x08
+#define LOWPAN_IPHC_DAC                0x04
+#define LOWPAN_IPHC_DAM_00     0x00
+#define LOWPAN_IPHC_DAM_01     0x01
+#define LOWPAN_IPHC_DAM_10     0x02
+#define LOWPAN_IPHC_DAM_11     0x03
+
+#define LOWPAN_IPHC_DAM_BIT    0
+/*
+ * LOWPAN_UDP encoding (works together with IPHC)
+ */
+#define LOWPAN_NHC_UDP_MASK            0xF8
+#define LOWPAN_NHC_UDP_ID              0xF0
+#define LOWPAN_NHC_UDP_CHECKSUMC       0x04
+#define LOWPAN_NHC_UDP_CHECKSUMI       0x00
+
+#define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
+#define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
+#define LOWPAN_NHC_UDP_8BIT_PORT       0xF000
+#define LOWPAN_NHC_UDP_8BIT_MASK       0xFF00
+
+/* values for port compression, _with checksum_ ie bit 5 set to 0 */
+#define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
+#define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
+                                       dest = 0xF0 + 8 bit inline */
+#define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline,
+                                       dest = 16 bit inline */
+#define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
+#define LOWPAN_NHC_UDP_CS_C    0x04 /* checksum elided */
+
+#ifdef DEBUG
+/* print data in line */
+static inline void raw_dump_inline(const char *caller, char *msg,
+                                  unsigned char *buf, int len)
+{
+       if (msg)
+               pr_debug("%s():%s: ", caller, msg);
+
+       print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);
+}
+
+/* print data in a table format:
+ *
+ * addr: xx xx xx xx xx xx
+ * addr: xx xx xx xx xx xx
+ * ...
+ */
+static inline void raw_dump_table(const char *caller, char *msg,
+                                 unsigned char *buf, int len)
+{
+       if (msg)
+               pr_debug("%s():%s:\n", caller, msg);
+
+       print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
+}
+#else
+static inline void raw_dump_table(const char *caller, char *msg,
+                                 unsigned char *buf, int len) { }
+static inline void raw_dump_inline(const char *caller, char *msg,
+                                  unsigned char *buf, int len) { }
+#endif
+
+static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
+{
+       if (unlikely(!pskb_may_pull(skb, 1)))
+               return -EINVAL;
+
+       *val = skb->data[0];
+       skb_pull(skb, 1);
+
+       return 0;
+}
+
+static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
+{
+       if (unlikely(!pskb_may_pull(skb, 2)))
+               return -EINVAL;
+
+       *val = (skb->data[0] << 8) | skb->data[1];
+       skb_pull(skb, 2);
+
+       return 0;
+}
+
+static inline bool lowpan_fetch_skb(struct sk_buff *skb,
+               void *data, const unsigned int len)
+{
+       if (unlikely(!pskb_may_pull(skb, len)))
+               return true;
+
+       skb_copy_from_linear_data(skb, data, len);
+       skb_pull(skb, len);
+
+       return false;
+}
+
+static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
+                                      const size_t len)
+{
+       memcpy(*hc_ptr, data, len);
+       *hc_ptr += len;
+}
+
+static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
+{
+       static const u8 addr_sizes[] = {
+               [LOWPAN_IPHC_ADDR_00] = 16,
+               [LOWPAN_IPHC_ADDR_01] = 8,
+               [LOWPAN_IPHC_ADDR_02] = 2,
+               [LOWPAN_IPHC_ADDR_03] = 0,
+       };
+       return addr_sizes[addr_mode];
+}
+
+static inline u8 lowpan_next_hdr_size(const u8 h_enc, u16 *uncomp_header)
+{
+       u8 ret = 1;
+
+       if ((h_enc & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+               *uncomp_header += sizeof(struct udphdr);
+
+               switch (h_enc & LOWPAN_NHC_UDP_CS_P_11) {
+               case LOWPAN_NHC_UDP_CS_P_00:
+                       ret += 4;
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_01:
+               case LOWPAN_NHC_UDP_CS_P_10:
+                       ret += 3;
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_11:
+                       ret++;
+                       break;
+               default:
+                       break;
+               }
+
+               if (!(h_enc & LOWPAN_NHC_UDP_CS_C))
+                       ret += 2;
+       }
+
+       return ret;
+}
+
+/**
+ *     lowpan_uncompress_size - returns skb->len size with uncompressed header
+ *     @skb: sk_buff with 6lowpan header inside
+ *     @datagram_offset: optional to get the datagram_offset value
+ *
+ *     Returns the skb->len with uncompressed header
+ */
+static inline u16
+lowpan_uncompress_size(const struct sk_buff *skb, u16 *dgram_offset)
+{
+       u16 ret = 2, uncomp_header = sizeof(struct ipv6hdr);
+       u8 iphc0, iphc1, h_enc;
+
+       iphc0 = skb_network_header(skb)[0];
+       iphc1 = skb_network_header(skb)[1];
+
+       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+       case 0:
+               ret += 4;
+               break;
+       case 1:
+               ret += 3;
+               break;
+       case 2:
+               ret++;
+               break;
+       default:
+               break;
+       }
+
+       if (!(iphc0 & LOWPAN_IPHC_NH_C))
+               ret++;
+
+       if (!(iphc0 & 0x03))
+               ret++;
+
+       ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_SAM) >>
+                                    LOWPAN_IPHC_SAM_BIT);
+
+       if (iphc1 & LOWPAN_IPHC_M) {
+               switch ((iphc1 & LOWPAN_IPHC_DAM_11) >>
+                       LOWPAN_IPHC_DAM_BIT) {
+               case LOWPAN_IPHC_DAM_00:
+                       ret += 16;
+                       break;
+               case LOWPAN_IPHC_DAM_01:
+                       ret += 6;
+                       break;
+               case LOWPAN_IPHC_DAM_10:
+                       ret += 4;
+                       break;
+               case LOWPAN_IPHC_DAM_11:
+                       ret++;
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_DAM_11) >>
+                                            LOWPAN_IPHC_DAM_BIT);
+       }
+
+       if (iphc0 & LOWPAN_IPHC_NH_C) {
+               h_enc = skb_network_header(skb)[ret];
+               ret += lowpan_next_hdr_size(h_enc, &uncomp_header);
+       }
+
+       if (dgram_offset)
+               *dgram_offset = uncomp_header;
+
+       return skb->len + uncomp_header - ret;
+}
+
+typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
+
+int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
+               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
+               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
+               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
+int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type, const void *_daddr,
+                       const void *_saddr, unsigned int len);
+
+#endif /* __6LOWPAN_H__ */
index 788d8378e587f00bbf2a61bd39665370b17f7a41..3ee4c92afd1bd2baf2b90201a9b4af896d020b5f 100644 (file)
@@ -89,7 +89,7 @@ struct tc_action_ops {
        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);
-       int     (*cleanup)(struct tc_action *, int bind);
+       void    (*cleanup)(struct tc_action *, int bind);
        int     (*lookup)(struct tc_action *, u32);
        int     (*init)(struct net *net, struct nlattr *nla,
                        struct nlattr *est, struct tc_action *act, int ovr,
@@ -98,20 +98,18 @@ struct tc_action_ops {
 };
 
 int tcf_hash_search(struct tc_action *a, u32 index);
-void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo);
-int tcf_hash_release(struct tcf_common *p, int bind,
-                    struct tcf_hashinfo *hinfo);
+void tcf_hash_destroy(struct tc_action *a);
+int tcf_hash_release(struct tc_action *a, int bind);
 u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
-struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a,
-                                 int bind);
-struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
-                                  struct tc_action *a, int size,
-                                  int bind);
-void tcf_hash_insert(struct tcf_common *p, 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);
+void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
+void tcf_hash_insert(struct tc_action *a);
 
-int tcf_register_action(struct tc_action_ops *a);
+int tcf_register_action(struct tc_action_ops *a, unsigned int mask);
 int tcf_unregister_action(struct tc_action_ops *a);
-void tcf_action_destroy(struct list_head *actions, int bind);
+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);
 int tcf_action_init(struct net *net, struct nlattr *nla,
index 50e39a8822b49ab5ce6b16b5e17c5e875e5d1abe..933a9f22a05ff63abb4379f94cb907c95f6beac4 100644 (file)
@@ -314,7 +314,7 @@ static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr)
 static inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
 {
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
-       __u64 *p = (__u64 *)addr;
+       __be64 *p = (__be64 *)addr;
        return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(1))) == 0UL;
 #else
        return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
@@ -326,7 +326,7 @@ static inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr)
 static inline bool ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
 {
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
-       __u64 *p = (__u64 *)addr;
+       __be64 *p = (__be64 *)addr;
        return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(2))) == 0UL;
 #else
        return ((addr->s6_addr32[0] ^ htonl(0xff020000)) |
@@ -343,7 +343,7 @@ static inline bool ipv6_addr_is_isatap(const struct in6_addr *addr)
 static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
 {
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64
-       __u64 *p = (__u64 *)addr;
+       __be64 *p = (__be64 *)addr;
        return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) |
                ((p[1] ^ cpu_to_be64(0x00000001ff000000UL)) &
                 cpu_to_be64(0xffffffffff000000UL))) == 0UL;
index 75e64c7a2960a17a0f3c7f6ce62553c6c874f0c9..f79ae2aa76d6a45fb9a1e452d53f82d05e101717 100644 (file)
@@ -36,7 +36,7 @@ enum {
 /* address length, octets */
 #define IEEE802154_ADDR_LEN    8
 
-struct ieee802154_addr {
+struct ieee802154_addr_sa {
        int addr_type;
        u16 pan_id;
        union {
@@ -51,7 +51,7 @@ struct ieee802154_addr {
 
 struct sockaddr_ieee802154 {
        sa_family_t family; /* AF_IEEE802154 */
-       struct ieee802154_addr addr;
+       struct ieee802154_addr_sa addr;
 };
 
 /* get/setsockopt */
index 37a0e24adbe72a995e341c1c0113fbed0c5fd69b..a28f4e0f625193b0682932207a46578f094f52a9 100644 (file)
@@ -69,6 +69,19 @@ static inline __wsum csum_sub(__wsum csum, __wsum addend)
        return csum_add(csum, ~addend);
 }
 
+static inline __sum16 csum16_add(__sum16 csum, __be16 addend)
+{
+       u16 res = (__force u16)csum;
+
+       res += (__force u16)addend;
+       return (__force __sum16)(res + (res < (__force u16)addend));
+}
+
+static inline __sum16 csum16_sub(__sum16 csum, __be16 addend)
+{
+       return csum16_add(csum, ~addend);
+}
+
 static inline __wsum
 csum_block_add(__wsum csum, __wsum csum2, int offset)
 {
@@ -112,9 +125,15 @@ static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
        *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum)));
 }
 
-static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
+/* Implements RFC 1624 (Incremental Internet Checksum)
+ * 3. Discussion states :
+ *     HC' = ~(~HC + ~m + m')
+ *  m : old value of a 16bit field
+ *  m' : new value of a 16bit field
+ */
+static inline void csum_replace2(__sum16 *sum, __be16 old, __be16 new)
 {
-       csum_replace4(sum, (__force __be32)from, (__force __be32)to);
+       *sum = ~csum16_add(csum16_sub(~(*sum), old), new);
 }
 
 struct sk_buff;
index deb7ca75db488f94b0c697cbdfa1946c3263b63b..93cb18f729b5bac2185990b3eb36cbe5a1d74144 100644 (file)
@@ -15,4 +15,6 @@ struct datalink_proto {
        struct list_head node;
 };
 
+struct datalink_proto *make_EII_client(void);
+void destroy_EII_client(struct datalink_proto *dl);
 #endif
index ccc15588d108ecc2a33d5b2544b8e0e1feb33069..913b73d239f54a11b87e7b304e0cea825fc7e416 100644 (file)
@@ -200,6 +200,8 @@ static inline void dn_sk_ports_copy(struct flowidn *fld, struct dn_scp *scp)
 }
 
 unsigned int dn_mss_from_pmtu(struct net_device *dev, int mtu);
+void dn_register_sysctl(void);
+void dn_unregister_sysctl(void);
 
 #define DN_MENUVER_ACC 0x01
 #define DN_MENUVER_USR 0x02
index b409ad6b8d7adbb5bd25ad3b71cbea5c8723b70e..55df9939bca268106384d10d330615ae091d3aea 100644 (file)
@@ -20,6 +20,8 @@ int dn_route_output_sock(struct dst_entry __rcu **pprt, struct flowidn *,
                         struct sock *sk, int flags);
 int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
 void dn_rt_cache_flush(int delay);
+int dn_route_rcv(struct sk_buff *skb, struct net_device *dev,
+                struct packet_type *pt, struct net_device *orig_dev);
 
 /* Masks for flags field */
 #define DN_RT_F_PID 0x07 /* Mask for packet type                      */
index 77eb53fabfb00d6e446d89066937621b22c68e44..46ed958e0c6ef2ffc7142a3739c985382f9a97cf 100644 (file)
@@ -54,10 +54,9 @@ struct dst_entry {
 #define DST_NOHASH             0x0008
 #define DST_NOCACHE            0x0010
 #define DST_NOCOUNT            0x0020
-#define DST_NOPEER             0x0040
-#define DST_FAKE_RTABLE                0x0080
-#define DST_XFRM_TUNNEL                0x0100
-#define DST_XFRM_QUEUE         0x0200
+#define DST_FAKE_RTABLE                0x0040
+#define DST_XFRM_TUNNEL                0x0080
+#define DST_XFRM_QUEUE         0x0100
 
        unsigned short          pending_confirm;
 
@@ -109,9 +108,11 @@ struct dst_entry {
 u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
 extern const u32 dst_default_metrics[];
 
-#define DST_METRICS_READ_ONLY  0x1UL
+#define DST_METRICS_READ_ONLY          0x1UL
+#define DST_METRICS_FORCE_OVERWRITE    0x2UL
+#define DST_METRICS_FLAGS              0x3UL
 #define __DST_METRICS_PTR(Y)   \
-       ((u32 *)((Y) & ~DST_METRICS_READ_ONLY))
+       ((u32 *)((Y) & ~DST_METRICS_FLAGS))
 #define DST_METRICS_PTR(X)     __DST_METRICS_PTR((X)->_metrics)
 
 static inline bool dst_metrics_read_only(const struct dst_entry *dst)
@@ -119,6 +120,11 @@ static inline bool dst_metrics_read_only(const struct dst_entry *dst)
        return dst->_metrics & DST_METRICS_READ_ONLY;
 }
 
+static inline void dst_metrics_set_force_overwrite(struct dst_entry *dst)
+{
+       dst->_metrics |= DST_METRICS_FORCE_OVERWRITE;
+}
+
 void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old);
 
 static inline void dst_destroy_metrics_generic(struct dst_entry *dst)
index 96f3789b27bcc88ac38c0b433d1d81c1e8a3a82b..2a2d6bb34eb8b5923ca8b951f2a5e10acd99be40 100644 (file)
@@ -16,6 +16,7 @@
 struct ethoc_platform_data {
        u8 hwaddr[IFHWADDRLEN];
        s8 phy_id;
+       u32 eth_clkfreq;
 };
 
 #endif /* !LINUX_NET_ETHOC_H */
index d23e7fa2042e0dd79b9d23867d5237f164ff3782..64fd24836650b7ea14a5c6ba8278066bbb21bf0d 100644 (file)
@@ -218,9 +218,11 @@ struct flow_cache_object *flow_cache_lookup(struct net *net,
                                            const struct flowi *key, u16 family,
                                            u8 dir, flow_resolve_t resolver,
                                            void *ctx);
+int flow_cache_init(struct net *net);
+void flow_cache_fini(struct net *net);
 
-void flow_cache_flush(void);
-void flow_cache_flush_deferred(void);
+void flow_cache_flush(struct net *net);
+void flow_cache_flush_deferred(struct net *net);
 extern atomic_t flow_cache_genid;
 
 #endif
diff --git a/include/net/flowcache.h b/include/net/flowcache.h
new file mode 100644 (file)
index 0000000..c8f665e
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _NET_FLOWCACHE_H
+#define _NET_FLOWCACHE_H
+
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/notifier.h>
+
+struct flow_cache_percpu {
+       struct hlist_head               *hash_table;
+       int                             hash_count;
+       u32                             hash_rnd;
+       int                             hash_rnd_recalc;
+       struct tasklet_struct           flush_tasklet;
+};
+
+struct flow_cache {
+       u32                             hash_shift;
+       struct flow_cache_percpu __percpu *percpu;
+       struct notifier_block           hotcpu_notifier;
+       int                             low_watermark;
+       int                             high_watermark;
+       struct timer_list               rnd_timer;
+};
+#endif /* _NET_FLOWCACHE_H */
index ee59f8b188ddfb081c948b27f54ac73839a9d2ef..c7ae0ac528dc1e5e1d3c2d5456c2d0e5221b6933 100644 (file)
            (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \
        } while (0)
 
-#define IEEE802154_FC_SECEN            (1 << 3)
-#define IEEE802154_FC_FRPEND           (1 << 4)
-#define IEEE802154_FC_ACK_REQ          (1 << 5)
-#define IEEE802154_FC_INTRA_PAN                (1 << 6)
+#define IEEE802154_FC_SECEN_SHIFT      3
+#define IEEE802154_FC_SECEN            (1 << IEEE802154_FC_SECEN_SHIFT)
+#define IEEE802154_FC_FRPEND_SHIFT     4
+#define IEEE802154_FC_FRPEND           (1 << IEEE802154_FC_FRPEND_SHIFT)
+#define IEEE802154_FC_ACK_REQ_SHIFT    5
+#define IEEE802154_FC_ACK_REQ          (1 << IEEE802154_FC_ACK_REQ_SHIFT)
+#define IEEE802154_FC_INTRA_PAN_SHIFT  6
+#define IEEE802154_FC_INTRA_PAN                (1 << IEEE802154_FC_INTRA_PAN_SHIFT)
 
 #define IEEE802154_FC_SAMODE_SHIFT     14
 #define IEEE802154_FC_SAMODE_MASK      (3 << IEEE802154_FC_SAMODE_SHIFT)
 #define IEEE802154_FC_DAMODE_SHIFT     10
 #define IEEE802154_FC_DAMODE_MASK      (3 << IEEE802154_FC_DAMODE_SHIFT)
 
+#define IEEE802154_FC_VERSION_SHIFT    12
+#define IEEE802154_FC_VERSION_MASK     (3 << IEEE802154_FC_VERSION_SHIFT)
+#define IEEE802154_FC_VERSION(x)       ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT)
+
 #define IEEE802154_FC_SAMODE(x)                \
        (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT)
 
 #define IEEE802154_FC_DAMODE(x)                \
        (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT)
 
+#define IEEE802154_SCF_SECLEVEL_MASK           7
+#define IEEE802154_SCF_SECLEVEL_SHIFT          0
+#define IEEE802154_SCF_SECLEVEL(x)             (x & IEEE802154_SCF_SECLEVEL_MASK)
+#define IEEE802154_SCF_KEY_ID_MODE_SHIFT       3
+#define IEEE802154_SCF_KEY_ID_MODE_MASK                (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT)
+#define IEEE802154_SCF_KEY_ID_MODE(x)          \
+       ((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT)
+
+#define IEEE802154_SCF_KEY_IMPLICIT            0
+#define IEEE802154_SCF_KEY_INDEX               1
+#define IEEE802154_SCF_KEY_SHORT_INDEX         2
+#define IEEE802154_SCF_KEY_HW_INDEX            3
 
 /* MAC footer size */
 #define IEEE802154_MFR_SIZE    2 /* 2 octets */
index 8196d5d4035970849c4caba4ee0c2c0928ec24a0..e1717cbf609b67d6761dc68ed9d8a40a202bbfb3 100644 (file)
 #define IEEE802154_NETDEVICE_H
 
 #include <net/af_ieee802154.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+struct ieee802154_sechdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u8 level:3,
+          key_id_mode:2,
+          reserved:3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       u8 reserved:3,
+          key_id_mode:2,
+          level:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+       u8 key_id;
+       __le32 frame_counter;
+       union {
+               __le32 short_src;
+               __le64 extended_src;
+       };
+};
+
+struct ieee802154_addr {
+       u8 mode;
+       __le16 pan_id;
+       union {
+               __le16 short_addr;
+               __le64 extended_addr;
+       };
+};
+
+struct ieee802154_hdr_fc {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       u16 type:3,
+           security_enabled:1,
+           frame_pending:1,
+           ack_request:1,
+           intra_pan:1,
+           reserved:3,
+           dest_addr_mode:2,
+           version:2,
+           source_addr_mode:2;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+       u16 reserved:1,
+           intra_pan:1,
+           ack_request:1,
+           frame_pending:1,
+           security_enabled:1,
+           type:3,
+           source_addr_mode:2,
+           version:2,
+           dest_addr_mode:2,
+           reserved2:2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+};
+
+struct ieee802154_hdr {
+       struct ieee802154_hdr_fc fc;
+       u8 seq;
+       struct ieee802154_addr source;
+       struct ieee802154_addr dest;
+       struct ieee802154_sechdr sec;
+};
+
+/* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
+ * the contents of hdr will be, and the actual value of those bits in
+ * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
+ * version, if SECEN is set.
+ */
+int ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr);
+
+/* pulls the entire 802.15.4 header off of the skb, including the security
+ * header, and performs pan id decompression
+ */
+int ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr);
+
+/* parses the frame control, sequence number of address fields in a given skb
+ * and stores them into hdr, performing pan id decompression and length checks
+ * to be suitable for use in header_ops.parse
+ */
+int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
+                             struct ieee802154_hdr *hdr);
+
+static inline int ieee802154_hdr_length(struct sk_buff *skb)
+{
+       struct ieee802154_hdr hdr;
+       int len = ieee802154_hdr_pull(skb, &hdr);
+
+       if (len > 0)
+               skb_push(skb, len);
+
+       return len;
+}
+
+static inline bool ieee802154_addr_equal(const struct ieee802154_addr *a1,
+                                        const struct ieee802154_addr *a2)
+{
+       if (a1->pan_id != a2->pan_id || a1->mode != a2->mode)
+               return false;
+
+       if ((a1->mode == IEEE802154_ADDR_LONG &&
+            a1->extended_addr != a2->extended_addr) ||
+           (a1->mode == IEEE802154_ADDR_SHORT &&
+            a1->short_addr != a2->short_addr))
+               return false;
+
+       return true;
+}
+
+static inline __le64 ieee802154_devaddr_from_raw(const void *raw)
+{
+       u64 temp;
+
+       memcpy(&temp, raw, IEEE802154_ADDR_LEN);
+       return (__force __le64)swab64(temp);
+}
+
+static inline void ieee802154_devaddr_to_raw(void *raw, __le64 addr)
+{
+       u64 temp = swab64((__force u64)addr);
+
+       memcpy(raw, &temp, IEEE802154_ADDR_LEN);
+}
+
+static inline void ieee802154_addr_from_sa(struct ieee802154_addr *a,
+                                          const struct ieee802154_addr_sa *sa)
+{
+       a->mode = sa->addr_type;
+       a->pan_id = cpu_to_le16(sa->pan_id);
+
+       switch (a->mode) {
+       case IEEE802154_ADDR_SHORT:
+               a->short_addr = cpu_to_le16(sa->short_addr);
+               break;
+       case IEEE802154_ADDR_LONG:
+               a->extended_addr = ieee802154_devaddr_from_raw(sa->hwaddr);
+               break;
+       }
+}
+
+static inline void ieee802154_addr_to_sa(struct ieee802154_addr_sa *sa,
+                                        const struct ieee802154_addr *a)
+{
+       sa->addr_type = a->mode;
+       sa->pan_id = le16_to_cpu(a->pan_id);
+
+       switch (a->mode) {
+       case IEEE802154_ADDR_SHORT:
+               sa->short_addr = le16_to_cpu(a->short_addr);
+               break;
+       case IEEE802154_ADDR_LONG:
+               ieee802154_devaddr_to_raw(sa->hwaddr, a->extended_addr);
+               break;
+       }
+}
 
 /*
  * A control block of skb passed between the ARPHRD_IEEE802154 device
  */
 struct ieee802154_mac_cb {
        u8 lqi;
-       struct ieee802154_addr sa;
-       struct ieee802154_addr da;
        u8 flags;
        u8 seq;
+       struct ieee802154_addr source;
+       struct ieee802154_addr dest;
 };
 
 static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
@@ -50,23 +208,17 @@ static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
 
 #define MAC_CB_FLAG_ACKREQ             (1 << 3)
 #define MAC_CB_FLAG_SECEN              (1 << 4)
-#define MAC_CB_FLAG_INTRAPAN           (1 << 5)
 
-static inline int mac_cb_is_ackreq(struct sk_buff *skb)
+static inline bool mac_cb_is_ackreq(struct sk_buff *skb)
 {
        return mac_cb(skb)->flags & MAC_CB_FLAG_ACKREQ;
 }
 
-static inline int mac_cb_is_secen(struct sk_buff *skb)
+static inline bool mac_cb_is_secen(struct sk_buff *skb)
 {
        return mac_cb(skb)->flags & MAC_CB_FLAG_SECEN;
 }
 
-static inline int mac_cb_is_intrapan(struct sk_buff *skb)
-{
-       return mac_cb(skb)->flags & MAC_CB_FLAG_INTRAPAN;
-}
-
 static inline int mac_cb_type(struct sk_buff *skb)
 {
        return mac_cb(skb)->flags & MAC_CB_FLAG_TYPEMASK;
@@ -92,7 +244,7 @@ struct ieee802154_mlme_ops {
                        u8 channel, u8 page, u8 cap);
        int (*assoc_resp)(struct net_device *dev,
                        struct ieee802154_addr *addr,
-                       u16 short_addr, u8 status);
+                       __le16 short_addr, u8 status);
        int (*disassoc_req)(struct net_device *dev,
                        struct ieee802154_addr *addr,
                        u8 reason);
@@ -111,8 +263,8 @@ struct ieee802154_mlme_ops {
         * FIXME: these should become the part of PIB/MIB interface.
         * However we still don't have IB interface of any kind
         */
-       u16 (*get_pan_id)(const struct net_device *dev);
-       u16 (*get_short_addr)(const struct net_device *dev);
+       __le16 (*get_pan_id)(const struct net_device *dev);
+       __le16 (*get_short_addr)(const struct net_device *dev);
        u8 (*get_dsn)(const struct net_device *dev);
 };
 
index 9650a3ffd2d2328f11859adc4a3169ae41b25442..b4956a5fcc3f117e9e4199a5ad7af94894fea859 100644 (file)
 #define IF_PREFIX_AUTOCONF     0x02
 
 enum {
+       INET6_IFADDR_STATE_PREDAD,
        INET6_IFADDR_STATE_DAD,
        INET6_IFADDR_STATE_POSTDAD,
+       INET6_IFADDR_STATE_ERRDAD,
        INET6_IFADDR_STATE_UP,
        INET6_IFADDR_STATE_DEAD,
 };
@@ -58,7 +60,7 @@ struct inet6_ifaddr {
        unsigned long           cstamp; /* created timestamp */
        unsigned long           tstamp; /* updated timestamp */
 
-       struct timer_list       dad_timer;
+       struct delayed_work     dad_work;
 
        struct inet6_dev        *idev;
        struct rt6_info         *rt;
index 23be0fd37937ebabfbab8a38864381d0f2d6ff31..25064c28e059e2e42d46dcaf3209a2ff517a7a82 100644 (file)
@@ -187,6 +187,7 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
 #define NET_INC_STATS(net, field)      SNMP_INC_STATS((net)->mib.net_statistics, field)
 #define NET_INC_STATS_BH(net, field)   SNMP_INC_STATS_BH((net)->mib.net_statistics, field)
 #define NET_INC_STATS_USER(net, field)         SNMP_INC_STATS_USER((net)->mib.net_statistics, field)
+#define NET_ADD_STATS(net, field, adnd)        SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd)
 #define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd)
 #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd)
 
@@ -266,7 +267,8 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
 
 static inline bool ip_sk_accept_pmtu(const struct sock *sk)
 {
-       return inet_sk(sk)->pmtudisc != IP_PMTUDISC_INTERFACE;
+       return inet_sk(sk)->pmtudisc != IP_PMTUDISC_INTERFACE &&
+              inet_sk(sk)->pmtudisc != IP_PMTUDISC_OMIT;
 }
 
 static inline bool ip_sk_use_pmtu(const struct sock *sk)
@@ -274,6 +276,12 @@ static inline bool ip_sk_use_pmtu(const struct sock *sk)
        return inet_sk(sk)->pmtudisc < IP_PMTUDISC_PROBE;
 }
 
+static inline bool ip_sk_local_df(const struct sock *sk)
+{
+       return inet_sk(sk)->pmtudisc < IP_PMTUDISC_DO ||
+              inet_sk(sk)->pmtudisc == IP_PMTUDISC_OMIT;
+}
+
 static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
                                                    bool forwarding)
 {
@@ -489,7 +497,8 @@ int ip_options_rcv_srr(struct sk_buff *skb);
 
 void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
-int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc);
+int ip_cmsg_send(struct net *net, struct msghdr *msg,
+                struct ipcm_cookie *ipc, bool allow_ipv6);
 int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                  unsigned int optlen);
 int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
index aca0c2709fd6b9771a743810e5078ead2659bd4f..9bcb220bd4ad13538ed0ee2d51546b1463cd116b 100644 (file)
@@ -284,7 +284,8 @@ struct fib6_node *fib6_locate(struct fib6_node *root,
 void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
                    void *arg);
 
-int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info);
+int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,
+            struct nlattr *mx, int mx_len);
 
 int fib6_del(struct rt6_info *rt, struct nl_info *info);
 
index 017badb1aec7e8648a6f71d473862b730a78b4e8..00e3f12cb2f94dfd0755581f6c48bc165a469588 100644 (file)
@@ -171,7 +171,14 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb)
 
 static inline bool ip6_sk_accept_pmtu(const struct sock *sk)
 {
-       return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE;
+       return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE &&
+              inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_OMIT;
+}
+
+static inline bool ip6_sk_local_df(const struct sock *sk)
+{
+       return inet6_sk(sk)->pmtudisc < IPV6_PMTUDISC_DO ||
+              inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT;
 }
 
 static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt)
index 48ed75c21260b8dd17e681021311bb8dae4f2617..e77c10405d515da16071461fe9f7385d8ac08556 100644 (file)
@@ -129,6 +129,7 @@ int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[],
 int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
                      struct ip_tunnel_parm *p);
 void ip_tunnel_setup(struct net_device *dev, int net_id);
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t);
 
 /* Extract dsfield from inner protocol */
 static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
index 9e9e35465bafbaff131c893814abd44d99be712f..0143180fecc983a01fd5c1c3027f984d0f0be177 100644 (file)
@@ -140,6 +140,17 @@ static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
 }
 
 void ipxitf_down(struct ipx_interface *intrfc);
+struct ipx_interface *ipxitf_find_using_net(__be32 net);
+int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node);
+__be16 ipx_cksum(struct ipxhdr *packet, int length);
+int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
+                    unsigned char *node);
+void ipxrtr_del_routes(struct ipx_interface *intrfc);
+int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
+                       struct iovec *iov, size_t len, int noblock);
+int ipxrtr_route_skb(struct sk_buff *skb);
+struct ipx_route *ipxrtr_lookup(__be32 net);
+int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
 
 static __inline__ void ipxitf_put(struct ipx_interface *intrfc)
 {
index 807d6b7a943fecab78db1afd6b57ee33b70ded72..a591053cae6305c399eabb745c6f1764c41bc8be 100644 (file)
@@ -20,6 +20,7 @@
 #define NET_MAC802154_H
 
 #include <net/af_ieee802154.h>
+#include <linux/skbuff.h>
 
 /* General MAC frame format:
  *  2 bytes: Frame Control
@@ -50,7 +51,7 @@ struct ieee802154_hw_addr_filt {
                                 * devices across independent networks.
                                 */
        __le16  short_addr;
-       u8      ieee_addr[IEEE802154_ADDR_LEN];
+       __le64  ieee_addr;
        u8      pan_coord;
 };
 
@@ -113,6 +114,32 @@ struct ieee802154_dev {
  *       Set radio for listening on specific address.
  *       Set the device for listening on specified address.
  *       Returns either zero, or negative errno.
+ *
+ * set_txpower:
+ *       Set radio transmit power in dB. Called with pib_lock held.
+ *       Returns either zero, or negative errno.
+ *
+ * set_lbt
+ *       Enables or disables listen before talk on the device. Called with
+ *       pib_lock held.
+ *       Returns either zero, or negative errno.
+ *
+ * set_cca_mode
+ *       Sets the CCA mode used by the device. Called with pib_lock held.
+ *       Returns either zero, or negative errno.
+ *
+ * set_cca_ed_level
+ *       Sets the CCA energy detection threshold in dBm. Called with pib_lock
+ *       held.
+ *       Returns either zero, or negative errno.
+ *
+ * set_csma_params
+ *       Sets the CSMA parameter set for the PHY. Called with pib_lock held.
+ *       Returns either zero, or negative errno.
+ *
+ * set_frame_retries
+ *       Sets the retransmission attempt limit. Called with pib_lock held.
+ *       Returns either zero, or negative errno.
  */
 struct ieee802154_ops {
        struct module   *owner;
@@ -127,8 +154,16 @@ struct ieee802154_ops {
        int             (*set_hw_addr_filt)(struct ieee802154_dev *dev,
                                          struct ieee802154_hw_addr_filt *filt,
                                            unsigned long changed);
-       int             (*ieee_addr)(struct ieee802154_dev *dev,
-                                    u8 addr[IEEE802154_ADDR_LEN]);
+       int             (*ieee_addr)(struct ieee802154_dev *dev, __le64 addr);
+       int             (*set_txpower)(struct ieee802154_dev *dev, int db);
+       int             (*set_lbt)(struct ieee802154_dev *dev, bool on);
+       int             (*set_cca_mode)(struct ieee802154_dev *dev, u8 mode);
+       int             (*set_cca_ed_level)(struct ieee802154_dev *dev,
+                                           s32 level);
+       int             (*set_csma_params)(struct ieee802154_dev *dev,
+                                          u8 min_be, u8 max_be, u8 retries);
+       int             (*set_frame_retries)(struct ieee802154_dev *dev,
+                                            s8 retries);
 };
 
 /* Basic interface to register ieee802154 device */
index da68c9a90ac56932638feca9cdbba6a61b75ba64..79387f73f87585101ff44f548c5db299ae0b574c 100644 (file)
@@ -15,6 +15,7 @@
 #include <net/netns/packet.h>
 #include <net/netns/ipv4.h>
 #include <net/netns/ipv6.h>
+#include <net/netns/ieee802154_6lowpan.h>
 #include <net/netns/sctp.h>
 #include <net/netns/dccp.h>
 #include <net/netns/netfilter.h>
@@ -90,6 +91,9 @@ struct net {
 #if IS_ENABLED(CONFIG_IPV6)
        struct netns_ipv6       ipv6;
 #endif
+#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN)
+       struct netns_ieee802154_lowpan  ieee802154_lowpan;
+#endif
 #if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
        struct netns_sctp       sctp;
 #endif
@@ -162,6 +166,14 @@ extern struct list_head net_namespace_list;
 struct net *get_net_ns_by_pid(pid_t pid);
 struct net *get_net_ns_by_fd(int pid);
 
+#ifdef CONFIG_SYSCTL
+void ipx_register_sysctl(void);
+void ipx_unregister_sysctl(void);
+#else
+#define ipx_register_sysctl()
+#define ipx_unregister_sysctl()
+#endif
+
 #ifdef CONFIG_NET_NS
 void __put_net(struct net *net);
 
index 01ea6eed1bb1ddcc9b8c9001286ae85730bea416..37252f71a38037d0e969699dc7376e6dcae1c5ec 100644 (file)
@@ -73,10 +73,17 @@ struct nf_conn_help {
 
 struct nf_conn {
        /* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
-           plus 1 for any connection(s) we are `master' for */
+        * plus 1 for any connection(s) we are `master' for
+        *
+        * Hint, SKB address this struct and refcnt via skb->nfct and
+        * helpers nf_conntrack_get() and nf_conntrack_put().
+        * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt,
+        * beware nf_ct_get() is different and don't inc refcnt.
+        */
        struct nf_conntrack ct_general;
 
-       spinlock_t lock;
+       spinlock_t      lock;
+       u16             cpu;
 
        /* XXX should I move this to the tail ? - Y.K */
        /* These are my tuples; original and reply */
@@ -284,6 +291,8 @@ extern unsigned int nf_conntrack_max;
 extern unsigned int nf_conntrack_hash_rnd;
 void init_nf_conntrack_hash_rnd(void);
 
+void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl);
+
 #define NF_CT_STAT_INC(net, count)       __this_cpu_inc((net)->ct.stat->count)
 #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count)
 
index 15308b8eb5b5218330c3043c46a02537d00779a2..cc0c1882760270f21bd1cc7080cece06afd518d8 100644 (file)
@@ -77,6 +77,13 @@ print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
             const struct nf_conntrack_l3proto *l3proto,
             const struct nf_conntrack_l4proto *proto);
 
-extern spinlock_t nf_conntrack_lock ;
+#ifdef CONFIG_LOCKDEP
+# define CONNTRACK_LOCKS 8
+#else
+# define CONNTRACK_LOCKS 1024
+#endif
+extern spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS];
+
+extern spinlock_t nf_conntrack_expect_lock;
 
 #endif /* _NF_CONNTRACK_CORE_H */
index c985695283b3a34d5d78aa99b062ab4dfb839c18..dec6336bf850f77928f54f4cd04d37b3ebe3e16a 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <uapi/linux/netfilter/xt_connlabel.h>
 
+#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
+
 struct nf_conn_labels {
        u8 words;
        unsigned long bits[];
@@ -29,7 +31,7 @@ static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct)
        u8 words;
 
        words = ACCESS_ONCE(net->ct.label_words);
-       if (words == 0 || WARN_ON_ONCE(words > 8))
+       if (words == 0)
                return NULL;
 
        cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS,
index 57c8ff7955dfbd109e8ac2c731d595539220b3d4..e6bc14d8fa9a9a4b324fac9df5a47e64277f2aa8 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <linux/netfilter.h>
+#include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netlink.h>
@@ -252,6 +253,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
  *     @owner: module reference
  *     @policy: netlink attribute policy
  *     @maxattr: highest netlink attribute number
+ *     @family: address family for AF-specific types
  */
 struct nft_expr_type {
        const struct nft_expr_ops       *(*select_ops)(const struct nft_ctx *,
@@ -262,6 +264,7 @@ struct nft_expr_type {
        struct module                   *owner;
        const struct nla_policy         *policy;
        unsigned int                    maxattr;
+       u8                              family;
 };
 
 /**
@@ -286,7 +289,8 @@ struct nft_expr_ops {
        int                             (*init)(const struct nft_ctx *ctx,
                                                const struct nft_expr *expr,
                                                const struct nlattr * const tb[]);
-       void                            (*destroy)(const struct nft_expr *expr);
+       void                            (*destroy)(const struct nft_ctx *ctx,
+                                                  const struct nft_expr *expr);
        int                             (*dump)(struct sk_buff *skb,
                                                const struct nft_expr *expr);
        int                             (*validate)(const struct nft_ctx *ctx,
@@ -320,18 +324,18 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
  *     struct nft_rule - nf_tables rule
  *
  *     @list: used internally
- *     @rcu_head: used internally for rcu
  *     @handle: rule handle
  *     @genmask: generation mask
  *     @dlen: length of expression data
+ *     @ulen: length of user data (used for comments)
  *     @data: expression data
  */
 struct nft_rule {
        struct list_head                list;
-       struct rcu_head                 rcu_head;
-       u64                             handle:46,
+       u64                             handle:42,
                                        genmask:2,
-                                       dlen:16;
+                                       dlen:12,
+                                       ulen:8;
        unsigned char                   data[]
                __attribute__((aligned(__alignof__(struct nft_expr))));
 };
@@ -340,19 +344,13 @@ struct nft_rule {
  *     struct nft_rule_trans - nf_tables rule update in transaction
  *
  *     @list: used internally
+ *     @ctx: rule context
  *     @rule: rule that needs to be updated
- *     @chain: chain that this rule belongs to
- *     @table: table for which this chain applies
- *     @nlh: netlink header of the message that contain this update
- *     @family: family expressesed as AF_*
  */
 struct nft_rule_trans {
        struct list_head                list;
+       struct nft_ctx                  ctx;
        struct nft_rule                 *rule;
-       const struct nft_chain          *chain;
-       const struct nft_table          *table;
-       const struct nlmsghdr           *nlh;
-       u8                              family;
 };
 
 static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule)
@@ -370,6 +368,11 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule)
        return (struct nft_expr *)&rule->data[rule->dlen];
 }
 
+static inline void *nft_userdata(const struct nft_rule *rule)
+{
+       return (void *)&rule->data[rule->dlen];
+}
+
 /*
  * The last pointer isn't really necessary, but the compiler isn't able to
  * determine that the result of nft_expr_last() is always the same since it
@@ -389,7 +392,6 @@ enum nft_chain_flags {
  *
  *     @rules: list of rules in the chain
  *     @list: used internally
- *     @rcu_head: used internally
  *     @net: net namespace that this chain belongs to
  *     @table: table that this chain belongs to
  *     @handle: chain handle
@@ -401,7 +403,6 @@ enum nft_chain_flags {
 struct nft_chain {
        struct list_head                rules;
        struct list_head                list;
-       struct rcu_head                 rcu_head;
        struct net                      *net;
        struct nft_table                *table;
        u64                             handle;
@@ -523,12 +524,18 @@ void nft_unregister_chain_type(const struct nf_chain_type *);
 int nft_register_expr(struct nft_expr_type *);
 void nft_unregister_expr(struct nft_expr_type *);
 
+#define nft_dereference(p)                                     \
+       nfnl_dereference(p, NFNL_SUBSYS_NFTABLES)
+
 #define MODULE_ALIAS_NFT_FAMILY(family)        \
        MODULE_ALIAS("nft-afinfo-" __stringify(family))
 
 #define MODULE_ALIAS_NFT_CHAIN(family, name) \
        MODULE_ALIAS("nft-chain-" __stringify(family) "-" name)
 
+#define MODULE_ALIAS_NFT_AF_EXPR(family, name) \
+       MODULE_ALIAS("nft-expr-" __stringify(family) "-" name)
+
 #define MODULE_ALIAS_NFT_EXPR(name) \
        MODULE_ALIAS("nft-expr-" name)
 
diff --git a/include/net/netfilter/nft_reject.h b/include/net/netfilter/nft_reject.h
new file mode 100644 (file)
index 0000000..36b0da2
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _NFT_REJECT_H_
+#define _NFT_REJECT_H_
+
+struct nft_reject {
+       enum nft_reject_types   type:8;
+       u8                      icmp_code;
+};
+
+extern const struct nla_policy nft_reject_policy[];
+
+int nft_reject_init(const struct nft_ctx *ctx,
+                   const struct nft_expr *expr,
+                   const struct nlattr * const tb[]);
+
+int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr);
+
+void nft_reject_ipv4_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt);
+
+void nft_reject_ipv6_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt);
+
+#endif
index fbcc7fa536dc4ab49440d4566e63fedf8b860d2a..773cce308bc61ce312c4a5ecab0464ba84e1ce41 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/list_nulls.h>
 #include <linux/atomic.h>
 #include <linux/netfilter/nf_conntrack_tcp.h>
+#include <linux/seqlock.h>
 
 struct ctl_table_header;
 struct nf_conntrack_ecache;
@@ -62,6 +63,13 @@ struct nf_ip_net {
 #endif
 };
 
+struct ct_pcpu {
+       spinlock_t              lock;
+       struct hlist_nulls_head unconfirmed;
+       struct hlist_nulls_head dying;
+       struct hlist_nulls_head tmpl;
+};
+
 struct netns_ct {
        atomic_t                count;
        unsigned int            expect_count;
@@ -83,12 +91,11 @@ struct netns_ct {
        int                     sysctl_checksum;
 
        unsigned int            htable_size;
+       seqcount_t              generation;
        struct kmem_cache       *nf_conntrack_cachep;
        struct hlist_nulls_head *hash;
        struct hlist_head       *expect_hash;
-       struct hlist_nulls_head unconfirmed;
-       struct hlist_nulls_head dying;
-       struct hlist_nulls_head tmpl;
+       struct ct_pcpu __percpu *pcpu_lists;
        struct ip_conntrack_stat __percpu *stat;
        struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
        struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
diff --git a/include/net/netns/ieee802154_6lowpan.h b/include/net/netns/ieee802154_6lowpan.h
new file mode 100644 (file)
index 0000000..079030c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * ieee802154 6lowpan in net namespaces
+ */
+
+#include <net/inet_frag.h>
+
+#ifndef __NETNS_IEEE802154_6LOWPAN_H__
+#define __NETNS_IEEE802154_6LOWPAN_H__
+
+struct netns_sysctl_lowpan {
+#ifdef CONFIG_SYSCTL
+       struct ctl_table_header *frags_hdr;
+#endif
+};
+
+struct netns_ieee802154_lowpan {
+       struct netns_sysctl_lowpan sysctl;
+       struct netns_frags      frags;
+       u16                     max_dsize;
+};
+
+#endif
index 1006a265beb393a0ab917eb8315f0fb258c39e0a..3492434baf88e9dffb3da763de75db36480d9eb9 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/workqueue.h>
 #include <linux/xfrm.h>
 #include <net/dst_ops.h>
+#include <net/flowcache.h>
 
 struct ctl_table_header;
 
@@ -58,9 +59,17 @@ struct netns_xfrm {
        struct dst_ops          xfrm6_dst_ops;
 #endif
        spinlock_t xfrm_state_lock;
-       spinlock_t xfrm_policy_sk_bundle_lock;
        rwlock_t xfrm_policy_lock;
        struct mutex xfrm_cfg_mutex;
+
+       /* flow cache part */
+       struct flow_cache       flow_cache_global;
+       atomic_t                flow_cache_genid;
+       struct list_head        flow_cache_gc_list;
+       spinlock_t              flow_cache_gc_lock;
+       struct work_struct      flow_cache_gc_work;
+       struct work_struct      flow_cache_flush_work;
+       struct mutex            flow_flush_sem;
 };
 
 #endif
index 99d2ba1c7e03f76d7a92e95691fb002535de52eb..b23548e0409848530b1c7f94fb805601c46e583c 100644 (file)
@@ -52,7 +52,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
  * Note: This is in section 7.3.2 of the IEEE 802.15.4 document.
  */
 int ieee802154_nl_assoc_confirm(struct net_device *dev,
-               u16 short_addr, u8 status);
+               __le16 short_addr, u8 status);
 
 /**
  * ieee802154_nl_disassoc_indic - Notify userland of disassociation.
@@ -111,8 +111,8 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
  * Note: This API cannot indicate a beacon frame for a coordinator
  *       operating in long addressing mode.
  */
-int ieee802154_nl_beacon_indic(struct net_device *dev, u16 panid,
-               u16 coord_addr);
+int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
+               __le16 coord_addr);
 
 /**
  * ieee802154_nl_start_confirm - Notify userland of completion of start.
index 9d1f423d5944bc3908bf68e64aae7f259ff7fdb0..b17cf28f996e6ab3cee2b73b6747eafde6f02380 100644 (file)
@@ -191,7 +191,6 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
 void ip_rt_multicast_event(struct in_device *);
 int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
 void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
-int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb);
 
 struct in_ifaddr;
 void fib_add_ifaddr(struct in_ifaddr *);
index 661e45d3805173b119c3fdbfe477922528172562..72240e5ac2c4b2223e9e1706c81974f11d7eafc6 100644 (file)
@@ -140,7 +140,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname,
                                    struct nlattr *tb[]);
 int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm);
 
-extern const struct nla_policy ifla_policy[IFLA_MAX+1];
+int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len);
 
 #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
 
index d992ca3145fec9826c1df1cf0affc95272a6af25..6ee76c804893fc9f291a469550b2356fe1b93c39 100644 (file)
@@ -1653,17 +1653,6 @@ struct sctp_association {
        /* This is the last advertised value of rwnd over a SACK chunk. */
        __u32 a_rwnd;
 
-       /* Number of bytes by which the rwnd has slopped.  The rwnd is allowed
-        * to slop over a maximum of the association's frag_point.
-        */
-       __u32 rwnd_over;
-
-       /* Keeps treack of rwnd pressure.  This happens when we have
-        * a window, but not recevie buffer (i.e small packets).  This one
-        * is releases slowly (1 PMTU at a time ).
-        */
-       __u32 rwnd_press;
-
        /* This is the sndbuf size in use for the association.
         * This corresponds to the sndbuf size for the association,
         * as specified in the sk->sndbuf.
@@ -1892,8 +1881,7 @@ void sctp_assoc_update(struct sctp_association *old,
 __u32 sctp_association_get_next_tsn(struct sctp_association *);
 
 void sctp_assoc_sync_pmtu(struct sock *, struct sctp_association *);
-void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int);
-void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int);
+void sctp_assoc_rwnd_update(struct sctp_association *, bool);
 void sctp_assoc_set_primary(struct sctp_association *,
                            struct sctp_transport *);
 void sctp_assoc_del_nonprimary_peers(struct sctp_association *,
index 5c3f7c3624aa00214572c47cd3b6dbb3777d93ee..06a5668f05c984526c4ce2455aff825e2aaa9836 100644 (file)
@@ -862,9 +862,9 @@ static inline void sock_rps_save_rxhash(struct sock *sk,
                                        const struct sk_buff *skb)
 {
 #ifdef CONFIG_RPS
-       if (unlikely(sk->sk_rxhash != skb->rxhash)) {
+       if (unlikely(sk->sk_rxhash != skb->hash)) {
                sock_rps_reset_flow(sk);
-               sk->sk_rxhash = skb->rxhash;
+               sk->sk_rxhash = skb->hash;
        }
 #endif
 }
@@ -1488,6 +1488,11 @@ static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
  */
 #define sock_owned_by_user(sk) ((sk)->sk_lock.owned)
 
+static inline void sock_release_ownership(struct sock *sk)
+{
+       sk->sk_lock.owned = 0;
+}
+
 /*
  * Macro so as to not evaluate some arguments when
  * lockdep is not enabled.
@@ -1616,33 +1621,6 @@ void sk_common_release(struct sock *sk);
 /* Initialise core socket variables */
 void sock_init_data(struct socket *sock, struct sock *sk);
 
-void sk_filter_release_rcu(struct rcu_head *rcu);
-
-/**
- *     sk_filter_release - release a socket filter
- *     @fp: filter to remove
- *
- *     Remove a filter from a socket and release its resources.
- */
-
-static inline void sk_filter_release(struct sk_filter *fp)
-{
-       if (atomic_dec_and_test(&fp->refcnt))
-               call_rcu(&fp->rcu, sk_filter_release_rcu);
-}
-
-static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
-{
-       atomic_sub(sk_filter_size(fp->len), &sk->sk_omem_alloc);
-       sk_filter_release(fp);
-}
-
-static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
-{
-       atomic_inc(&fp->refcnt);
-       atomic_add(sk_filter_size(fp->len), &sk->sk_omem_alloc);
-}
-
 /*
  * Socket reference counting postulates.
  *
@@ -2186,7 +2164,6 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
 {
 #define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL)                      | \
                           (1UL << SOCK_RCVTSTAMP)                      | \
-                          (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)       | \
                           (1UL << SOCK_TIMESTAMPING_SOFTWARE)          | \
                           (1UL << SOCK_TIMESTAMPING_RAW_HARDWARE)      | \
                           (1UL << SOCK_TIMESTAMPING_SYS_HARDWARE))
@@ -2252,8 +2229,12 @@ void sock_net_set(struct sock *sk, struct net *net)
  */
 static inline void sk_change_net(struct sock *sk, struct net *net)
 {
-       put_net(sock_net(sk));
-       sock_net_set(sk, hold_net(net));
+       struct net *current_net = sock_net(sk);
+
+       if (!net_eq(current_net, net)) {
+               put_net(current_net);
+               sock_net_set(sk, hold_net(net));
+       }
 }
 
 static inline struct sock *skb_steal_sock(struct sk_buff *skb)
index 9e8710be7a04f0d43cd8358bd07208e5a6adb14a..fa8f5fac65e959bff4458cd3e7cce6005bd08533 100644 (file)
@@ -9,7 +9,7 @@ struct tcf_csum {
 
        u32 update_flags;
 };
-#define to_tcf_csum(pc) \
-       container_of(pc,struct tcf_csum,common)
+#define to_tcf_csum(a) \
+       container_of(a->priv,struct tcf_csum,common)
 
 #endif /* __NET_TC_CSUM_H */
index 65f024b809589bc638de15053257d31da5b206cc..9763dcbb9bc3e594c61b62504917e3a3185d1caa 100644 (file)
@@ -8,7 +8,7 @@ struct tcf_defact {
        u32                     tcfd_datalen;
        void                    *tcfd_defdata;
 };
-#define to_defact(pc) \
-       container_of(pc, struct tcf_defact, common)
+#define to_defact(a) \
+       container_of(a->priv, struct tcf_defact, common)
 
 #endif /* __NET_TC_DEF_H */
index 9e3f6767b80e5de5213a8a9b74ae6f4446021046..9fc9b578908ab868dcc0ef5986358ccb603bf5f9 100644 (file)
@@ -11,7 +11,7 @@ struct tcf_gact {
         int                    tcfg_paction;
 #endif
 };
-#define to_gact(pc) \
-       container_of(pc, struct tcf_gact, common)
+#define to_gact(a) \
+       container_of(a->priv, struct tcf_gact, common)
 
 #endif /* __NET_TC_GACT_H */
index f7d25dfcc4b78c011acbb6044b38e4af8f8438d9..c0f4193f432c20d67234c6198ce7c6cb0a4933ac 100644 (file)
@@ -11,7 +11,7 @@ struct tcf_ipt {
        char                    *tcfi_tname;
        struct xt_entry_target  *tcfi_t;
 };
-#define to_ipt(pc) \
-       container_of(pc, struct tcf_ipt, common)
+#define to_ipt(a) \
+       container_of(a->priv, struct tcf_ipt, common)
 
 #endif /* __NET_TC_IPT_H */
index cfe2943690ff298cd3e938ecef2ddb8d49dfc229..4dd77a1c106b246b0abc9d8af3d6dc67fa748b5c 100644 (file)
@@ -11,7 +11,7 @@ struct tcf_mirred {
        struct net_device       *tcfm_dev;
        struct list_head        tcfm_list;
 };
-#define to_mirred(pc) \
-       container_of(pc, struct tcf_mirred, common)
+#define to_mirred(a) \
+       container_of(a->priv, struct tcf_mirred, common)
 
 #endif /* __NET_TC_MIR_H */
index 4a691f34d7035c2eea28a941cf701c82832d7050..63d8e9ca9d99e0bef223973a48d24229689de27e 100644 (file)
@@ -13,9 +13,9 @@ struct tcf_nat {
        u32 flags;
 };
 
-static inline struct tcf_nat *to_tcf_nat(struct tcf_common *pc)
+static inline struct tcf_nat *to_tcf_nat(struct tc_action *a)
 {
-       return container_of(pc, struct tcf_nat, common);
+       return container_of(a->priv, struct tcf_nat, common);
 }
 
 #endif /* __NET_TC_NAT_H */
index e6f6e15956f5fb9dfb5fcbd446fc3d60ed7f4ec1..5b80998879c7cf6c0bf7df280556de05b5831260 100644 (file)
@@ -9,7 +9,7 @@ struct tcf_pedit {
        unsigned char           tcfp_flags;
        struct tc_pedit_key     *tcfp_keys;
 };
-#define to_pedit(pc) \
-       container_of(pc, struct tcf_pedit, common)
+#define to_pedit(a) \
+       container_of(a->priv, struct tcf_pedit, common)
 
 #endif /* __NET_TC_PED_H */
index dd5d86fab030c8fb8d16d6acad7eefebcab375b9..0df9a0db4a8e4ac300fcbafdd505f05ffd320782 100644 (file)
@@ -29,7 +29,7 @@ struct tcf_skbedit {
        u16                     queue_mapping;
        /* XXX: 16-bit pad here? */
 };
-#define to_skbedit(pc) \
-       container_of(pc, struct tcf_skbedit, common)
+#define to_skbedit(a) \
+       container_of(a->priv, struct tcf_skbedit, common)
 
 #endif /* __NET_TC_SKBEDIT_H */
index 56fc366da6d5183b536648e949769a118ba33677..87d87740818867b8b50074c8a5634658be46199c 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/crypto.h>
 #include <linux/cryptohash.h>
 #include <linux/kref.h>
+#include <linux/ktime.h>
 
 #include <net/inet_connection_sock.h>
 #include <net/inet_timewait_sock.h>
@@ -478,22 +479,22 @@ int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th,
 struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
                             struct ip_options *opt);
 #ifdef CONFIG_SYN_COOKIES
-#include <linux/ktime.h>
 
-/* Syncookies use a monotonic timer which increments every 64 seconds.
+/* Syncookies use a monotonic timer which increments every 60 seconds.
  * This counter is used both as a hash input and partially encoded into
  * the cookie value.  A cookie is only validated further if the delta
  * between the current counter value and the encoded one is less than this,
- * i.e. a sent cookie is valid only at most for 128 seconds (or less if
+ * i.e. a sent cookie is valid only at most for 2*60 seconds (or less if
  * the counter advances immediately after a cookie is generated).
  */
 #define MAX_SYNCOOKIE_AGE 2
 
 static inline u32 tcp_cookie_time(void)
 {
-       struct timespec now;
-       getnstimeofday(&now);
-       return now.tv_sec >> 6; /* 64 seconds granularity */
+       u64 val = get_jiffies_64();
+
+       do_div(val, 60 * HZ);
+       return val;
 }
 
 u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th,
@@ -619,7 +620,7 @@ static inline void tcp_bound_rto(const struct sock *sk)
 
 static inline u32 __tcp_set_rto(const struct tcp_sock *tp)
 {
-       return (tp->srtt >> 3) + tp->rttvar;
+       return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us);
 }
 
 static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd)
@@ -656,6 +657,11 @@ static inline u32 tcp_rto_min(struct sock *sk)
        return rto_min;
 }
 
+static inline u32 tcp_rto_min_us(struct sock *sk)
+{
+       return jiffies_to_usecs(tcp_rto_min(sk));
+}
+
 /* Compute the actual receive window we are currently advertising.
  * Rcv_nxt can be after the window if our peer push more data
  * than the offered window.
@@ -778,7 +784,6 @@ enum tcp_ca_event {
 #define TCP_CA_BUF_MAX (TCP_CA_NAME_MAX*TCP_CA_MAX)
 
 #define TCP_CONG_NON_RESTRICTED 0x1
-#define TCP_CONG_RTT_STAMP     0x2
 
 struct tcp_congestion_ops {
        struct list_head        list;
@@ -791,8 +796,6 @@ struct tcp_congestion_ops {
 
        /* return slow start threshold (required) */
        u32 (*ssthresh)(struct sock *sk);
-       /* lower bound for congestion window (optional) */
-       u32 (*min_cwnd)(const struct sock *sk);
        /* do new cwnd calculation (required) */
        void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked, u32 in_flight);
        /* call before changing ca_state (optional) */
@@ -827,7 +830,6 @@ void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w);
 extern struct tcp_congestion_ops tcp_init_congestion_ops;
 u32 tcp_reno_ssthresh(struct sock *sk);
 void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight);
-u32 tcp_reno_min_cwnd(const struct sock *sk);
 extern struct tcp_congestion_ops tcp_reno;
 
 static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state)
@@ -1303,7 +1305,8 @@ struct tcp_fastopen_request {
        /* Fast Open cookie. Size 0 means a cookie request */
        struct tcp_fastopen_cookie      cookie;
        struct msghdr                   *data;  /* data in MSG_FASTOPEN */
-       u16                             copied; /* queued in tcp_connect() */
+       size_t                          size;
+       int                             copied; /* queued in tcp_connect() */
 };
 void tcp_free_fastopen_req(struct tcp_sock *tp);
 
index b52bda8d13b183a953b88cb90700a1ee8cf08e23..10ab0fc6d4f79a8a608d0ce642aae294636dcecc 100644 (file)
@@ -37,15 +37,22 @@ struct wpan_phy {
        struct mutex pib_lock;
 
        /*
-        * This is a PIB according to 802.15.4-2006.
+        * This is a PIB according to 802.15.4-2011.
         * We do not provide timing-related variables, as they
         * aren't used outside of driver
         */
        u8 current_channel;
        u8 current_page;
        u32 channels_supported[32];
-       u8 transmit_power;
+       s8 transmit_power;
        u8 cca_mode;
+       u8 min_be;
+       u8 max_be;
+       u8 csma_retries;
+       s8 frame_retries;
+
+       bool lbt;
+       s32 cca_ed_level;
 
        struct device dev;
        int idx;
@@ -54,6 +61,14 @@ struct wpan_phy {
                                        const char *name, int type);
        void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
 
+       int (*set_txpower)(struct wpan_phy *phy, int db);
+       int (*set_lbt)(struct wpan_phy *phy, bool on);
+       int (*set_cca_mode)(struct wpan_phy *phy, u8 cca_mode);
+       int (*set_cca_ed_level)(struct wpan_phy *phy, int level);
+       int (*set_csma_params)(struct wpan_phy *phy, u8 min_be, u8 max_be,
+                              u8 retries);
+       int (*set_frame_retries)(struct wpan_phy *phy, s8 retries);
+
        char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
 
index afa5730fb3bd2ff810f63f861f1b52b29e34c965..32682ae47b3fe6d88e7750120089efc791b38894 100644 (file)
 struct xfrm_state_walk {
        struct list_head        all;
        u8                      state;
-       union {
-               u8              dying;
-               u8              proto;
-       };
+       u8                      dying;
+       u8                      proto;
        u32                     seq;
+       struct xfrm_address_filter *filter;
 };
 
 /* Full description of state of transformer. */
@@ -350,6 +349,16 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo);
 struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family);
 void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
+struct xfrm_input_afinfo {
+       unsigned int            family;
+       struct module           *owner;
+       int                     (*callback)(struct sk_buff *skb, u8 protocol,
+                                           int err);
+};
+
+int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo);
+int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo);
+
 void xfrm_state_delete_tunnel(struct xfrm_state *x);
 
 struct xfrm_type {
@@ -594,21 +603,33 @@ struct xfrm_mgr {
                                           const struct xfrm_migrate *m,
                                           int num_bundles,
                                           const struct xfrm_kmaddress *k);
+       bool                    (*is_alive)(const struct km_event *c);
 };
 
 int xfrm_register_km(struct xfrm_mgr *km);
 int xfrm_unregister_km(struct xfrm_mgr *km);
 
+struct xfrm_tunnel_skb_cb {
+       union {
+               struct inet_skb_parm h4;
+               struct inet6_skb_parm h6;
+       } header;
+
+       union {
+               struct ip_tunnel *ip4;
+               struct ip6_tnl *ip6;
+       } tunnel;
+};
+
+#define XFRM_TUNNEL_SKB_CB(__skb) ((struct xfrm_tunnel_skb_cb *)&((__skb)->cb[0]))
+
 /*
  * This structure is used for the duration where packets are being
  * transformed by IPsec.  As soon as the packet leaves IPsec the
  * area beyond the generic IP part may be overwritten.
  */
 struct xfrm_skb_cb {
-       union {
-               struct inet_skb_parm h4;
-               struct inet6_skb_parm h6;
-        } header;
+       struct xfrm_tunnel_skb_cb header;
 
         /* Sequence number for replay protection. */
        union {
@@ -630,10 +651,7 @@ struct xfrm_skb_cb {
  * to transmit header information to the mode input/output functions.
  */
 struct xfrm_mode_skb_cb {
-       union {
-               struct inet_skb_parm h4;
-               struct inet6_skb_parm h6;
-       } header;
+       struct xfrm_tunnel_skb_cb header;
 
        /* Copied from header for IPv4, always set to zero and DF for IPv6. */
        __be16 id;
@@ -665,10 +683,7 @@ struct xfrm_mode_skb_cb {
  * related information.
  */
 struct xfrm_spi_skb_cb {
-       union {
-               struct inet_skb_parm h4;
-               struct inet6_skb_parm h6;
-       } header;
+       struct xfrm_tunnel_skb_cb header;
 
        unsigned int daddroff;
        unsigned int family;
@@ -1347,18 +1362,34 @@ struct xfrm_algo_desc {
        struct sadb_alg desc;
 };
 
-/* XFRM tunnel handlers.  */
-struct xfrm_tunnel {
+/* XFRM protocol handlers.  */
+struct xfrm4_protocol {
        int (*handler)(struct sk_buff *skb);
+       int (*input_handler)(struct sk_buff *skb, int nexthdr, __be32 spi,
+                            int encap_type);
+       int (*cb_handler)(struct sk_buff *skb, int err);
        int (*err_handler)(struct sk_buff *skb, u32 info);
 
-       struct xfrm_tunnel __rcu *next;
+       struct xfrm4_protocol __rcu *next;
+       int priority;
+};
+
+struct xfrm6_protocol {
+       int (*handler)(struct sk_buff *skb);
+       int (*cb_handler)(struct sk_buff *skb, int err);
+       int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                          u8 type, u8 code, int offset, __be32 info);
+
+       struct xfrm6_protocol __rcu *next;
        int priority;
 };
 
-struct xfrm_tunnel_notifier {
+/* XFRM tunnel handlers.  */
+struct xfrm_tunnel {
        int (*handler)(struct sk_buff *skb);
-       struct xfrm_tunnel_notifier __rcu *next;
+       int (*err_handler)(struct sk_buff *skb, u32 info);
+
+       struct xfrm_tunnel __rcu *next;
        int priority;
 };
 
@@ -1375,11 +1406,14 @@ void xfrm4_init(void);
 int xfrm_state_init(struct net *net);
 void xfrm_state_fini(struct net *net);
 void xfrm4_state_init(void);
+void xfrm4_protocol_init(void);
 #ifdef CONFIG_XFRM
 int xfrm6_init(void);
 void xfrm6_fini(void);
 int xfrm6_state_init(void);
 void xfrm6_state_fini(void);
+int xfrm6_protocol_init(void);
+void xfrm6_protocol_fini(void);
 #else
 static inline int xfrm6_init(void)
 {
@@ -1405,7 +1439,8 @@ static inline void xfrm_sysctl_fini(struct net *net)
 }
 #endif
 
-void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto);
+void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto,
+                         struct xfrm_address_filter *filter);
 int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
                    int (*func)(struct xfrm_state *, int, void*), void *);
 void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net);
@@ -1497,20 +1532,22 @@ int xfrm4_rcv(struct sk_buff *skb);
 
 static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
 {
-       return xfrm4_rcv_encap(skb, nexthdr, spi, 0);
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
+       XFRM_SPI_SKB_CB(skb)->family = AF_INET;
+       XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
+       return xfrm_input(skb, nexthdr, spi, 0);
 }
 
 int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_output(struct sk_buff *skb);
 int xfrm4_output_finish(struct sk_buff *skb);
+int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err);
+int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
+int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol);
 int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family);
 int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family);
 void xfrm4_local_error(struct sk_buff *skb, u32 mtu);
-int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler);
-int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler);
-int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler);
-int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler);
 int xfrm6_extract_header(struct sk_buff *skb);
 int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi);
@@ -1519,6 +1556,9 @@ int xfrm6_rcv(struct sk_buff *skb);
 int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
                     xfrm_address_t *saddr, u8 proto);
 void xfrm6_local_error(struct sk_buff *skb, u32 mtu);
+int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err);
+int xfrm6_protocol_register(struct xfrm6_protocol *handler, unsigned char protocol);
+int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, unsigned char protocol);
 int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
 int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
 __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
@@ -1646,8 +1686,27 @@ static inline int xfrm_aevent_is_on(struct net *net)
        rcu_read_unlock();
        return ret;
 }
+
+static inline int xfrm_acquire_is_on(struct net *net)
+{
+       struct sock *nlsk;
+       int ret = 0;
+
+       rcu_read_lock();
+       nlsk = rcu_dereference(net->xfrm.nlsk);
+       if (nlsk)
+               ret = netlink_has_listeners(nlsk, XFRMNLGRP_ACQUIRE);
+       rcu_read_unlock();
+
+       return ret;
+}
 #endif
 
+static inline int aead_len(struct xfrm_algo_aead *alg)
+{
+       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
+}
+
 static inline int xfrm_alg_len(const struct xfrm_algo *alg)
 {
        return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
@@ -1686,6 +1745,12 @@ static inline int xfrm_replay_clone(struct xfrm_state *x,
        return 0;
 }
 
+static inline struct xfrm_algo_aead *xfrm_algo_aead_clone(struct xfrm_algo_aead *orig)
+{
+       return kmemdup(orig, aead_len(orig), GFP_KERNEL);
+}
+
+
 static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig)
 {
        return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL);
@@ -1737,4 +1802,24 @@ static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m)
        return ret;
 }
 
+static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x,
+                                   unsigned int family)
+{
+       bool tunnel = false;
+
+       switch(family) {
+       case AF_INET:
+               if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4)
+                       tunnel = true;
+               break;
+       case AF_INET6:
+               if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6)
+                       tunnel = true;
+               break;
+       }
+       if (tunnel && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL))
+               return -EINVAL;
+
+       return 0;
+}
 #endif /* _NET_XFRM_H */
index 8d4a1c06f7e4e9bb14c28992afbb37128fe31b56..6793f32ccb581f4313d052d7a228a0e7852e0973 100644 (file)
@@ -226,7 +226,8 @@ enum ib_port_cap_flags {
        IB_PORT_CAP_MASK_NOTICE_SUP             = 1 << 22,
        IB_PORT_BOOT_MGMT_SUP                   = 1 << 23,
        IB_PORT_LINK_LATENCY_SUP                = 1 << 24,
-       IB_PORT_CLIENT_REG_SUP                  = 1 << 25
+       IB_PORT_CLIENT_REG_SUP                  = 1 << 25,
+       IB_PORT_IP_BASED_GIDS                   = 1 << 26
 };
 
 enum ib_port_width {
index 68d92e36facda52f6e4b249e108bd43c8847e92e..6e89ef6c11c1a42c853a8f87021bbf1244a14ffc 100644 (file)
@@ -449,14 +449,22 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
                            const char *pin);
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                    const char *pin);
 int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
                             const char *pin);
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                     const char *pin);
 int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                const char *pin);
 int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
                                const char *pin);
 int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
                                  const char *pin);
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                          const char *pin);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin);
 void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
index ae5a17111968c7ca8bc8667a65d16393532ffbde..4483fadfa68d8fdc744743d6bc5bcd52de301608 100644 (file)
@@ -12,6 +12,7 @@ struct iscsit_transport {
        int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
        int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
        void (*iscsit_free_np)(struct iscsi_np *);
+       void (*iscsit_wait_conn)(struct iscsi_conn *);
        void (*iscsit_free_conn)(struct iscsi_conn *);
        int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
        int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
index c9c791209cd18e579c5477b6b1cbe195cba744a0..1772fadcff62aaa8ab1e3ab2b4a7aef15de87fa7 100644 (file)
@@ -525,7 +525,6 @@ struct se_cmd {
 #define CMD_T_COMPLETE         (1 << 2)
 #define CMD_T_SENT             (1 << 4)
 #define CMD_T_STOP             (1 << 5)
-#define CMD_T_FAILED           (1 << 6)
 #define CMD_T_DEV_ACTIVE       (1 << 7)
 #define CMD_T_REQUEST_STOP     (1 << 8)
 #define CMD_T_BUSY             (1 << 9)
index a34f27b2e394ef1ebdb7148b69ac573df85b6502..1de256b358074b6b3486e4e1b4686f9ecace6320 100644 (file)
@@ -153,8 +153,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,
                __field(        u16,                    vlan_tci        )
                __field(        u16,                    protocol        )
                __field(        u8,                     ip_summed       )
-               __field(        u32,                    rxhash          )
-               __field(        bool,                   l4_rxhash       )
+               __field(        u32,                    hash            )
+               __field(        bool,                   l4_hash         )
                __field(        unsigned int,           len             )
                __field(        unsigned int,           data_len        )
                __field(        unsigned int,           truesize        )
@@ -179,8 +179,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,
                __entry->vlan_tci = vlan_tx_tag_get(skb);
                __entry->protocol = ntohs(skb->protocol);
                __entry->ip_summed = skb->ip_summed;
-               __entry->rxhash = skb->rxhash;
-               __entry->l4_rxhash = skb->l4_rxhash;
+               __entry->hash = skb->hash;
+               __entry->l4_hash = skb->l4_hash;
                __entry->len = skb->len;
                __entry->data_len = skb->data_len;
                __entry->truesize = skb->truesize;
@@ -191,11 +191,11 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,
                __entry->gso_type = skb_shinfo(skb)->gso_type;
        ),
 
-       TP_printk("dev=%s napi_id=%#x queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d rxhash=0x%08x l4_rxhash=%d len=%u data_len=%u truesize=%u mac_header_valid=%d mac_header=%d nr_frags=%d gso_size=%d gso_type=%#x",
+       TP_printk("dev=%s napi_id=%#x queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d hash=0x%08x l4_hash=%d len=%u data_len=%u truesize=%u mac_header_valid=%d mac_header=%d nr_frags=%d gso_size=%d gso_type=%#x",
                  __get_str(name), __entry->napi_id, __entry->queue_mapping,
                  __entry->skbaddr, __entry->vlan_tagged, __entry->vlan_proto,
                  __entry->vlan_tci, __entry->protocol, __entry->ip_summed,
-                 __entry->rxhash, __entry->l4_rxhash, __entry->len,
+                 __entry->hash, __entry->l4_hash, __entry->len,
                  __entry->data_len, __entry->truesize,
                  __entry->mac_header_valid, __entry->mac_header,
                  __entry->nr_frags, __entry->gso_size, __entry->gso_type)
index 9e9475c85de50ba2eb487e0903820b5845caf564..e5bf9a76f169681c356a1d14236d5e71d14bdb96 100644 (file)
@@ -42,7 +42,6 @@ TRACE_EVENT(pstate_sample,
                u32 state,
                u64 mperf,
                u64 aperf,
-               u32 energy,
                u32 freq
                ),
 
@@ -51,7 +50,6 @@ TRACE_EVENT(pstate_sample,
                state,
                mperf,
                aperf,
-               energy,
                freq
                ),
 
@@ -61,7 +59,6 @@ TRACE_EVENT(pstate_sample,
                __field(u32, state)
                __field(u64, mperf)
                __field(u64, aperf)
-               __field(u32, energy)
                __field(u32, freq)
 
        ),
@@ -72,17 +69,15 @@ TRACE_EVENT(pstate_sample,
                __entry->state = state;
                __entry->mperf = mperf;
                __entry->aperf = aperf;
-               __entry->energy = energy;
                __entry->freq = freq;
                ),
 
-       TP_printk("core_busy=%lu scaled=%lu state=%lu mperf=%llu aperf=%llu energy=%lu freq=%lu ",
+       TP_printk("core_busy=%lu scaled=%lu state=%lu mperf=%llu aperf=%llu freq=%lu ",
                (unsigned long)__entry->core_busy,
                (unsigned long)__entry->scaled_busy,
                (unsigned long)__entry->state,
                (unsigned long long)__entry->mperf,
                (unsigned long long)__entry->aperf,
-               (unsigned long)__entry->energy,
                (unsigned long)__entry->freq
                )
 
index ddc179b7a1052aa6c3fb9df408e3b5ad9e50d792..1fef3e6e943632e6b2e1619c6536bc328a81eb8f 100644 (file)
@@ -83,7 +83,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                ),
 
        TP_fast_assign(
-               __entry->client_id = clnt->cl_clid;
+               __entry->client_id = clnt ? clnt->cl_clid : -1;
                __entry->task_id = task->tk_pid;
                __entry->action = action;
                __entry->runstate = task->tk_runstate;
@@ -91,7 +91,7 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                __entry->flags = task->tk_flags;
                ),
 
-       TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d action=%pf",
+       TP_printk("task:%u@%d flags=%4.4x state=%4.4lx status=%d action=%pf",
                __entry->task_id, __entry->client_id,
                __entry->flags,
                __entry->runstate,
index c7bbbe794e65cdd0a41c7235bcee6e9718970876..464ea82e10dbf1f1a519b75c52f9e129a5a715e0 100644 (file)
@@ -287,11 +287,11 @@ TRACE_EVENT(writeback_queue_io,
                __field(int,            reason)
        ),
        TP_fast_assign(
-               unsigned long older_than_this = work->older_than_this;
+               unsigned long *older_than_this = work->older_than_this;
                strncpy(__entry->name, dev_name(wb->bdi->dev), 32);
-               __entry->older  = older_than_this;
+               __entry->older  = older_than_this ?  *older_than_this : 0;
                __entry->age    = older_than_this ?
-                                 (jiffies - older_than_this) * 1000 / HZ : -1;
+                                 (jiffies - *older_than_this) * 1000 / HZ : -1;
                __entry->moved  = moved;
                __entry->reason = work->reason;
        ),
index 1a8b28db37752707cb130566b6295eb3f8bc4b90..1ee19a24cc5f7170a3dab525767c669f3773dc7e 100644 (file)
@@ -310,15 +310,12 @@ static struct trace_event_functions ftrace_event_type_funcs_##call = {    \
 #undef __array
 #define __array(type, item, len)                                       \
        do {                                                            \
-               mutex_lock(&event_storage_mutex);                       \
+               char *type_str = #type"["__stringify(len)"]";           \
                BUILD_BUG_ON(len > MAX_FILTER_STR_VAL);                 \
-               snprintf(event_storage, sizeof(event_storage),          \
-                        "%s[%d]", #type, len);                         \
-               ret = trace_define_field(event_call, event_storage, #item, \
+               ret = trace_define_field(event_call, type_str, #item,   \
                                 offsetof(typeof(field), item),         \
                                 sizeof(field.item),                    \
                                 is_signed_type(type), FILTER_OTHER);   \
-               mutex_unlock(&event_storage_mutex);                     \
                if (ret)                                                \
                        return ret;                                     \
        } while (0);
index a20a9b4d38713f5a92982457f0e8f330b0bfd58c..dde8041f40d2e8a29a25a6205dd38577f2b46bce 100644 (file)
@@ -692,9 +692,13 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \
 __SYSCALL(__NR_kcmp, sys_kcmp)
 #define __NR_finit_module 273
 __SYSCALL(__NR_finit_module, sys_finit_module)
+#define __NR_sched_setattr 274
+__SYSCALL(__NR_sched_setattr, sys_sched_setattr)
+#define __NR_sched_getattr 275
+__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
 
 #undef __NR_syscalls
-#define __NR_syscalls 274
+#define __NR_syscalls 276
 
 /*
  * All syscalls below here should go away really,
index 3c9a833992e872f095a4373d6cb5e33602129acc..b06c8ed687079759ea7e585589aac199ac288e22 100644 (file)
@@ -619,6 +619,8 @@ struct drm_gem_open {
 #define  DRM_PRIME_CAP_EXPORT          0x2
 #define DRM_CAP_TIMESTAMP_MONOTONIC    0x6
 #define DRM_CAP_ASYNC_PAGE_FLIP                0x7
+#define DRM_CAP_CURSOR_WIDTH           0x8
+#define DRM_CAP_CURSOR_HEIGHT          0x9
 
 /** DRM_IOCTL_GET_CAP ioctl argument type */
 struct drm_get_cap {
index 9971c560ed9aa42dc841e76b9586f05e25225d96..87792a5fee3bad7d143de81555a56ede7e532f1a 100644 (file)
@@ -87,6 +87,7 @@
 #define DRM_VMW_PARAM_MAX_SURF_MEMORY  7
 #define DRM_VMW_PARAM_3D_CAPS_SIZE     8
 #define DRM_VMW_PARAM_MAX_MOB_MEMORY   9
+#define DRM_VMW_PARAM_MAX_MOB_SIZE     10
 
 /**
  * struct drm_vmw_getparam_arg
index 1b8a0f4c95900b14e7d6f71fa54523409d3b2be6..b4d69092fbdbea488f4998c8e9fd4e158cf2465f 100644 (file)
@@ -558,7 +558,6 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
 #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64)
 #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
                                    struct btrfs_ioctl_space_args)
-#define BTRFS_IOC_GLOBAL_RSV _IOR(BTRFS_IOCTL_MAGIC, 20, __u64)
 #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
 #define BTRFS_IOC_WAIT_SYNC  _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
 #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
index e52958d7c2d119cb416587466f4a4d2a5bb1e8d0..5d9d1d1407180a9291c0f986945e3a34f2ccf51e 100644 (file)
@@ -8,6 +8,38 @@
  * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
  * All rights reserved.
  *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * 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 CAN_H
index df944ed206a8e4bd23d9f9a3ec9e08c9e0ad6e3b..7e2e1863db16e02fa15e1edc109adefda8236ba7 100644 (file)
@@ -96,6 +96,7 @@ struct can_ctrlmode {
 #define CAN_CTRLMODE_3_SAMPLES         0x04    /* Triple sampling mode */
 #define CAN_CTRLMODE_ONE_SHOT          0x08    /* One-Shot mode */
 #define CAN_CTRLMODE_BERR_REPORTING    0x10    /* Bus-error reporting */
+#define CAN_CTRLMODE_FD                        0x20    /* CAN FD mode */
 
 /*
  * CAN device statistics
@@ -122,6 +123,8 @@ enum {
        IFLA_CAN_RESTART_MS,
        IFLA_CAN_RESTART,
        IFLA_CAN_BERR_COUNTER,
+       IFLA_CAN_DATA_BITTIMING,
+       IFLA_CAN_DATA_BITTIMING_CONST,
        __IFLA_CAN_MAX
 };
 
index 38dbafaa5341154167a685a245096fbece6a375d..fd161e91b6d7e711270da030ed84b38f9b718f0c 100644 (file)
 #include <linux/types.h>
 #include <linux/if_ether.h>
 
-/* This should work for both 32 and 64 bit userland. */
+/* 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
+ * @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
+ *     interface supports autonegotiation or auto-detection.
+ *     Read-only.
+ * @advertising: Bitmask of %ADVERTISED_* flags for the link modes,
+ *     physical connectors and other link features that are
+ *     advertised through autonegotiation or enabled for
+ *     auto-detection.
+ * @speed: Low bits of the speed
+ * @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.
+ * @transceiver: Historically used to distinguish different possible
+ *     PHY types, but not in a consistent way.  Deprecated.
+ * @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.
+ * @maxtxpkt: Historically used to report TX IRQ coalescing; now
+ *     obsoleted by &struct ethtool_coalesce.  Read-only; deprecated.
+ * @maxrxpkt: Historically used to report RX IRQ coalescing; now
+ *     obsoleted by &struct ethtool_coalesce.  Read-only; deprecated.
+ * @speed_hi: High bits of the speed
+ * @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.
+ * @lp_advertising: Bitmask of %ADVERTISED_* flags for the link modes
+ *     and other link features that the link partner advertised
+ *     through autonegotiation; 0 if unknown or not applicable.
+ *     Read-only.
+ *
+ * The link speed in Mbps is split between @speed and @speed_hi.  Use
+ * the ethtool_cmd_speed() and ethtool_cmd_speed_set() functions to
+ * access it.
+ *
+ * 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.
+ *
+ * Users should assume that all fields not marked read-only are
+ * writable and subject to validation by the driver.  They should use
+ * %ETHTOOL_GSET to get the current values before making specific
+ * changes and then applying them with %ETHTOOL_SSET.
+ *
+ * Drivers that implement set_settings() should validate all fields
+ * other than @cmd that are not described as read-only or deprecated,
+ * and must ignore all fields described as read-only.
+ *
+ * Deprecated fields should be ignored by both users and drivers.
+ */
 struct ethtool_cmd {
        __u32   cmd;
-       __u32   supported;      /* Features this interface supports */
-       __u32   advertising;    /* Features this interface advertises */
-       __u16   speed;          /* The forced speed (lower bits) in
-                                * Mbps. Please use
-                                * ethtool_cmd_speed()/_set() to
-                                * access it */
-       __u8    duplex;         /* Duplex, half or full */
-       __u8    port;           /* Which connector port */
-       __u8    phy_address;    /* MDIO PHY address (PRTAD for clause 45).
-                                * May be read-only or read-write
-                                * depending on the driver.
-                                */
-       __u8    transceiver;    /* Which transceiver to use */
-       __u8    autoneg;        /* Enable or disable autonegotiation */
-       __u8    mdio_support;   /* MDIO protocols supported.  Read-only.
-                                * Not set by all drivers.
-                                */
-       __u32   maxtxpkt;       /* Tx pkts before generating tx int */
-       __u32   maxrxpkt;       /* Rx pkts before generating rx int */
-       __u16   speed_hi;       /* The forced speed (upper
-                                * bits) in Mbps. Please use
-                                * ethtool_cmd_speed()/_set() to
-                                * access it */
-       __u8    eth_tp_mdix;    /* twisted pair MDI-X status */
-       __u8    eth_tp_mdix_ctrl; /* twisted pair MDI-X control, when set,
-                                  * link should be renegotiated if necessary
-                                  */
-       __u32   lp_advertising; /* Features the link partner advertises */
+       __u32   supported;
+       __u32   advertising;
+       __u16   speed;
+       __u8    duplex;
+       __u8    port;
+       __u8    phy_address;
+       __u8    transceiver;
+       __u8    autoneg;
+       __u8    mdio_support;
+       __u32   maxtxpkt;
+       __u32   maxrxpkt;
+       __u16   speed_hi;
+       __u8    eth_tp_mdix;
+       __u8    eth_tp_mdix_ctrl;
+       __u32   lp_advertising;
        __u32   reserved[2];
 };
 
@@ -79,37 +139,68 @@ static inline __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep)
 
 #define ETHTOOL_FWVERS_LEN     32
 #define ETHTOOL_BUSINFO_LEN    32
-/* these strings are set to whatever the driver author decides... */
+
+/**
+ * struct ethtool_drvinfo - general driver and device information
+ * @cmd: Command number = %ETHTOOL_GDRVINFO
+ * @driver: Driver short name.  This should normally match the name
+ *     in its bus driver structure (e.g. pci_driver::name).  Must
+ *     not be an empty string.
+ * @version: Driver version string; may be an empty string
+ * @fw_version: Firmware version string; may be an empty string
+ * @bus_info: Device bus address.  This should match the dev_name()
+ *     string for the underlying bus device, if there is one.  May be
+ *     an empty string.
+ * @n_priv_flags: Number of flags valid for %ETHTOOL_GPFLAGS and
+ *     %ETHTOOL_SPFLAGS commands; also the number of strings in the
+ *     %ETH_SS_PRIV_FLAGS set
+ * @n_stats: Number of u64 statistics returned by the %ETHTOOL_GSTATS
+ *     command; also the number of strings in the %ETH_SS_STATS set
+ * @testinfo_len: Number of results returned by the %ETHTOOL_TEST
+ *     command; also the number of strings in the %ETH_SS_TEST set
+ * @eedump_len: Size of EEPROM accessible through the %ETHTOOL_GEEPROM
+ *     and %ETHTOOL_SEEPROM commands, in bytes
+ * @regdump_len: Size of register dump returned by the %ETHTOOL_GREGS
+ *     command, in bytes
+ *
+ * Users can use the %ETHTOOL_GSSET_INFO command to get the number of
+ * strings in any string set (from Linux 2.6.34).
+ *
+ * Drivers should set at most @driver, @version, @fw_version and
+ * @bus_info in their get_drvinfo() implementation.  The ethtool
+ * core fills in the other fields using other driver operations.
+ */
 struct ethtool_drvinfo {
        __u32   cmd;
-       char    driver[32];     /* driver short name, "tulip", "eepro100" */
-       char    version[32];    /* driver version string */
-       char    fw_version[ETHTOOL_FWVERS_LEN]; /* firmware version string */
-       char    bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
-                               /* For PCI devices, use pci_name(pci_dev). */
+       char    driver[32];
+       char    version[32];
+       char    fw_version[ETHTOOL_FWVERS_LEN];
+       char    bus_info[ETHTOOL_BUSINFO_LEN];
        char    reserved1[32];
        char    reserved2[12];
-                               /*
-                                * Some struct members below are filled in
-                                * using ops->get_sset_count().  Obtaining
-                                * this info from ethtool_drvinfo is now
-                                * deprecated; Use ETHTOOL_GSSET_INFO
-                                * instead.
-                                */
-       __u32   n_priv_flags;   /* number of flags valid in ETHTOOL_GPFLAGS */
-       __u32   n_stats;        /* number of u64's from ETHTOOL_GSTATS */
+       __u32   n_priv_flags;
+       __u32   n_stats;
        __u32   testinfo_len;
-       __u32   eedump_len;     /* Size of data from ETHTOOL_GEEPROM (bytes) */
-       __u32   regdump_len;    /* Size of data from ETHTOOL_GREGS (bytes) */
+       __u32   eedump_len;
+       __u32   regdump_len;
 };
 
 #define SOPASS_MAX     6
-/* wake-on-lan settings */
+
+/**
+ * struct ethtool_wolinfo - Wake-On-Lan configuration
+ * @cmd: Command number = %ETHTOOL_GWOL or %ETHTOOL_SWOL
+ * @supported: Bitmask of %WAKE_* flags for supported Wake-On-Lan modes.
+ *     Read-only.
+ * @wolopts: Bitmask of %WAKE_* flags for enabled Wake-On-Lan modes.
+ * @sopass: SecureOn(tm) password; meaningful only if %WAKE_MAGICSECURE
+ *     is set in @wolopts.
+ */
 struct ethtool_wolinfo {
        __u32   cmd;
        __u32   supported;
        __u32   wolopts;
-       __u8    sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+       __u8    sopass[SOPASS_MAX];
 };
 
 /* for passing single values */
@@ -118,20 +209,51 @@ struct ethtool_value {
        __u32   data;
 };
 
-/* for passing big chunks of data */
+/**
+ * struct ethtool_regs - hardware register dump
+ * @cmd: Command number = %ETHTOOL_GREGS
+ * @version: Dump format version.  This is driver-specific and may
+ *     distinguish different chips/revisions.  Drivers must use new
+ *     version numbers whenever the dump format changes in an
+ *     incompatible way.
+ * @len: On entry, the real length of @data.  On return, the number of
+ *     bytes used.
+ * @data: Buffer for the register dump
+ *
+ * Users should use %ETHTOOL_GDRVINFO to find the maximum length of
+ * a register dump for the interface.  They must allocate the buffer
+ * immediately following this structure.
+ */
 struct ethtool_regs {
        __u32   cmd;
-       __u32   version; /* driver-specific, indicates different chips/revs */
-       __u32   len; /* bytes */
+       __u32   version;
+       __u32   len;
        __u8    data[0];
 };
 
-/* for passing EEPROM chunks */
+/**
+ * struct ethtool_eeprom - EEPROM dump
+ * @cmd: Command number = %ETHTOOL_GEEPROM, %ETHTOOL_GMODULEEEPROM or
+ *     %ETHTOOL_SEEPROM
+ * @magic: A 'magic cookie' value to guard against accidental changes.
+ *     The value passed in to %ETHTOOL_SEEPROM must match the value
+ *     returned by %ETHTOOL_GEEPROM for the same device.  This is
+ *     unused when @cmd is %ETHTOOL_GMODULEEEPROM.
+ * @offset: Offset within the EEPROM to begin reading/writing, in bytes
+ * @len: On entry, number of bytes to read/write.  On successful
+ *     return, number of bytes actually read/written.  In case of
+ *     error, this may indicate at what point the error occurred.
+ * @data: Buffer to read/write from
+ *
+ * Users may use %ETHTOOL_GDRVINFO or %ETHTOOL_GMODULEINFO to find
+ * the length of an on-board or module EEPROM, respectively.  They
+ * must allocate the buffer immediately following this structure.
+ */
 struct ethtool_eeprom {
        __u32   cmd;
        __u32   magic;
-       __u32   offset; /* in bytes */
-       __u32   len; /* in bytes */
+       __u32   offset;
+       __u32   len;
        __u8    data[0];
 };
 
@@ -229,17 +351,18 @@ struct ethtool_modinfo {
  * @rate_sample_interval: How often to do adaptive coalescing packet rate
  *     sampling, measured in seconds.  Must not be zero.
  *
- * Each pair of (usecs, max_frames) fields specifies this exit
- * condition for interrupt coalescing:
+ * Each pair of (usecs, max_frames) fields specifies that interrupts
+ * should be coalesced until
  *     (usecs > 0 && time_since_first_completion >= usecs) ||
  *     (max_frames > 0 && completed_frames >= max_frames)
+ *
  * It is illegal to set both usecs and max_frames to zero as this
  * would cause interrupts to never be generated.  To disable
  * coalescing, set usecs = 0 and max_frames = 1.
  *
  * Some implementations ignore the value of max_frames and use the
- * condition:
- *     time_since_first_completion >= usecs
+ * condition time_since_first_completion >= usecs
+ *
  * This is deprecated.  Drivers for hardware that does not support
  * counting completions should validate that max_frames == !rx_usecs.
  *
@@ -279,22 +402,37 @@ struct ethtool_coalesce {
        __u32   rate_sample_interval;
 };
 
-/* for configuring RX/TX ring parameters */
+/**
+ * struct ethtool_ringparam - RX/TX ring parameters
+ * @cmd: Command number = %ETHTOOL_GRINGPARAM or %ETHTOOL_SRINGPARAM
+ * @rx_max_pending: Maximum supported number of pending entries per
+ *     RX ring.  Read-only.
+ * @rx_mini_max_pending: Maximum supported number of pending entries
+ *     per RX mini ring.  Read-only.
+ * @rx_jumbo_max_pending: Maximum supported number of pending entries
+ *     per RX jumbo ring.  Read-only.
+ * @tx_max_pending: Maximum supported number of pending entries per
+ *     TX ring.  Read-only.
+ * @rx_pending: Current maximum number of pending entries per RX ring
+ * @rx_mini_pending: Current maximum number of pending entries per RX
+ *     mini ring
+ * @rx_jumbo_pending: Current maximum number of pending entries per RX
+ *     jumbo ring
+ * @tx_pending: Current maximum supported number of pending entries
+ *     per TX ring
+ *
+ * If the interface does not have separate RX mini and/or jumbo rings,
+ * @rx_mini_max_pending and/or @rx_jumbo_max_pending will be 0.
+ *
+ * There may also be driver-dependent minimum values for the number
+ * of entries per ring.
+ */
 struct ethtool_ringparam {
-       __u32   cmd;    /* ETHTOOL_{G,S}RINGPARAM */
-
-       /* Read only attributes.  These indicate the maximum number
-        * of pending RX/TX ring entries the driver will allow the
-        * user to set.
-        */
+       __u32   cmd;
        __u32   rx_max_pending;
        __u32   rx_mini_max_pending;
        __u32   rx_jumbo_max_pending;
        __u32   tx_max_pending;
-
-       /* Values changeable by the user.  The valid values are
-        * in the range 1 to the "*_max_pending" counterpart above.
-        */
        __u32   rx_pending;
        __u32   rx_mini_pending;
        __u32   rx_jumbo_pending;
@@ -329,51 +467,96 @@ struct ethtool_channels {
        __u32   combined_count;
 };
 
-/* for configuring link flow control parameters */
+/**
+ * struct ethtool_pauseparam - Ethernet pause (flow control) parameters
+ * @cmd: Command number = %ETHTOOL_GPAUSEPARAM or %ETHTOOL_SPAUSEPARAM
+ * @autoneg: Flag to enable autonegotiation of pause frame use
+ * @rx_pause: Flag to enable reception of pause frames
+ * @tx_pause: Flag to enable transmission of pause frames
+ *
+ * Drivers should reject a non-zero setting of @autoneg when
+ * autoneogotiation is disabled (or not supported) for the link.
+ *
+ * If the link is autonegotiated, drivers should use
+ * mii_advertise_flowctrl() or similar code to set the advertised
+ * pause frame capabilities based on the @rx_pause and @tx_pause flags,
+ * even if @autoneg is zero.  They should also allow the advertised
+ * pause frame capabilities to be controlled directly through the
+ * advertising field of &struct ethtool_cmd.
+ *
+ * If @autoneg is non-zero, the MAC is configured to send and/or
+ * receive pause frames according to the result of autonegotiation.
+ * Otherwise, it is configured directly based on the @rx_pause and
+ * @tx_pause flags.
+ */
 struct ethtool_pauseparam {
-       __u32   cmd;    /* ETHTOOL_{G,S}PAUSEPARAM */
-
-       /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
-        * being true) the user may set 'autoneg' here non-zero to have the
-        * pause parameters be auto-negotiated too.  In such a case, the
-        * {rx,tx}_pause values below determine what capabilities are
-        * advertised.
-        *
-        * If 'autoneg' is zero or the link is not being auto-negotiated,
-        * then {rx,tx}_pause force the driver to use/not-use pause
-        * flow control.
-        */
+       __u32   cmd;
        __u32   autoneg;
        __u32   rx_pause;
        __u32   tx_pause;
 };
 
 #define ETH_GSTRING_LEN                32
+
+/**
+ * enum ethtool_stringset - string set ID
+ * @ETH_SS_TEST: Self-test result names, for use with %ETHTOOL_TEST
+ * @ETH_SS_STATS: Statistic names, for use with %ETHTOOL_GSTATS
+ * @ETH_SS_PRIV_FLAGS: Driver private flag names, for use with
+ *     %ETHTOOL_GPFLAGS and %ETHTOOL_SPFLAGS
+ * @ETH_SS_NTUPLE_FILTERS: Previously used with %ETHTOOL_GRXNTUPLE;
+ *     now deprecated
+ * @ETH_SS_FEATURES: Device feature names
+ */
 enum ethtool_stringset {
        ETH_SS_TEST             = 0,
        ETH_SS_STATS,
        ETH_SS_PRIV_FLAGS,
-       ETH_SS_NTUPLE_FILTERS,  /* Do not use, GRXNTUPLE is now deprecated */
+       ETH_SS_NTUPLE_FILTERS,
        ETH_SS_FEATURES,
 };
 
-/* for passing string sets for data tagging */
+/**
+ * struct ethtool_gstrings - string set for data tagging
+ * @cmd: Command number = %ETHTOOL_GSTRINGS
+ * @string_set: String set ID; one of &enum ethtool_stringset
+ * @len: On return, the number of strings in the string set
+ * @data: Buffer for strings.  Each string is null-padded to a size of
+ *     %ETH_GSTRING_LEN.
+ *
+ * Users must use %ETHTOOL_GSSET_INFO to find the number of strings in
+ * the string set.  They must allocate a buffer of the appropriate
+ * size immediately following this structure.
+ */
 struct ethtool_gstrings {
-       __u32   cmd;            /* ETHTOOL_GSTRINGS */
-       __u32   string_set;     /* string set id e.c. ETH_SS_TEST, etc*/
-       __u32   len;            /* number of strings in the string set */
+       __u32   cmd;
+       __u32   string_set;
+       __u32   len;
        __u8    data[0];
 };
 
+/**
+ * struct ethtool_sset_info - string set information
+ * @cmd: Command number = %ETHTOOL_GSSET_INFO
+ * @sset_mask: On entry, a bitmask of string sets to query, with bits
+ *     numbered according to &enum ethtool_stringset.  On return, a
+ *     bitmask of those string sets queried that are supported.
+ * @data: Buffer for string set sizes.  On return, this contains the
+ *     size of each string set that was queried and supported, in
+ *     order of ID.
+ *
+ * Example: The user passes in @sset_mask = 0x7 (sets 0, 1, 2) and on
+ * return @sset_mask == 0x6 (sets 1, 2).  Then @data[0] contains the
+ * size of set 1 and @data[1] contains the size of set 2.
+ *
+ * Users must allocate a buffer of the appropriate size (4 * number of
+ * sets queried) immediately following this structure.
+ */
 struct ethtool_sset_info {
-       __u32   cmd;            /* ETHTOOL_GSSET_INFO */
+       __u32   cmd;
        __u32   reserved;
-       __u64   sset_mask;      /* input: each bit selects an sset to query */
-                               /* output: each bit a returned sset */
-       __u32   data[0];        /* ETH_SS_xxx count, in order, based on bits
-                                  in sset_mask.  One bit implies one
-                                  __u32, two bits implies two
-                                  __u32's, etc. */
+       __u64   sset_mask;
+       __u32   data[0];
 };
 
 /**
@@ -393,24 +576,58 @@ enum ethtool_test_flags {
        ETH_TEST_FL_EXTERNAL_LB_DONE    = (1 << 3),
 };
 
-/* for requesting NIC test and getting results*/
+/**
+ * struct ethtool_test - device self-test invocation
+ * @cmd: Command number = %ETHTOOL_TEST
+ * @flags: A bitmask of flags from &enum ethtool_test_flags.  Some
+ *     flags may be set by the user on entry; others may be set by
+ *     the driver on return.
+ * @len: On return, the number of test results
+ * @data: Array of test results
+ *
+ * Users must use %ETHTOOL_GSSET_INFO or %ETHTOOL_GDRVINFO to find the
+ * number of test results that will be returned.  They must allocate a
+ * buffer of the appropriate size (8 * number of results) immediately
+ * following this structure.
+ */
 struct ethtool_test {
-       __u32   cmd;            /* ETHTOOL_TEST */
-       __u32   flags;          /* ETH_TEST_FL_xxx */
+       __u32   cmd;
+       __u32   flags;
        __u32   reserved;
-       __u32   len;            /* result length, in number of u64 elements */
+       __u32   len;
        __u64   data[0];
 };
 
-/* for dumping NIC-specific statistics */
+/**
+ * struct ethtool_stats - device-specific statistics
+ * @cmd: Command number = %ETHTOOL_GSTATS
+ * @n_stats: On return, the number of statistics
+ * @data: Array of statistics
+ *
+ * Users must use %ETHTOOL_GSSET_INFO or %ETHTOOL_GDRVINFO to find the
+ * number of statistics that will be returned.  They must allocate a
+ * buffer of the appropriate size (8 * number of statistics)
+ * immediately following this structure.
+ */
 struct ethtool_stats {
-       __u32   cmd;            /* ETHTOOL_GSTATS */
-       __u32   n_stats;        /* number of u64's being returned */
+       __u32   cmd;
+       __u32   n_stats;
        __u64   data[0];
 };
 
+/**
+ * struct ethtool_perm_addr - permanent hardware address
+ * @cmd: Command number = %ETHTOOL_GPERMADDR
+ * @size: On entry, the size of the buffer.  On return, the size of the
+ *     address.  The command fails if the buffer is too small.
+ * @data: Buffer for the address
+ *
+ * Users must allocate the buffer immediately following this structure.
+ * A buffer size of %MAX_ADDR_LEN should be sufficient for any address
+ * type.
+ */
 struct ethtool_perm_addr {
-       __u32   cmd;            /* ETHTOOL_GPERMADDR */
+       __u32   cmd;
        __u32   size;
        __u8    data[0];
 };
@@ -593,7 +810,7 @@ struct ethtool_rx_flow_spec {
  * %ETHTOOL_SRXCLSRLINS may add the rule at any suitable unused
  * location, and may remove a rule at a later location (lower
  * priority) that matches exactly the same set of flows.  The special
- * values are: %RX_CLS_LOC_ANY, selecting any location;
+ * values are %RX_CLS_LOC_ANY, selecting any location;
  * %RX_CLS_LOC_FIRST, selecting the first suitable location (maximum
  * priority); and %RX_CLS_LOC_LAST, selecting the last suitable
  * location (minimum priority).  Additional special values may be
@@ -704,9 +921,6 @@ struct ethtool_flash {
  *      for %ETHTOOL_GET_DUMP_FLAG command
  * @data: data collected for get dump data operation
  */
-
-#define ETH_FW_DUMP_DISABLE 0
-
 struct ethtool_dump {
        __u32   cmd;
        __u32   version;
@@ -715,6 +929,8 @@ struct ethtool_dump {
        __u8    data[0];
 };
 
+#define ETH_FW_DUMP_DISABLE 0
+
 /* for returning and changing feature sets */
 
 /**
@@ -734,8 +950,9 @@ struct ethtool_get_features_block {
 /**
  * struct ethtool_gfeatures - command to get state of device's features
  * @cmd: command number = %ETHTOOL_GFEATURES
- * @size: in: number of elements in the features[] array;
- *       out: number of elements in features[] needed to hold all features
+ * @size: On entry, the number of elements in the features[] array;
+ *     on return, the number of elements in features[] needed to hold
+ *     all features
  * @features: state of features
  */
 struct ethtool_gfeatures {
@@ -905,7 +1122,6 @@ enum ethtool_sfeatures_retval_bits {
 #define SPARC_ETH_GSET         ETHTOOL_GSET
 #define SPARC_ETH_SSET         ETHTOOL_SSET
 
-/* Indicates what features are supported by the interface. */
 #define SUPPORTED_10baseT_Half         (1 << 0)
 #define SUPPORTED_10baseT_Full         (1 << 1)
 #define SUPPORTED_100baseT_Half                (1 << 2)
@@ -934,7 +1150,6 @@ enum ethtool_sfeatures_retval_bits {
 #define SUPPORTED_40000baseSR4_Full    (1 << 25)
 #define SUPPORTED_40000baseLR4_Full    (1 << 26)
 
-/* Indicates what features are advertised by the interface. */
 #define ADVERTISED_10baseT_Half                (1 << 0)
 #define ADVERTISED_10baseT_Full                (1 << 1)
 #define ADVERTISED_100baseT_Half       (1 << 2)
@@ -999,9 +1214,7 @@ enum ethtool_sfeatures_retval_bits {
 #define XCVR_DUMMY2            0x03
 #define XCVR_DUMMY3            0x04
 
-/* Enable or disable autonegotiation.  If this is set to enable,
- * the forced link modes above are completely ignored.
- */
+/* Enable or disable autonegotiation. */
 #define AUTONEG_DISABLE                0x00
 #define AUTONEG_ENABLE         0x01
 
index d758163b0e432f6c461d2b32335dcf138d217df7..9cf2394f0bcff00b6629933e3a864d69abd1da55 100644 (file)
 #define        IFALIASZ        256
 #include <linux/hdlc/ioctl.h>
 
-/* Standard interface flags (netdevice->flags). */
-#define        IFF_UP          0x1             /* interface is up              */
-#define        IFF_BROADCAST   0x2             /* broadcast address valid      */
-#define        IFF_DEBUG       0x4             /* turn on debugging            */
-#define        IFF_LOOPBACK    0x8             /* is a loopback net            */
-#define        IFF_POINTOPOINT 0x10            /* interface is has p-p link    */
-#define        IFF_NOTRAILERS  0x20            /* avoid use of trailers        */
-#define        IFF_RUNNING     0x40            /* interface RFC2863 OPER_UP    */
-#define        IFF_NOARP       0x80            /* no ARP protocol              */
-#define        IFF_PROMISC     0x100           /* receive all packets          */
-#define        IFF_ALLMULTI    0x200           /* receive all multicast packets*/
-
-#define IFF_MASTER     0x400           /* master of a load balancer    */
-#define IFF_SLAVE      0x800           /* slave of a load balancer     */
-
-#define IFF_MULTICAST  0x1000          /* Supports multicast           */
-
-#define IFF_PORTSEL    0x2000          /* can set media type           */
-#define IFF_AUTOMEDIA  0x4000          /* auto media select active     */
-#define IFF_DYNAMIC    0x8000          /* dialup device with changing addresses*/
-
-#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
-#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+/**
+ * enum net_device_flags - &struct net_device flags
+ *
+ * These are the &struct net_device flags, they can be set by drivers, the
+ * kernel and some can be triggered by userspace. Userspace can query and
+ * set these flags using userspace utilities but there is also a sysfs
+ * entry available for all dev flags which can be queried and set. These flags
+ * are shared for all types of net_devices. The sysfs entries are available
+ * via /sys/class/net/<dev>/flags. Flags which can be toggled through sysfs
+ * are annotated below, note that only a few flags can be toggled and some
+ * other flags are always always preserved from the original net_device flags
+ * even if you try to set them via sysfs. Flags which are always preserved
+ * are kept under the flag grouping @IFF_VOLATILE. Flags which are volatile
+ * are annotated below as such.
+ *
+ * You should have a pretty good reason to be extending these flags.
+ *
+ * @IFF_UP: interface is up. Can be toggled through sysfs.
+ * @IFF_BROADCAST: broadcast address valid. Volatile.
+ * @IFF_DEBUG: turn on debugging. Can be toggled through sysfs.
+ * @IFF_LOOPBACK: is a loopback net. Volatile.
+ * @IFF_POINTOPOINT: interface is has p-p link. Volatile.
+ * @IFF_NOTRAILERS: avoid use of trailers. Can be toggled through sysfs.
+ *     Volatile.
+ * @IFF_RUNNING: interface RFC2863 OPER_UP. Volatile.
+ * @IFF_NOARP: no ARP protocol. Can be toggled through sysfs. Volatile.
+ * @IFF_PROMISC: receive all packets. Can be toggled through sysfs.
+ * @IFF_ALLMULTI: receive all multicast packets. Can be toggled through
+ *     sysfs.
+ * @IFF_MASTER: master of a load balancer. Volatile.
+ * @IFF_SLAVE: slave of a load balancer. Volatile.
+ * @IFF_MULTICAST: Supports multicast. Can be toggled through sysfs.
+ * @IFF_PORTSEL: can set media type. Can be toggled through sysfs.
+ * @IFF_AUTOMEDIA: auto media select active. Can be toggled through sysfs.
+ * @IFF_DYNAMIC: dialup device with changing addresses. Can be toggled
+ *     through sysfs.
+ * @IFF_LOWER_UP: driver signals L1 up. Volatile.
+ * @IFF_DORMANT: driver signals dormant. Volatile.
+ * @IFF_ECHO: echo sent packets. Volatile.
+ */
+enum net_device_flags {
+       IFF_UP                          = 1<<0,  /* sysfs */
+       IFF_BROADCAST                   = 1<<1,  /* volatile */
+       IFF_DEBUG                       = 1<<2,  /* sysfs */
+       IFF_LOOPBACK                    = 1<<3,  /* volatile */
+       IFF_POINTOPOINT                 = 1<<4,  /* volatile */
+       IFF_NOTRAILERS                  = 1<<5,  /* sysfs */
+       IFF_RUNNING                     = 1<<6,  /* volatile */
+       IFF_NOARP                       = 1<<7,  /* sysfs */
+       IFF_PROMISC                     = 1<<8,  /* sysfs */
+       IFF_ALLMULTI                    = 1<<9,  /* sysfs */
+       IFF_MASTER                      = 1<<10, /* volatile */
+       IFF_SLAVE                       = 1<<11, /* volatile */
+       IFF_MULTICAST                   = 1<<12, /* sysfs */
+       IFF_PORTSEL                     = 1<<13, /* sysfs */
+       IFF_AUTOMEDIA                   = 1<<14, /* sysfs */
+       IFF_DYNAMIC                     = 1<<15, /* sysfs */
+       IFF_LOWER_UP                    = 1<<16, /* volatile */
+       IFF_DORMANT                     = 1<<17, /* volatile */
+       IFF_ECHO                        = 1<<18, /* volatile */
+};
 
-#define IFF_ECHO       0x40000         /* echo sent packets            */
+#define IFF_UP                         IFF_UP
+#define IFF_BROADCAST                  IFF_BROADCAST
+#define IFF_DEBUG                      IFF_DEBUG
+#define IFF_LOOPBACK                   IFF_LOOPBACK
+#define IFF_POINTOPOINT                        IFF_POINTOPOINT
+#define IFF_NOTRAILERS                 IFF_NOTRAILERS
+#define IFF_RUNNING                    IFF_RUNNING
+#define IFF_NOARP                      IFF_NOARP
+#define IFF_PROMISC                    IFF_PROMISC
+#define IFF_ALLMULTI                   IFF_ALLMULTI
+#define IFF_MASTER                     IFF_MASTER
+#define IFF_SLAVE                      IFF_SLAVE
+#define IFF_MULTICAST                  IFF_MULTICAST
+#define IFF_PORTSEL                    IFF_PORTSEL
+#define IFF_AUTOMEDIA                  IFF_AUTOMEDIA
+#define IFF_DYNAMIC                    IFF_DYNAMIC
+#define IFF_LOWER_UP                   IFF_LOWER_UP
+#define IFF_DORMANT                    IFF_DORMANT
+#define IFF_ECHO                       IFF_ECHO
 
 #define IFF_VOLATILE   (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
                IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
 
-/* Private (from user) interface flags (netdevice->priv_flags). */
-#define IFF_802_1Q_VLAN 0x1             /* 802.1Q VLAN device.          */
-#define IFF_EBRIDGE    0x2             /* Ethernet bridging device.    */
-#define IFF_SLAVE_INACTIVE     0x4     /* bonding slave not the curr. active */
-#define IFF_MASTER_8023AD      0x8     /* bonding master, 802.3ad.     */
-#define IFF_MASTER_ALB 0x10            /* bonding master, balance-alb. */
-#define IFF_BONDING    0x20            /* bonding master or slave      */
-#define IFF_SLAVE_NEEDARP 0x40         /* need ARPs for validation     */
-#define IFF_ISATAP     0x80            /* ISATAP interface (RFC4214)   */
-#define IFF_MASTER_ARPMON 0x100                /* bonding master, ARP mon in use */
-#define IFF_WAN_HDLC   0x200           /* WAN HDLC device              */
-#define IFF_XMIT_DST_RELEASE 0x400     /* dev_hard_start_xmit() is allowed to
-                                        * release skb->dst
-                                        */
-#define IFF_DONT_BRIDGE 0x800          /* disallow bridging this ether dev */
-#define IFF_DISABLE_NETPOLL    0x1000  /* disable netpoll at run-time */
-#define IFF_MACVLAN_PORT       0x2000  /* device used as macvlan port */
-#define IFF_BRIDGE_PORT        0x4000          /* device used as bridge port */
-#define IFF_OVS_DATAPATH       0x8000  /* device used as Open vSwitch
-                                        * datapath port */
-#define IFF_TX_SKB_SHARING     0x10000 /* The interface supports sharing
-                                        * skbs on transmit */
-#define IFF_UNICAST_FLT        0x20000         /* Supports unicast filtering   */
-#define IFF_TEAM_PORT  0x40000         /* device used as team port */
-#define IFF_SUPP_NOFCS 0x80000         /* device supports sending custom FCS */
-#define IFF_LIVE_ADDR_CHANGE 0x100000  /* device supports hardware address
-                                        * change when it's running */
-#define IFF_MACVLAN 0x200000           /* Macvlan device */
-
-
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
 
index 2ce0f6a78fa5b47ba6308b371cf6b0c8f21e579b..0f8210b8e0bc47ac0b7faab45a12ca6dcfbdf72d 100644 (file)
 #define ETH_P_SLOW     0x8809          /* Slow Protocol. See 802.3ad 43B */
 #define ETH_P_WCCP     0x883E          /* Web-cache coordination protocol
                                         * defined in draft-wilson-wrec-wccp-v2-00.txt */
-#define ETH_P_PPP_DISC 0x8863          /* PPPoE discovery messages     */
-#define ETH_P_PPP_SES  0x8864          /* PPPoE session messages       */
 #define ETH_P_MPLS_UC  0x8847          /* MPLS Unicast traffic         */
 #define ETH_P_MPLS_MC  0x8848          /* MPLS Multicast traffic       */
 #define ETH_P_ATMMPOA  0x884c          /* MultiProtocol Over ATM       */
+#define ETH_P_PPP_DISC 0x8863          /* PPPoE discovery messages     */
+#define ETH_P_PPP_SES  0x8864          /* PPPoE session messages       */
 #define ETH_P_LINK_CTL 0x886c          /* HPNA, wlan link local tunnel */
 #define ETH_P_ATMFATE  0x8884          /* Frame-based ATM Transport
                                         * over Ethernet
@@ -89,6 +89,8 @@
 #define ETH_P_FCOE     0x8906          /* Fibre Channel over Ethernet  */
 #define ETH_P_TDLS     0x890D          /* TDLS */
 #define ETH_P_FIP      0x8914          /* FCoE Initialization Protocol */
+#define ETH_P_80221    0x8917          /* IEEE 802.21 Media Independent Handover Protocol */
+#define ETH_P_LOOPBACK 0x9000          /* Ethernet loopback packet, per IEEE 802.3 */
 #define ETH_P_QINQ1    0x9100          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_QINQ2    0x9200          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
 #define ETH_P_QINQ3    0x9300          /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
index 393c5de09d42c69393cb228e0d401189f072deb4..c33a65e3d62c85d104d38ab082d997df13cd4c0b 100644 (file)
@@ -120,6 +120,10 @@ struct in_addr {
  * this socket to prevent accepting spoofed ones.
  */
 #define IP_PMTUDISC_INTERFACE          4
+/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get
+ * fragmented if they exeed the interface mtu
+ */
+#define IP_PMTUDISC_OMIT               5
 
 #define IP_MULTICAST_IF                        32
 #define IP_MULTICAST_TTL               33
index 633b93cac1ed8680407119036d880e8e0a799452..0d8e0f0342dc183acd5393e11bfe203f019ca165 100644 (file)
@@ -128,22 +128,13 @@ struct in6_flowlabel_req {
  *     IPV6 extension headers
  */
 #if __UAPI_DEF_IPPROTO_V6
-enum {
-  IPPROTO_HOPOPTS = 0,         /* IPv6 hop-by-hop options      */
-#define IPPROTO_HOPOPTS                IPPROTO_HOPOPTS
-  IPPROTO_ROUTING = 43,                /* IPv6 routing header          */
-#define IPPROTO_ROUTING                IPPROTO_ROUTING
-  IPPROTO_FRAGMENT = 44,       /* IPv6 fragmentation header    */
-#define IPPROTO_FRAGMENT       IPPROTO_FRAGMENT
-  IPPROTO_ICMPV6 = 58,         /* ICMPv6                       */
-#define IPPROTO_ICMPV6         IPPROTO_ICMPV6
-  IPPROTO_NONE = 59,           /* IPv6 no next header          */
-#define IPPROTO_NONE           IPPROTO_NONE
-  IPPROTO_DSTOPTS = 60,                /* IPv6 destination options     */
-#define IPPROTO_DSTOPTS                IPPROTO_DSTOPTS
-  IPPROTO_MH = 135,            /* IPv6 mobility header         */
-#define IPPROTO_MH             IPPROTO_MH
-};
+#define IPPROTO_HOPOPTS                0       /* IPv6 hop-by-hop options      */
+#define IPPROTO_ROUTING                43      /* IPv6 routing header          */
+#define IPPROTO_FRAGMENT       44      /* IPv6 fragmentation header    */
+#define IPPROTO_ICMPV6         58      /* ICMPv6                       */
+#define IPPROTO_NONE           59      /* IPv6 no next header          */
+#define IPPROTO_DSTOPTS                60      /* IPv6 destination options     */
+#define IPPROTO_MH             135     /* IPv6 mobility header         */
 #endif /* __UAPI_DEF_IPPROTO_V6 */
 
 /*
@@ -194,6 +185,10 @@ enum {
  * also see comments on IP_PMTUDISC_INTERFACE
  */
 #define IPV6_PMTUDISC_INTERFACE                4
+/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to
+ * get fragmented if they exceed the interface mtu
+ */
+#define IPV6_PMTUDISC_OMIT             5
 
 /* Flowlabel */
 #define IPV6_FLOWLABEL_MGR     32
index 7fabba5059cf6c362e67093b9ee37ffc4d188276..feb0b4c0814c0ff3ec93318612300d260fdf8442 100644 (file)
@@ -39,7 +39,7 @@ struct mic_copy_desc {
 #else
        struct iovec *iov;
 #endif
-       int iovcnt;
+       __u32 iovcnt;
        __u8 vr_idx;
        __u8 update_used;
        __u32 out_len;
diff --git a/include/uapi/linux/mpls.h b/include/uapi/linux/mpls.h
new file mode 100644 (file)
index 0000000..bc9abfe
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef _UAPI_MPLS_H
+#define _UAPI_MPLS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* Reference: RFC 5462, RFC 3032
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                Label                  | TC  |S|       TTL     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *     Label:  Label Value, 20 bits
+ *     TC:     Traffic Class field, 3 bits
+ *     S:      Bottom of Stack, 1 bit
+ *     TTL:    Time to Live, 8 bits
+ */
+
+struct mpls_label {
+       __be32 entry;
+};
+
+#define MPLS_LS_LABEL_MASK      0xFFFFF000
+#define MPLS_LS_LABEL_SHIFT     12
+#define MPLS_LS_TC_MASK         0x00000E00
+#define MPLS_LS_TC_SHIFT        9
+#define MPLS_LS_S_MASK          0x00000100
+#define MPLS_LS_S_SHIFT         8
+#define MPLS_LS_TTL_MASK        0x000000FF
+#define MPLS_LS_TTL_SHIFT       0
+
+#endif /* _UAPI_MPLS_H */
index 25d3b2f79c022e92cfd8f851e0f9ae8a2f7b731a..78c2f2e799208a467b75c8035b4d3362365362bb 100644 (file)
@@ -82,6 +82,8 @@ enum {
        IPSET_ATTR_PROTO,       /* 7 */
        IPSET_ATTR_CADT_FLAGS,  /* 8 */
        IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO,     /* 9 */
+       IPSET_ATTR_MARK,        /* 10 */
+       IPSET_ATTR_MARKMASK,    /* 11 */
        /* Reserve empty slots */
        IPSET_ATTR_CADT_MAX = 16,
        /* Create-only specific attributes */
@@ -144,6 +146,7 @@ enum ipset_errno {
        IPSET_ERR_IPADDR_IPV6,
        IPSET_ERR_COUNTER,
        IPSET_ERR_COMMENT,
+       IPSET_ERR_INVALID_MARKMASK,
 
        /* Type specific error codes */
        IPSET_ERR_TYPE_SPECIFIC = 4352,
@@ -182,9 +185,18 @@ enum ipset_cadt_flags {
        IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
        IPSET_FLAG_BIT_WITH_COMMENT = 4,
        IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT),
+       IPSET_FLAG_BIT_WITH_FORCEADD = 5,
+       IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD),
        IPSET_FLAG_CADT_MAX     = 15,
 };
 
+/* The flag bits which correspond to the non-extension create flags */
+enum ipset_create_flags {
+       IPSET_CREATE_FLAG_BIT_FORCEADD = 0,
+       IPSET_CREATE_FLAG_FORCEADD = (1 << IPSET_CREATE_FLAG_BIT_FORCEADD),
+       IPSET_CREATE_FLAG_BIT_MAX = 7,
+};
+
 /* Commands with settype-specific attributes */
 enum ipset_adt {
        IPSET_ADD,
index 83c985a6170bd52938764732f45a70d09ae2a28e..c88ccbfda5f1b111a5fa43e1d1803bcccf95b521 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef _LINUX_NF_TABLES_H
 #define _LINUX_NF_TABLES_H
 
-#define NFT_CHAIN_MAXNAMELEN 32
+#define NFT_CHAIN_MAXNAMELEN   32
+#define NFT_USERDATA_MAXLEN    256
 
 enum nft_registers {
        NFT_REG_VERDICT,
@@ -156,6 +157,7 @@ enum nft_chain_attributes {
  * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
  * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
  * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
@@ -165,6 +167,7 @@ enum nft_rule_attributes {
        NFTA_RULE_EXPRESSIONS,
        NFTA_RULE_COMPAT,
        NFTA_RULE_POSITION,
+       NFTA_RULE_USERDATA,
        __NFTA_RULE_MAX
 };
 #define NFTA_RULE_MAX          (__NFTA_RULE_MAX - 1)
@@ -601,6 +604,7 @@ enum nft_ct_keys {
        NFT_CT_PROTOCOL,
        NFT_CT_PROTO_SRC,
        NFT_CT_PROTO_DST,
+       NFT_CT_LABELS,
 };
 
 /**
index 0b80c806631fc12d26a11d9f6e5d1f3b65e9066a..ada7f0171cccd3174810d1c9c0d6ea566c558c0a 100644 (file)
@@ -235,6 +235,18 @@ struct sadb_x_kmaddress {
 } __attribute__((packed));
 /* sizeof(struct sadb_x_kmaddress) == 8 */
 
+/* To specify the SA dump filter */
+struct sadb_x_filter {
+       __u16   sadb_x_filter_len;
+       __u16   sadb_x_filter_exttype;
+       __u32   sadb_x_filter_saddr[4];
+       __u32   sadb_x_filter_daddr[4];
+       __u16   sadb_x_filter_family;
+       __u8    sadb_x_filter_splen;
+       __u8    sadb_x_filter_dplen;
+} __attribute__((packed));
+/* sizeof(struct sadb_x_filter) == 40 */
+
 /* Message types */
 #define SADB_RESERVED          0
 #define SADB_GETSPI            1
@@ -358,7 +370,8 @@ struct sadb_x_kmaddress {
 #define SADB_X_EXT_SEC_CTX             24
 /* Used with MIGRATE to pass @ to IKE for negotiation */
 #define SADB_X_EXT_KMADDRESS           25
-#define SADB_EXT_MAX                   25
+#define SADB_X_EXT_FILTER              26
+#define SADB_EXT_MAX                   26
 
 /* Identity Extension values */
 #define SADB_IDENTTYPE_RESERVED        0
index b65c834f83e903c6dd00c062362a93bfd9a51aea..f0b7bfe5da920069a8acdca9dc018860495e0e59 100644 (file)
@@ -50,7 +50,8 @@ struct ptp_clock_caps {
        int n_ext_ts;  /* Number of external time stamp channels. */
        int n_per_out; /* Number of programmable periodic signals. */
        int pps;       /* Whether the clock supports a PPS callback. */
-       int rsv[15];   /* Reserved for future use. */
+       int n_pins;    /* Number of input/output pins. */
+       int rsv[14];   /* Reserved for future use. */
 };
 
 struct ptp_extts_request {
@@ -80,6 +81,40 @@ struct ptp_sys_offset {
        struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1];
 };
 
+enum ptp_pin_function {
+       PTP_PF_NONE,
+       PTP_PF_EXTTS,
+       PTP_PF_PEROUT,
+       PTP_PF_PHYSYNC,
+};
+
+struct ptp_pin_desc {
+       /*
+        * Hardware specific human readable pin name. This field is
+        * set by the kernel during the PTP_PIN_GETFUNC ioctl and is
+        * ignored for the PTP_PIN_SETFUNC ioctl.
+        */
+       char name[64];
+       /*
+        * Pin index in the range of zero to ptp_clock_caps.n_pins - 1.
+        */
+       unsigned int index;
+       /*
+        * Which of the PTP_PF_xxx functions to use on this pin.
+        */
+       unsigned int func;
+       /*
+        * The specific channel to use for this function.
+        * This corresponds to the 'index' field of the
+        * PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls.
+        */
+       unsigned int chan;
+       /*
+        * Reserved for future use.
+        */
+       unsigned int rsv[5];
+};
+
 #define PTP_CLK_MAGIC '='
 
 #define PTP_CLOCK_GETCAPS  _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
@@ -87,6 +122,8 @@ struct ptp_sys_offset {
 #define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request)
 #define PTP_ENABLE_PPS     _IOW(PTP_CLK_MAGIC, 4, int)
 #define PTP_SYS_OFFSET     _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset)
+#define PTP_PIN_GETFUNC    _IOWR(PTP_CLK_MAGIC, 6, struct ptp_pin_desc)
+#define PTP_PIN_SETFUNC    _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc)
 
 struct ptp_extts_event {
        struct ptp_clock_time t; /* Time event occured. */
index bbaba22f2d1bcfa25517acb1bf19fc8eb648c480..df40137f33dd48c0b23dad1f5cd13c357c91c031 100644 (file)
@@ -252,6 +252,7 @@ enum
        LINUX_MIB_TCPCHALLENGEACK,              /* TCPChallengeACK */
        LINUX_MIB_TCPSYNCHALLENGE,              /* TCPSYNChallenge */
        LINUX_MIB_TCPFASTOPENACTIVE,            /* TCPFastOpenActive */
+       LINUX_MIB_TCPFASTOPENACTIVEFAIL,        /* TCPFastOpenActiveFail */
        LINUX_MIB_TCPFASTOPENPASSIVE,           /* TCPFastOpenPassive*/
        LINUX_MIB_TCPFASTOPENPASSIVEFAIL,       /* TCPFastOpenPassiveFail */
        LINUX_MIB_TCPFASTOPENLISTENOVERFLOW,    /* TCPFastOpenListenOverflow */
@@ -259,6 +260,11 @@ enum
        LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */
        LINUX_MIB_BUSYPOLLRXPACKETS,            /* BusyPollRxPackets */
        LINUX_MIB_TCPAUTOCORKING,               /* TCPAutoCorking */
+       LINUX_MIB_TCPFROMZEROWINDOWADV,         /* TCPFromZeroWindowAdv */
+       LINUX_MIB_TCPTOZEROWINDOWADV,           /* TCPToZeroWindowAdv */
+       LINUX_MIB_TCPWANTZEROWINDOWADV,         /* TCPWantZeroWindowAdv */
+       LINUX_MIB_TCPSYNRETRANS,                /* TCPSynRetrans */
+       LINUX_MIB_TCPORIGDATASENT,              /* TCPOrigDataSent */
        __LINUX_MIB_MAX
 };
 
index 377f1e59411d1572eb645b7b80be42347a7513f5..3b9718328d8bf7732a73a13a4811b98ff667f000 100644 (file)
@@ -186,6 +186,9 @@ struct tcp_info {
        __u32   tcpi_rcv_space;
 
        __u32   tcpi_total_retrans;
+
+       __u64   tcpi_pacing_rate;
+       __u64   tcpi_max_pacing_rate;
 };
 
 /* for TCP_MD5SIG socket option */
index 54a37b13f2c4d77202d35d42e852689ddc9fcdd0..93533926035ca8d18e08f04eac3adacfcb266d8d 100644 (file)
 #define TCP_METRICS_GENL_VERSION       0x1
 
 enum tcp_metric_index {
-       TCP_METRIC_RTT,
-       TCP_METRIC_RTTVAR,
+       TCP_METRIC_RTT,         /* in ms units */
+       TCP_METRIC_RTTVAR,      /* in ms units */
        TCP_METRIC_SSTHRESH,
        TCP_METRIC_CWND,
        TCP_METRIC_REORDERING,
 
+       TCP_METRIC_RTT_US,      /* in usec units */
+       TCP_METRIC_RTTVAR_US,   /* in usec units */
+
        /* Always last.  */
        __TCP_METRIC_MAX,
 };
index f35aa0a338c7610d89aa7f9e92e47d7e3a0de0a2..b6a9cdd6e096a26831bcb5c1cc69e6d41c8afe05 100644 (file)
@@ -56,6 +56,7 @@
 #define USB_CDC_OBEX_TYPE              0x15
 #define USB_CDC_NCM_TYPE               0x1a
 #define USB_CDC_MBIM_TYPE              0x1b
+#define USB_CDC_MBIM_EXTENDED_TYPE     0x1c
 
 /* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
 struct usb_cdc_header_desc {
@@ -205,6 +206,17 @@ struct usb_cdc_mbim_desc {
        __u8    bmNetworkCapabilities;
 } __attribute__ ((packed));
 
+/* "MBIM Extended Functional Descriptor" from CDC MBIM spec 1.0 errata-1 */
+struct usb_cdc_mbim_extended_desc {
+       __u8    bLength;
+       __u8    bDescriptorType;
+       __u8    bDescriptorSubType;
+
+       __le16  bcdMBIMExtendedVersion;
+       __u8    bMaxOutstandingCommandMessages;
+       __le16  wMTU;
+} __attribute__ ((packed));
+
 /*-------------------------------------------------------------------------*/
 
 /*
index a8cd6a4a297070052a0e3deddafd9a05bca62c91..25e5dd916ba491feba3f1d570e8712283a95645e 100644 (file)
@@ -298,6 +298,8 @@ enum xfrm_attr_type_t {
        XFRMA_TFCPAD,           /* __u32 */
        XFRMA_REPLAY_ESN_VAL,   /* struct xfrm_replay_esn */
        XFRMA_SA_EXTRA_FLAGS,   /* __u32 */
+       XFRMA_PROTO,            /* __u8 */
+       XFRMA_ADDRESS_FILTER,   /* struct xfrm_address_filter */
        __XFRMA_MAX
 
 #define XFRMA_MAX (__XFRMA_MAX - 1)
@@ -474,6 +476,14 @@ struct xfrm_user_mapping {
        __be16                          new_sport;
 };
 
+struct xfrm_address_filter {
+       xfrm_address_t                  saddr;
+       xfrm_address_t                  daddr;
+       __u16                           family;
+       __u8                            splen;
+       __u8                            dplen;
+};
+
 #ifndef __KERNEL__
 /* backwards compatibility for userspace */
 #define XFRMGRP_ACQUIRE                1
index 61257cb146539364bdce89c3b15eff115b81902b..5c459628e8c7492c7eaea4bf6cc75e6976438e82 100644 (file)
@@ -1,3 +1,5 @@
 # UAPI Header export list
 header-y += evtchn.h
+header-y += gntalloc.h
+header-y += gntdev.h
 header-y += privcmd.h
diff --git a/include/uapi/xen/gntalloc.h b/include/uapi/xen/gntalloc.h
new file mode 100644 (file)
index 0000000..76bd580
--- /dev/null
@@ -0,0 +1,82 @@
+/******************************************************************************
+ * gntalloc.h
+ *
+ * Interface to /dev/xen/gntalloc.
+ *
+ * Author: Daniel De Graaf <dgdegra@tycho.nsa.gov>
+ *
+ * This file is in the public domain.
+ */
+
+#ifndef __LINUX_PUBLIC_GNTALLOC_H__
+#define __LINUX_PUBLIC_GNTALLOC_H__
+
+/*
+ * Allocates a new page and creates a new grant reference.
+ */
+#define IOCTL_GNTALLOC_ALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
+struct ioctl_gntalloc_alloc_gref {
+       /* IN parameters */
+       /* The ID of the domain to be given access to the grants. */
+       uint16_t domid;
+       /* Flags for this mapping */
+       uint16_t flags;
+       /* Number of pages to map */
+       uint32_t count;
+       /* OUT parameters */
+       /* The offset to be used on a subsequent call to mmap(). */
+       uint64_t index;
+       /* The grant references of the newly created grant, one per page */
+       /* Variable size, depending on count */
+       uint32_t gref_ids[1];
+};
+
+#define GNTALLOC_FLAG_WRITABLE 1
+
+/*
+ * Deallocates the grant reference, allowing the associated page to be freed if
+ * no other domains are using it.
+ */
+#define IOCTL_GNTALLOC_DEALLOC_GREF \
+_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
+struct ioctl_gntalloc_dealloc_gref {
+       /* IN parameters */
+       /* The offset returned in the map operation */
+       uint64_t index;
+       /* Number of references to unmap */
+       uint32_t count;
+};
+
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
+struct ioctl_gntalloc_unmap_notify {
+       /* IN parameters */
+       /* Offset in the file descriptor for a byte within the page (same as
+        * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+        * be cleared. Otherwise, it can be any byte in the page whose
+        * notification we are adjusting.
+        */
+       uint64_t index;
+       /* Action(s) to take on unmap */
+       uint32_t action;
+       /* Event channel to notify */
+       uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+#endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
diff --git a/include/uapi/xen/gntdev.h b/include/uapi/xen/gntdev.h
new file mode 100644 (file)
index 0000000..5304bd3
--- /dev/null
@@ -0,0 +1,150 @@
+/******************************************************************************
+ * gntdev.h
+ * 
+ * Interface to /dev/xen/gntdev.
+ * 
+ * Copyright (c) 2007, D G Murray
+ * 
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (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.
+ */
+
+#ifndef __LINUX_PUBLIC_GNTDEV_H__
+#define __LINUX_PUBLIC_GNTDEV_H__
+
+struct ioctl_gntdev_grant_ref {
+       /* The domain ID of the grant to be mapped. */
+       uint32_t domid;
+       /* The grant reference of the grant to be mapped. */
+       uint32_t ref;
+};
+
+/*
+ * Inserts the grant references into the mapping table of an instance
+ * of gntdev. N.B. This does not perform the mapping, which is deferred
+ * until mmap() is called with @index as the offset.
+ */
+#define IOCTL_GNTDEV_MAP_GRANT_REF \
+_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
+struct ioctl_gntdev_map_grant_ref {
+       /* IN parameters */
+       /* The number of grants to be mapped. */
+       uint32_t count;
+       uint32_t pad;
+       /* OUT parameters */
+       /* The offset to be used on a subsequent call to mmap(). */
+       uint64_t index;
+       /* Variable IN parameter. */
+       /* Array of grant references, of size @count. */
+       struct ioctl_gntdev_grant_ref refs[1];
+};
+
+/*
+ * Removes the grant references from the mapping table of an instance of
+ * of gntdev. N.B. munmap() must be called on the relevant virtual address(es)
+ * before this ioctl is called, or an error will result.
+ */
+#define IOCTL_GNTDEV_UNMAP_GRANT_REF \
+_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))
+struct ioctl_gntdev_unmap_grant_ref {
+       /* IN parameters */
+       /* The offset was returned by the corresponding map operation. */
+       uint64_t index;
+       /* The number of pages to be unmapped. */
+       uint32_t count;
+       uint32_t pad;
+};
+
+/*
+ * Returns the offset in the driver's address space that corresponds
+ * to @vaddr. This can be used to perform a munmap(), followed by an
+ * UNMAP_GRANT_REF ioctl, where no state about the offset is retained by
+ * the caller. The number of pages that were allocated at the same time as
+ * @vaddr is returned in @count.
+ *
+ * N.B. Where more than one page has been mapped into a contiguous range, the
+ *      supplied @vaddr must correspond to the start of the range; otherwise
+ *      an error will result. It is only possible to munmap() the entire
+ *      contiguously-allocated range at once, and not any subrange thereof.
+ */
+#define IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR \
+_IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr))
+struct ioctl_gntdev_get_offset_for_vaddr {
+       /* IN parameters */
+       /* The virtual address of the first mapped page in a range. */
+       uint64_t vaddr;
+       /* OUT parameters */
+       /* The offset that was used in the initial mmap() operation. */
+       uint64_t offset;
+       /* The number of pages mapped in the VM area that begins at @vaddr. */
+       uint32_t count;
+       uint32_t pad;
+};
+
+/*
+ * Sets the maximum number of grants that may mapped at once by this gntdev
+ * instance.
+ *
+ * N.B. This must be called before any other ioctl is performed on the device.
+ */
+#define IOCTL_GNTDEV_SET_MAX_GRANTS \
+_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
+struct ioctl_gntdev_set_max_grants {
+       /* IN parameter */
+       /* The maximum number of grants that may be mapped at once. */
+       uint32_t count;
+};
+
+/*
+ * Sets up an unmap notification within the page, so that the other side can do
+ * cleanup if this side crashes. Required to implement cross-domain robust
+ * mutexes or close notification on communication channels.
+ *
+ * Each mapped page only supports one notification; multiple calls referring to
+ * the same page overwrite the previous notification. You must clear the
+ * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
+ * to occur.
+ */
+#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
+_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
+struct ioctl_gntdev_unmap_notify {
+       /* IN parameters */
+       /* Offset in the file descriptor for a byte within the page (same as
+        * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
+        * be cleared. Otherwise, it can be any byte in the page whose
+        * notification we are adjusting.
+        */
+       uint64_t index;
+       /* Action(s) to take on unmap */
+       uint32_t action;
+       /* Event channel to notify */
+       uint32_t event_channel_port;
+};
+
+/* Clear (set to zero) the byte specified by index */
+#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
+/* Send an interrupt on the indicated event channel */
+#define UNMAP_NOTIFY_SEND_EVENT 0x2
+
+#endif /* __LINUX_PUBLIC_GNTDEV_H__ */
diff --git a/include/xen/gntalloc.h b/include/xen/gntalloc.h
deleted file mode 100644 (file)
index 76bd580..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/******************************************************************************
- * gntalloc.h
- *
- * Interface to /dev/xen/gntalloc.
- *
- * Author: Daniel De Graaf <dgdegra@tycho.nsa.gov>
- *
- * This file is in the public domain.
- */
-
-#ifndef __LINUX_PUBLIC_GNTALLOC_H__
-#define __LINUX_PUBLIC_GNTALLOC_H__
-
-/*
- * Allocates a new page and creates a new grant reference.
- */
-#define IOCTL_GNTALLOC_ALLOC_GREF \
-_IOC(_IOC_NONE, 'G', 5, sizeof(struct ioctl_gntalloc_alloc_gref))
-struct ioctl_gntalloc_alloc_gref {
-       /* IN parameters */
-       /* The ID of the domain to be given access to the grants. */
-       uint16_t domid;
-       /* Flags for this mapping */
-       uint16_t flags;
-       /* Number of pages to map */
-       uint32_t count;
-       /* OUT parameters */
-       /* The offset to be used on a subsequent call to mmap(). */
-       uint64_t index;
-       /* The grant references of the newly created grant, one per page */
-       /* Variable size, depending on count */
-       uint32_t gref_ids[1];
-};
-
-#define GNTALLOC_FLAG_WRITABLE 1
-
-/*
- * Deallocates the grant reference, allowing the associated page to be freed if
- * no other domains are using it.
- */
-#define IOCTL_GNTALLOC_DEALLOC_GREF \
-_IOC(_IOC_NONE, 'G', 6, sizeof(struct ioctl_gntalloc_dealloc_gref))
-struct ioctl_gntalloc_dealloc_gref {
-       /* IN parameters */
-       /* The offset returned in the map operation */
-       uint64_t index;
-       /* Number of references to unmap */
-       uint32_t count;
-};
-
-/*
- * Sets up an unmap notification within the page, so that the other side can do
- * cleanup if this side crashes. Required to implement cross-domain robust
- * mutexes or close notification on communication channels.
- *
- * Each mapped page only supports one notification; multiple calls referring to
- * the same page overwrite the previous notification. You must clear the
- * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
- * to occur.
- */
-#define IOCTL_GNTALLOC_SET_UNMAP_NOTIFY \
-_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntalloc_unmap_notify))
-struct ioctl_gntalloc_unmap_notify {
-       /* IN parameters */
-       /* Offset in the file descriptor for a byte within the page (same as
-        * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
-        * be cleared. Otherwise, it can be any byte in the page whose
-        * notification we are adjusting.
-        */
-       uint64_t index;
-       /* Action(s) to take on unmap */
-       uint32_t action;
-       /* Event channel to notify */
-       uint32_t event_channel_port;
-};
-
-/* Clear (set to zero) the byte specified by index */
-#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
-/* Send an interrupt on the indicated event channel */
-#define UNMAP_NOTIFY_SEND_EVENT 0x2
-
-#endif /* __LINUX_PUBLIC_GNTALLOC_H__ */
diff --git a/include/xen/gntdev.h b/include/xen/gntdev.h
deleted file mode 100644 (file)
index 5304bd3..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/******************************************************************************
- * gntdev.h
- * 
- * Interface to /dev/xen/gntdev.
- * 
- * Copyright (c) 2007, D G Murray
- * 
- * 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; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (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.
- */
-
-#ifndef __LINUX_PUBLIC_GNTDEV_H__
-#define __LINUX_PUBLIC_GNTDEV_H__
-
-struct ioctl_gntdev_grant_ref {
-       /* The domain ID of the grant to be mapped. */
-       uint32_t domid;
-       /* The grant reference of the grant to be mapped. */
-       uint32_t ref;
-};
-
-/*
- * Inserts the grant references into the mapping table of an instance
- * of gntdev. N.B. This does not perform the mapping, which is deferred
- * until mmap() is called with @index as the offset.
- */
-#define IOCTL_GNTDEV_MAP_GRANT_REF \
-_IOC(_IOC_NONE, 'G', 0, sizeof(struct ioctl_gntdev_map_grant_ref))
-struct ioctl_gntdev_map_grant_ref {
-       /* IN parameters */
-       /* The number of grants to be mapped. */
-       uint32_t count;
-       uint32_t pad;
-       /* OUT parameters */
-       /* The offset to be used on a subsequent call to mmap(). */
-       uint64_t index;
-       /* Variable IN parameter. */
-       /* Array of grant references, of size @count. */
-       struct ioctl_gntdev_grant_ref refs[1];
-};
-
-/*
- * Removes the grant references from the mapping table of an instance of
- * of gntdev. N.B. munmap() must be called on the relevant virtual address(es)
- * before this ioctl is called, or an error will result.
- */
-#define IOCTL_GNTDEV_UNMAP_GRANT_REF \
-_IOC(_IOC_NONE, 'G', 1, sizeof(struct ioctl_gntdev_unmap_grant_ref))
-struct ioctl_gntdev_unmap_grant_ref {
-       /* IN parameters */
-       /* The offset was returned by the corresponding map operation. */
-       uint64_t index;
-       /* The number of pages to be unmapped. */
-       uint32_t count;
-       uint32_t pad;
-};
-
-/*
- * Returns the offset in the driver's address space that corresponds
- * to @vaddr. This can be used to perform a munmap(), followed by an
- * UNMAP_GRANT_REF ioctl, where no state about the offset is retained by
- * the caller. The number of pages that were allocated at the same time as
- * @vaddr is returned in @count.
- *
- * N.B. Where more than one page has been mapped into a contiguous range, the
- *      supplied @vaddr must correspond to the start of the range; otherwise
- *      an error will result. It is only possible to munmap() the entire
- *      contiguously-allocated range at once, and not any subrange thereof.
- */
-#define IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR \
-_IOC(_IOC_NONE, 'G', 2, sizeof(struct ioctl_gntdev_get_offset_for_vaddr))
-struct ioctl_gntdev_get_offset_for_vaddr {
-       /* IN parameters */
-       /* The virtual address of the first mapped page in a range. */
-       uint64_t vaddr;
-       /* OUT parameters */
-       /* The offset that was used in the initial mmap() operation. */
-       uint64_t offset;
-       /* The number of pages mapped in the VM area that begins at @vaddr. */
-       uint32_t count;
-       uint32_t pad;
-};
-
-/*
- * Sets the maximum number of grants that may mapped at once by this gntdev
- * instance.
- *
- * N.B. This must be called before any other ioctl is performed on the device.
- */
-#define IOCTL_GNTDEV_SET_MAX_GRANTS \
-_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
-struct ioctl_gntdev_set_max_grants {
-       /* IN parameter */
-       /* The maximum number of grants that may be mapped at once. */
-       uint32_t count;
-};
-
-/*
- * Sets up an unmap notification within the page, so that the other side can do
- * cleanup if this side crashes. Required to implement cross-domain robust
- * mutexes or close notification on communication channels.
- *
- * Each mapped page only supports one notification; multiple calls referring to
- * the same page overwrite the previous notification. You must clear the
- * notification prior to the IOCTL_GNTALLOC_DEALLOC_GREF if you do not want it
- * to occur.
- */
-#define IOCTL_GNTDEV_SET_UNMAP_NOTIFY \
-_IOC(_IOC_NONE, 'G', 7, sizeof(struct ioctl_gntdev_unmap_notify))
-struct ioctl_gntdev_unmap_notify {
-       /* IN parameters */
-       /* Offset in the file descriptor for a byte within the page (same as
-        * used in mmap). If using UNMAP_NOTIFY_CLEAR_BYTE, this is the byte to
-        * be cleared. Otherwise, it can be any byte in the page whose
-        * notification we are adjusting.
-        */
-       uint64_t index;
-       /* Action(s) to take on unmap */
-       uint32_t action;
-       /* Event channel to notify */
-       uint32_t event_channel_port;
-};
-
-/* Clear (set to zero) the byte specified by index */
-#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
-/* Send an interrupt on the indicated event channel */
-#define UNMAP_NOTIFY_SEND_EVENT 0x2
-
-#endif /* __LINUX_PUBLIC_GNTDEV_H__ */
index ae665ac59c36b6812a0470d5a7e0124c3e13a69f..32ec05a6572f779cb735b7a9b3ca5567cd1aed8f 100644 (file)
@@ -113,13 +113,13 @@ typedef uint64_t blkif_sector_t;
  * it's less than the number provided by the backend. The indirect_grefs field
  * in blkif_request_indirect should be filled by the frontend with the
  * grant references of the pages that are holding the indirect segments.
- * This pages are filled with an array of blkif_request_segment_aligned
- * that hold the information about the segments. The number of indirect
- * pages to use is determined by the maximum number of segments
- * a indirect request contains. Every indirect page can contain a maximum
- * of 512 segments (PAGE_SIZE/sizeof(blkif_request_segment_aligned)),
- * so to calculate the number of indirect pages to use we have to do
- * ceil(indirect_segments/512).
+ * These pages are filled with an array of blkif_request_segment that hold the
+ * information about the segments. The number of indirect pages to use is
+ * determined by the number of segments an indirect request contains. Every
+ * indirect page can contain a maximum of
+ * (PAGE_SIZE / sizeof(struct blkif_request_segment)) segments, so to
+ * calculate the number of indirect pages to use we have to do
+ * ceil(indirect_segments / (PAGE_SIZE / sizeof(struct blkif_request_segment))).
  *
  * If a backend does not recognize BLKIF_OP_INDIRECT, it should *not*
  * create the "feature-max-indirect-segments" node!
@@ -135,13 +135,12 @@ typedef uint64_t blkif_sector_t;
 
 #define BLKIF_MAX_INDIRECT_PAGES_PER_REQUEST 8
 
-struct blkif_request_segment_aligned {
-       grant_ref_t gref;        /* reference to I/O buffer frame        */
-       /* @first_sect: first sector in frame to transfer (inclusive).   */
-       /* @last_sect: last sector in frame to transfer (inclusive).     */
-       uint8_t     first_sect, last_sect;
-       uint16_t    _pad; /* padding to make it 8 bytes, so it's cache-aligned */
-} __attribute__((__packed__));
+struct blkif_request_segment {
+               grant_ref_t gref;        /* reference to I/O buffer frame        */
+               /* @first_sect: first sector in frame to transfer (inclusive).   */
+               /* @last_sect: last sector in frame to transfer (inclusive).     */
+               uint8_t     first_sect, last_sect;
+};
 
 struct blkif_request_rw {
        uint8_t        nr_segments;  /* number of segments                   */
@@ -151,12 +150,7 @@ struct blkif_request_rw {
 #endif
        uint64_t       id;           /* private guest value, echoed in resp  */
        blkif_sector_t sector_number;/* start sector idx on disk (r/w only)  */
-       struct blkif_request_segment {
-               grant_ref_t gref;        /* reference to I/O buffer frame        */
-               /* @first_sect: first sector in frame to transfer (inclusive).   */
-               /* @last_sect: last sector in frame to transfer (inclusive).     */
-               uint8_t     first_sect, last_sect;
-       } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+       struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 } __attribute__((__packed__));
 
 struct blkif_request_discard {
diff --git a/include/xen/interface/xencomm.h b/include/xen/interface/xencomm.h
deleted file mode 100644 (file)
index ac45e07..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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) IBM Corp. 2006
- */
-
-#ifndef _XEN_XENCOMM_H_
-#define _XEN_XENCOMM_H_
-
-/* A xencomm descriptor is a scatter/gather list containing physical
- * addresses corresponding to a virtually contiguous memory area. The
- * hypervisor translates these physical addresses to machine addresses to copy
- * to and from the virtually contiguous area.
- */
-
-#define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */
-#define XENCOMM_INVALID (~0UL)
-
-struct xencomm_desc {
-    uint32_t magic;
-    uint32_t nr_addrs; /* the number of entries in address[] */
-    uint64_t address[0];
-};
-
-#endif /* _XEN_XENCOMM_H_ */
diff --git a/include/xen/xencomm.h b/include/xen/xencomm.h
deleted file mode 100644 (file)
index e43b039..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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
- *
- * Copyright (C) IBM Corp. 2006
- *
- * Authors: Hollis Blanchard <hollisb@us.ibm.com>
- *          Jerone Young <jyoung5@us.ibm.com>
- */
-
-#ifndef _LINUX_XENCOMM_H_
-#define _LINUX_XENCOMM_H_
-
-#include <xen/interface/xencomm.h>
-
-#define XENCOMM_MINI_ADDRS 3
-struct xencomm_mini {
-       struct xencomm_desc _desc;
-       uint64_t address[XENCOMM_MINI_ADDRS];
-};
-
-/* To avoid additionnal virt to phys conversion, an opaque structure is
-   presented.  */
-struct xencomm_handle;
-
-extern void xencomm_free(struct xencomm_handle *desc);
-extern struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes);
-extern struct xencomm_handle *__xencomm_map_no_alloc(void *ptr,
-                       unsigned long bytes,  struct xencomm_mini *xc_area);
-
-#if 0
-#define XENCOMM_MINI_ALIGNED(xc_desc, n)                               \
-       struct xencomm_mini xc_desc ## _base[(n)]                       \
-       __attribute__((__aligned__(sizeof(struct xencomm_mini))));      \
-       struct xencomm_mini *xc_desc = &xc_desc ## _base[0];
-#else
-/*
- * gcc bug workaround:
- * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660
- * gcc doesn't handle properly stack variable with
- * __attribute__((__align__(sizeof(struct xencomm_mini))))
- */
-#define XENCOMM_MINI_ALIGNED(xc_desc, n)                               \
-       unsigned char xc_desc ## _base[((n) + 1 ) *                     \
-                                      sizeof(struct xencomm_mini)];    \
-       struct xencomm_mini *xc_desc = (struct xencomm_mini *)          \
-               ((unsigned long)xc_desc ## _base +                      \
-                (sizeof(struct xencomm_mini) -                         \
-                 ((unsigned long)xc_desc ## _base) %                   \
-                 sizeof(struct xencomm_mini)));
-#endif
-#define xencomm_map_no_alloc(ptr, bytes)                       \
-       ({ XENCOMM_MINI_ALIGNED(xc_desc, 1);                    \
-               __xencomm_map_no_alloc(ptr, bytes, xc_desc); })
-
-/* provided by architecture code: */
-extern unsigned long xencomm_vtop(unsigned long vaddr);
-
-static inline void *xencomm_pa(void *ptr)
-{
-       return (void *)xencomm_vtop((unsigned long)ptr);
-}
-
-#define xen_guest_handle(hnd)  ((hnd).p)
-
-#endif /* _LINUX_XENCOMM_H_ */
index eb03090cdced5aac82787cf3154c2430b7410924..9c7fd4c9249f2c72395fcaf2ac953f782a3e2b59 100644 (file)
@@ -561,7 +561,6 @@ asmlinkage void __init start_kernel(void)
        init_timers();
        hrtimers_init();
        softirq_init();
-       acpi_early_init();
        timekeeping_init();
        time_init();
        sched_clock_postinit();
@@ -613,6 +612,7 @@ asmlinkage void __init start_kernel(void)
        calibrate_delay();
        pidmap_init();
        anon_vma_init();
+       acpi_early_init();
 #ifdef CONFIG_X86
        if (efi_enabled(EFI_RUNTIME_SERVICES))
                efi_enter_virtual_mode();
index 383d638340b8417c8e31f53b935f8e8d833b2707..5bb8bfe671496e55b6c62df1d28922454a2a2dcf 100644 (file)
@@ -22,6 +22,16 @@ static void *get_mq(ctl_table *table)
        return which;
 }
 
+static int proc_mq_dointvec(ctl_table *table, int write,
+                           void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+       struct ctl_table mq_table;
+       memcpy(&mq_table, table, sizeof(mq_table));
+       mq_table.data = get_mq(table);
+
+       return proc_dointvec(&mq_table, write, buffer, lenp, ppos);
+}
+
 static int proc_mq_dointvec_minmax(ctl_table *table, int write,
        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -33,12 +43,10 @@ static int proc_mq_dointvec_minmax(ctl_table *table, int write,
                                        lenp, ppos);
 }
 #else
+#define proc_mq_dointvec NULL
 #define proc_mq_dointvec_minmax NULL
 #endif
 
-static int msg_queues_limit_min = MIN_QUEUESMAX;
-static int msg_queues_limit_max = HARD_QUEUESMAX;
-
 static int msg_max_limit_min = MIN_MSGMAX;
 static int msg_max_limit_max = HARD_MSGMAX;
 
@@ -51,9 +59,7 @@ static ctl_table mq_sysctls[] = {
                .data           = &init_ipc_ns.mq_queues_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_mq_dointvec_minmax,
-               .extra1         = &msg_queues_limit_min,
-               .extra2         = &msg_queues_limit_max,
+               .proc_handler   = proc_mq_dointvec,
        },
        {
                .procname       = "msg_max",
index ccf1f9fd263acdfae7dc56a87bceddd3170f69d9..c3b31179122c326342597d40cd58db11d51da940 100644 (file)
@@ -433,9 +433,9 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry,
                error = -EACCES;
                goto out_unlock;
        }
-       if (ipc_ns->mq_queues_count >= HARD_QUEUESMAX ||
-           (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
-            !capable(CAP_SYS_RESOURCE))) {
+
+       if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
+           !capable(CAP_SYS_RESOURCE)) {
                error = -ENOSPC;
                goto out_unlock;
        }
index 245db1140ad66a2be47744f02ef0d80deea5006f..649853105a5d773d30fac9929327030cad118a67 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -901,6 +901,8 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                return -EINVAL;
 
        if (msgflg & MSG_COPY) {
+               if ((msgflg & MSG_EXCEPT) || !(msgflg & IPC_NOWAIT))
+                       return -EINVAL;
                copy = prepare_copy(buf, min_t(size_t, bufsz, ns->msg_ctlmax));
                if (IS_ERR(copy))
                        return PTR_ERR(copy);
index 34c5a2310fbf9545eeff2e3fa803c8a361031bb3..3392d3e0254ac5d93199c0b00e271cbb0b2bfc9c 100644 (file)
@@ -182,7 +182,7 @@ struct audit_buffer {
 
 struct audit_reply {
        __u32 portid;
-       pid_t pid;
+       struct net *net;        
        struct sk_buff *skb;
 };
 
@@ -500,7 +500,7 @@ int audit_send_list(void *_dest)
 {
        struct audit_netlink_list *dest = _dest;
        struct sk_buff *skb;
-       struct net *net = get_net_ns_by_pid(dest->pid);
+       struct net *net = dest->net;
        struct audit_net *aunet = net_generic(net, audit_net_id);
 
        /* wait for parent to finish and send an ACK */
@@ -510,6 +510,7 @@ int audit_send_list(void *_dest)
        while ((skb = __skb_dequeue(&dest->q)) != NULL)
                netlink_unicast(aunet->nlsk, skb, dest->portid, 0);
 
+       put_net(net);
        kfree(dest);
 
        return 0;
@@ -543,7 +544,7 @@ out_kfree_skb:
 static int audit_send_reply_thread(void *arg)
 {
        struct audit_reply *reply = (struct audit_reply *)arg;
-       struct net *net = get_net_ns_by_pid(reply->pid);
+       struct net *net = reply->net;
        struct audit_net *aunet = net_generic(net, audit_net_id);
 
        mutex_lock(&audit_cmd_mutex);
@@ -552,12 +553,13 @@ static int audit_send_reply_thread(void *arg)
        /* Ignore failure. It'll only happen if the sender goes away,
           because our timeout is set to infinite. */
        netlink_unicast(aunet->nlsk , reply->skb, reply->portid, 0);
+       put_net(net);
        kfree(reply);
        return 0;
 }
 /**
  * audit_send_reply - send an audit reply message via netlink
- * @portid: netlink port to which to send reply
+ * @request_skb: skb of request we are replying to (used to target the reply)
  * @seq: sequence number
  * @type: audit message type
  * @done: done (last) flag
@@ -568,9 +570,11 @@ static int audit_send_reply_thread(void *arg)
  * Allocates an skb, builds the netlink message, and sends it to the port id.
  * No failure notifications.
  */
-static void audit_send_reply(__u32 portid, int seq, int type, int done,
+static void audit_send_reply(struct sk_buff *request_skb, int seq, int type, int done,
                             int multi, const void *payload, int size)
 {
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
        struct sk_buff *skb;
        struct task_struct *tsk;
        struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
@@ -583,8 +587,8 @@ static void audit_send_reply(__u32 portid, int seq, int type, int done,
        if (!skb)
                goto out;
 
+       reply->net = get_net(net);
        reply->portid = portid;
-       reply->pid = task_pid_vnr(current);
        reply->skb = skb;
 
        tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
@@ -673,8 +677,7 @@ static int audit_get_feature(struct sk_buff *skb)
 
        seq = nlmsg_hdr(skb)->nlmsg_seq;
 
-       audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
-                        &af, sizeof(af));
+       audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &af, sizeof(af));
 
        return 0;
 }
@@ -794,8 +797,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                s.backlog               = skb_queue_len(&audit_skb_queue);
                s.version               = AUDIT_VERSION_LATEST;
                s.backlog_wait_time     = audit_backlog_wait_time;
-               audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
-                                &s, sizeof(s));
+               audit_send_reply(skb, seq, AUDIT_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_SET: {
@@ -905,7 +907,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                           seq, data, nlmsg_len(nlh));
                break;
        case AUDIT_LIST_RULES:
-               err = audit_list_rules_send(NETLINK_CB(skb).portid, seq);
+               err = audit_list_rules_send(skb, seq);
                break;
        case AUDIT_TRIM:
                audit_trim_trees();
@@ -970,8 +972,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                        memcpy(sig_data->ctx, ctx, len);
                        security_release_secctx(ctx, len);
                }
-               audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_SIGNAL_INFO,
-                               0, 0, sig_data, sizeof(*sig_data) + len);
+               audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0,
+                                sig_data, sizeof(*sig_data) + len);
                kfree(sig_data);
                break;
        case AUDIT_TTY_GET: {
@@ -983,8 +985,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                s.log_passwd = tsk->signal->audit_tty_log_passwd;
                spin_unlock(&tsk->sighand->siglock);
 
-               audit_send_reply(NETLINK_CB(skb).portid, seq,
-                                AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
+               audit_send_reply(skb, seq, AUDIT_TTY_GET, 0, 0, &s, sizeof(s));
                break;
        }
        case AUDIT_TTY_SET: {
index 57cc64d67718903eebeab175030348df648b4f17..8df132214606f2b06e08e916196779b1aee64ad6 100644 (file)
@@ -247,7 +247,7 @@ extern void             audit_panic(const char *message);
 
 struct audit_netlink_list {
        __u32 portid;
-       pid_t pid;
+       struct net *net;
        struct sk_buff_head q;
 };
 
index 67ccf0e7cca92412f457175d5ff3e784b254966a..135944a7b28ab901a400d06fd583d831ac8167b9 100644 (file)
@@ -916,7 +916,7 @@ static int audit_tree_handle_event(struct fsnotify_group *group,
                                   struct fsnotify_mark *inode_mark,
                                   struct fsnotify_mark *vfsmount_mark,
                                   u32 mask, void *data, int data_type,
-                                  const unsigned char *file_name)
+                                  const unsigned char *file_name, u32 cookie)
 {
        return 0;
 }
index 2596fac5dcb4552a0d574decada597424df0587b..70b4554d2fbe093e4f83a045ed84705c7a9cffe0 100644 (file)
@@ -471,7 +471,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
                                    struct fsnotify_mark *inode_mark,
                                    struct fsnotify_mark *vfsmount_mark,
                                    u32 mask, void *data, int data_type,
-                                   const unsigned char *dname)
+                                   const unsigned char *dname, u32 cookie)
 {
        struct inode *inode;
        struct audit_parent *parent;
index 14a78cca384edb9cf8f36dc3f7fb5340c267c623..92062fd6cc8cec4deff933c04848782bfdcded11 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/security.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
 #include "audit.h"
 
 /*
@@ -1065,11 +1067,13 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
 
 /**
  * audit_list_rules_send - list the audit rules
- * @portid: target portid for netlink audit messages
+ * @request_skb: skb of request we are replying to (used to target the reply)
  * @seq: netlink audit message sequence (serial) number
  */
-int audit_list_rules_send(__u32 portid, int seq)
+int audit_list_rules_send(struct sk_buff *request_skb, int seq)
 {
+       u32 portid = NETLINK_CB(request_skb).portid;
+       struct net *net = sock_net(NETLINK_CB(request_skb).sk);
        struct task_struct *tsk;
        struct audit_netlink_list *dest;
        int err = 0;
@@ -1083,8 +1087,8 @@ int audit_list_rules_send(__u32 portid, int seq)
        dest = kmalloc(sizeof(struct audit_netlink_list), GFP_KERNEL);
        if (!dest)
                return -ENOMEM;
+       dest->net = get_net(net);
        dest->portid = portid;
-       dest->pid = task_pid_vnr(current);
        skb_queue_head_init(&dest->q);
 
        mutex_lock(&audit_filter_mutex);
index e2f46ba37f7243c4278de77a8c8536ddc4c0aad5..0c753ddd223bf9d543dfbb2d89915a08ab537f46 100644 (file)
@@ -886,7 +886,9 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
                 * per-subsystem and moved to css->id so that lookups are
                 * successful until the target css is released.
                 */
+               mutex_lock(&cgroup_mutex);
                idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+               mutex_unlock(&cgroup_mutex);
                cgrp->id = -1;
 
                call_rcu(&cgrp->rcu_head, cgroup_free_rcu);
@@ -1566,10 +1568,10 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                mutex_lock(&cgroup_mutex);
                mutex_lock(&cgroup_root_mutex);
 
-               root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp,
-                                          0, 1, GFP_KERNEL);
-               if (root_cgrp->id < 0)
+               ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL);
+               if (ret < 0)
                        goto unlock_drop;
+               root_cgrp->id = ret;
 
                /* Check for name clashes with existing mounts */
                ret = -EBUSY;
@@ -2763,10 +2765,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
         */
        update_before = cgroup_serial_nr_next;
 
-       mutex_unlock(&cgroup_mutex);
-
        /* add/rm files for all cgroups created before */
-       rcu_read_lock();
        css_for_each_descendant_pre(css, cgroup_css(root, ss)) {
                struct cgroup *cgrp = css->cgroup;
 
@@ -2775,23 +2774,19 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add)
 
                inode = cgrp->dentry->d_inode;
                dget(cgrp->dentry);
-               rcu_read_unlock();
-
                dput(prev);
                prev = cgrp->dentry;
 
+               mutex_unlock(&cgroup_mutex);
                mutex_lock(&inode->i_mutex);
                mutex_lock(&cgroup_mutex);
                if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp))
                        ret = cgroup_addrm_files(cgrp, cfts, is_add);
-               mutex_unlock(&cgroup_mutex);
                mutex_unlock(&inode->i_mutex);
-
-               rcu_read_lock();
                if (ret)
                        break;
        }
-       rcu_read_unlock();
+       mutex_unlock(&cgroup_mutex);
        dput(prev);
        deactivate_super(sb);
        return ret;
@@ -2910,9 +2905,14 @@ static void cgroup_enable_task_cg_lists(void)
                 * We should check if the process is exiting, otherwise
                 * it will race with cgroup_exit() in that the list
                 * entry won't be deleted though the process has exited.
+                * Do it while holding siglock so that we don't end up
+                * racing against cgroup_exit().
                 */
+               spin_lock_irq(&p->sighand->siglock);
                if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list))
                        list_add(&p->cg_list, &task_css_set(p)->tasks);
+               spin_unlock_irq(&p->sighand->siglock);
+
                task_unlock(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
@@ -4112,17 +4112,17 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
 
        err = percpu_ref_init(&css->refcnt, css_release);
        if (err)
-               goto err_free;
+               goto err_free_css;
 
        init_css(css, ss, cgrp);
 
        err = cgroup_populate_dir(cgrp, 1 << ss->subsys_id);
        if (err)
-               goto err_free;
+               goto err_free_percpu_ref;
 
        err = online_css(css);
        if (err)
-               goto err_free;
+               goto err_clear_dir;
 
        dget(cgrp->dentry);
        css_get(css->parent);
@@ -4138,8 +4138,11 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
 
        return 0;
 
-err_free:
+err_clear_dir:
+       cgroup_clear_dir(css->cgroup, 1 << css->ss->subsys_id);
+err_free_percpu_ref:
        percpu_ref_cancel_init(&css->refcnt);
+err_free_css:
        ss->css_free(css);
        return err;
 }
@@ -4158,7 +4161,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
        struct cgroup *cgrp;
        struct cgroup_name *name;
        struct cgroupfs_root *root = parent->root;
-       int ssid, err = 0;
+       int ssid, err;
        struct cgroup_subsys *ss;
        struct super_block *sb = root->sb;
 
@@ -4168,18 +4171,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                return -ENOMEM;
 
        name = cgroup_alloc_name(dentry);
-       if (!name)
+       if (!name) {
+               err = -ENOMEM;
                goto err_free_cgrp;
+       }
        rcu_assign_pointer(cgrp->name, name);
 
-       /*
-        * Temporarily set the pointer to NULL, so idr_find() won't return
-        * a half-baked cgroup.
-        */
-       cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
-       if (cgrp->id < 0)
-               goto err_free_name;
-
        /*
         * Only live parents can have children.  Note that the liveliness
         * check isn't strictly necessary because cgroup_mkdir() and
@@ -4189,7 +4186,17 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
         */
        if (!cgroup_lock_live_group(parent)) {
                err = -ENODEV;
-               goto err_free_id;
+               goto err_free_name;
+       }
+
+       /*
+        * Temporarily set the pointer to NULL, so idr_find() won't return
+        * a half-baked cgroup.
+        */
+       cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
+       if (cgrp->id < 0) {
+               err = -ENOMEM;
+               goto err_unlock;
        }
 
        /* Grab a reference on the superblock so the hierarchy doesn't
@@ -4221,7 +4228,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
         */
        err = cgroup_create_file(dentry, S_IFDIR | mode, sb);
        if (err < 0)
-               goto err_unlock;
+               goto err_free_id;
        lockdep_assert_held(&dentry->d_inode->i_mutex);
 
        cgrp->serial_nr = cgroup_serial_nr_next++;
@@ -4257,12 +4264,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
 
        return 0;
 
-err_unlock:
-       mutex_unlock(&cgroup_mutex);
-       /* Release the reference count that we took on the superblock */
-       deactivate_super(sb);
 err_free_id:
        idr_remove(&root->cgroup_idr, cgrp->id);
+       /* Release the reference count that we took on the superblock */
+       deactivate_super(sb);
+err_unlock:
+       mutex_unlock(&cgroup_mutex);
 err_free_name:
        kfree(rcu_dereference_raw(cgrp->name));
 err_free_cgrp:
index 4410ac6a55f1d9ae410976e3a8e7315acf88a61b..e6b1b66afe526acfa2a9ecbfc5bad9da76e8d9b4 100644 (file)
@@ -974,12 +974,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
  *    Temporarilly set tasks mems_allowed to target nodes of migration,
  *    so that the migration code can allocate pages on these nodes.
  *
- *    Call holding cpuset_mutex, so current's cpuset won't change
- *    during this call, as manage_mutex holds off any cpuset_attach()
- *    calls.  Therefore we don't need to take task_lock around the
- *    call to guarantee_online_mems(), as we know no one is changing
- *    our task's cpuset.
- *
  *    While the mm_struct we are migrating is typically from some
  *    other task, the task_struct mems_allowed that we are hacking
  *    is for our current task, which must allocate new pages for that
@@ -996,8 +990,10 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
 
        do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
 
+       rcu_read_lock();
        mems_cs = effective_nodemask_cpuset(task_cs(tsk));
        guarantee_online_mems(mems_cs, &tsk->mems_allowed);
+       rcu_read_unlock();
 }
 
 /*
@@ -2486,9 +2482,9 @@ int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask)
 
        task_lock(current);
        cs = nearest_hardwall_ancestor(task_cs(current));
+       allowed = node_isset(node, cs->mems_allowed);
        task_unlock(current);
 
-       allowed = node_isset(node, cs->mems_allowed);
        mutex_unlock(&callback_mutex);
        return allowed;
 }
index 56003c6edfd38c03e8dd523f1efb01d99bcf2e84..fa0b2d4ad83c5f7a08dfecf27d16d33d928a80f2 100644 (file)
@@ -7856,14 +7856,14 @@ static void perf_pmu_rotate_stop(struct pmu *pmu)
 static void __perf_event_exit_context(void *__info)
 {
        struct perf_event_context *ctx = __info;
-       struct perf_event *event, *tmp;
+       struct perf_event *event;
 
        perf_pmu_rotate_stop(ctx->pmu);
 
-       list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
-               __perf_remove_from_context(event);
-       list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry)
+       rcu_read_lock();
+       list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
                __perf_remove_from_context(event);
+       rcu_read_unlock();
 }
 
 static void perf_event_exit_cpu_context(int cpu)
@@ -7887,11 +7887,11 @@ static void perf_event_exit_cpu(int cpu)
 {
        struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
+       perf_event_exit_cpu_context(cpu);
+
        mutex_lock(&swhash->hlist_mutex);
        swevent_hlist_release(swhash);
        mutex_unlock(&swhash->hlist_mutex);
-
-       perf_event_exit_cpu_context(cpu);
 }
 #else
 static inline void perf_event_exit_cpu(int cpu) { }
index 44a1261cb9ff63a33eec42136be4794a0752a0ac..08ec814ad9d2fe95ae4303085cb1967265bd3758 100644 (file)
@@ -234,6 +234,7 @@ static const struct futex_q futex_q_init = {
  * waiting on a futex.
  */
 struct futex_hash_bucket {
+       atomic_t waiters;
        spinlock_t lock;
        struct plist_head chain;
 } ____cacheline_aligned_in_smp;
@@ -253,22 +254,37 @@ static inline void futex_get_mm(union futex_key *key)
        smp_mb__after_atomic_inc();
 }
 
-static inline bool hb_waiters_pending(struct futex_hash_bucket *hb)
+/*
+ * Reflects a new waiter being added to the waitqueue.
+ */
+static inline void hb_waiters_inc(struct futex_hash_bucket *hb)
 {
 #ifdef CONFIG_SMP
+       atomic_inc(&hb->waiters);
        /*
-        * Tasks trying to enter the critical region are most likely
-        * potential waiters that will be added to the plist. Ensure
-        * that wakers won't miss to-be-slept tasks in the window between
-        * the wait call and the actual plist_add.
+        * Full barrier (A), see the ordering comment above.
         */
-       if (spin_is_locked(&hb->lock))
-               return true;
-       smp_rmb(); /* Make sure we check the lock state first */
+       smp_mb__after_atomic_inc();
+#endif
+}
+
+/*
+ * Reflects a waiter being removed from the waitqueue by wakeup
+ * paths.
+ */
+static inline void hb_waiters_dec(struct futex_hash_bucket *hb)
+{
+#ifdef CONFIG_SMP
+       atomic_dec(&hb->waiters);
+#endif
+}
 
-       return !plist_head_empty(&hb->chain);
+static inline int hb_waiters_pending(struct futex_hash_bucket *hb)
+{
+#ifdef CONFIG_SMP
+       return atomic_read(&hb->waiters);
 #else
-       return true;
+       return 1;
 #endif
 }
 
@@ -954,6 +970,7 @@ static void __unqueue_futex(struct futex_q *q)
 
        hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
        plist_del(&q->list, &hb->chain);
+       hb_waiters_dec(hb);
 }
 
 /*
@@ -1257,7 +1274,9 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
         */
        if (likely(&hb1->chain != &hb2->chain)) {
                plist_del(&q->list, &hb1->chain);
+               hb_waiters_dec(hb1);
                plist_add(&q->list, &hb2->chain);
+               hb_waiters_inc(hb2);
                q->lock_ptr = &hb2->lock;
        }
        get_futex_key_refs(key2);
@@ -1600,6 +1619,17 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
        struct futex_hash_bucket *hb;
 
        hb = hash_futex(&q->key);
+
+       /*
+        * Increment the counter before taking the lock so that
+        * a potential waker won't miss a to-be-slept task that is
+        * waiting for the spinlock. This is safe as all queue_lock()
+        * users end up calling queue_me(). Similarly, for housekeeping,
+        * decrement the counter at queue_unlock() when some error has
+        * occurred and we don't end up adding the task to the list.
+        */
+       hb_waiters_inc(hb);
+
        q->lock_ptr = &hb->lock;
 
        spin_lock(&hb->lock); /* implies MB (A) */
@@ -1611,6 +1641,7 @@ queue_unlock(struct futex_hash_bucket *hb)
        __releases(&hb->lock)
 {
        spin_unlock(&hb->lock);
+       hb_waiters_dec(hb);
 }
 
 /**
@@ -2342,6 +2373,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
                 * Unqueue the futex_q and determine which it was.
                 */
                plist_del(&q->list, &hb->chain);
+               hb_waiters_dec(hb);
 
                /* Handle spurious wakeups gracefully */
                ret = -EWOULDBLOCK;
@@ -2875,6 +2907,7 @@ static int __init futex_init(void)
                futex_cmpxchg_enabled = 1;
 
        for (i = 0; i < futex_hashsize; i++) {
+               atomic_set(&futex_queues[i].waiters, 0);
                plist_head_init(&futex_queues[i].chain);
                spin_lock_init(&futex_queues[i].lock);
        }
index bd8e788d71e0dd582caa3f97602fd3b86acc21fb..1ef0606797c9c211b5b328aef7696a23b1eab652 100644 (file)
@@ -72,6 +72,51 @@ int devm_request_threaded_irq(struct device *dev, unsigned int irq,
 }
 EXPORT_SYMBOL(devm_request_threaded_irq);
 
+/**
+ *     devm_request_any_context_irq - allocate an interrupt line for a managed device
+ *     @dev: device to request interrupt for
+ *     @irq: Interrupt line to allocate
+ *     @handler: Function to be called when the IRQ occurs
+ *     @thread_fn: function to be called in a threaded interrupt context. NULL
+ *                 for devices which handle everything in @handler
+ *     @irqflags: Interrupt type flags
+ *     @devname: An ascii name for the claiming device
+ *     @dev_id: A cookie passed back to the handler function
+ *
+ *     Except for the extra @dev argument, this function takes the
+ *     same arguments and performs the same function as
+ *     request_any_context_irq().  IRQs requested with this function will be
+ *     automatically freed on driver detach.
+ *
+ *     If an IRQ allocated with this function needs to be freed
+ *     separately, devm_free_irq() must be used.
+ */
+int devm_request_any_context_irq(struct device *dev, unsigned int irq,
+                             irq_handler_t handler, unsigned long irqflags,
+                             const char *devname, void *dev_id)
+{
+       struct irq_devres *dr;
+       int rc;
+
+       dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres),
+                         GFP_KERNEL);
+       if (!dr)
+               return -ENOMEM;
+
+       rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id);
+       if (rc) {
+               devres_free(dr);
+               return rc;
+       }
+
+       dr->irq = irq;
+       dr->dev_id = dev_id;
+       devres_add(dev, dr);
+
+       return 0;
+}
+EXPORT_SYMBOL(devm_request_any_context_irq);
+
 /**
  *     devm_free_irq - free an interrupt
  *     @dev: device to free interrupt for
index 192a302d6cfd34d23d61294fed068fbc60adc858..8ab8e9390297a06ef7c4efc2a8ad502433b13879 100644 (file)
@@ -274,6 +274,7 @@ struct irq_desc *irq_to_desc(unsigned int irq)
 {
        return (irq < NR_IRQS) ? irq_desc + irq : NULL;
 }
+EXPORT_SYMBOL(irq_to_desc);
 
 static void free_desc(unsigned int irq)
 {
index cf68bb36fe5885dd2ba7b9c9ccef3c5165a320d3..f14033700c25cbc6872ccc2e60d33ee25a3493e9 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/topology.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
index 481a13c43b1708d3501a7f686760573c4eab6a34..d3bf660cb57fb8a26e55c3605dffc78ce82035f4 100644 (file)
@@ -802,8 +802,7 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc,
 
 static void wake_threads_waitq(struct irq_desc *desc)
 {
-       if (atomic_dec_and_test(&desc->threads_active) &&
-           waitqueue_active(&desc->wait_for_threads))
+       if (atomic_dec_and_test(&desc->threads_active))
                wake_up(&desc->wait_for_threads);
 }
 
index eacb8bd8cab4e1205230ecfdde12483be9846cf7..aba9c545a0e3940481f3b5ce54221906edb760e2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kbd_kern.h>
 #include <linux/vt.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include "power.h"
 
 #define SUSPEND_CONSOLE        (MAX_NR_CONSOLES-1)
index b1d255f041351779dacb5341dbcb0c0c4a09fb87..4dae9cbe9259f6a80712589370a39c705132f631 100644 (file)
@@ -1076,7 +1076,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                next_seq = log_next_seq;
 
                len = 0;
-               prev = 0;
                while (len >= 0 && seq < next_seq) {
                        struct printk_log *msg = log_from_idx(idx);
                        int textlen;
@@ -2788,7 +2787,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        next_idx = idx;
 
        l = 0;
-       prev = 0;
        while (seq < dumper->next_seq) {
                struct printk_log *msg = log_from_idx(idx);
 
index 6631e1ef55ab0970f095b42ec350982abd8d9678..ebdd9c1a86b4dfd7840df57c64f13f72a1401156 100644 (file)
@@ -549,14 +549,14 @@ static int create_hash_tables(void)
                struct page *page;
 
                page = alloc_pages_exact_node(node,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
                per_cpu(cpu_profile_hits, cpu)[1]
                                = (struct profile_hit *)page_address(page);
                page = alloc_pages_exact_node(node,
-                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+                               GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
index 43c2bcc35761e40c9342522b4fa87b92cdefd8f4..b30a2924ef1429a60152a40101ec4828c5e23268 100644 (file)
@@ -301,14 +301,14 @@ u64 sched_clock_cpu(int cpu)
        if (unlikely(!sched_clock_running))
                return 0ull;
 
-       preempt_disable();
+       preempt_disable_notrace();
        scd = cpu_sdc(cpu);
 
        if (cpu != smp_processor_id())
                clock = sched_clock_remote(scd);
        else
                clock = sched_clock_local(scd);
-       preempt_enable();
+       preempt_enable_notrace();
 
        return clock;
 }
index b46131ef6aab0ac48149482a03f8354330adf188..f5c6635b806c56550bcee17aa0c2490c96b16ff7 100644 (file)
@@ -1952,7 +1952,7 @@ static int dl_overflow(struct task_struct *p, int policy,
 {
 
        struct dl_bw *dl_b = dl_bw_of(task_cpu(p));
-       u64 period = attr->sched_period;
+       u64 period = attr->sched_period ?: attr->sched_deadline;
        u64 runtime = attr->sched_runtime;
        u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0;
        int cpus, err = -1;
@@ -3338,6 +3338,15 @@ recheck:
                                return -EPERM;
                }
 
+                /*
+                 * Can't set/change SCHED_DEADLINE policy at all for now
+                 * (safest behavior); in the future we would like to allow
+                 * unprivileged DL tasks to increase their relative deadline
+                 * or reduce their runtime (both ways reducing utilization)
+                 */
+               if (dl_policy(policy))
+                       return -EPERM;
+
                /*
                 * Treat SCHED_IDLE as nice 20. Only allow a switch to
                 * SCHED_NORMAL if the RLIMIT_NICE would normally permit it.
@@ -3661,13 +3670,14 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
  * @pid: the pid in question.
  * @uattr: structure containing the extended parameters.
  */
-SYSCALL_DEFINE2(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr)
+SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,
+                              unsigned int, flags)
 {
        struct sched_attr attr;
        struct task_struct *p;
        int retval;
 
-       if (!uattr || pid < 0)
+       if (!uattr || pid < 0 || flags)
                return -EINVAL;
 
        if (sched_copy_attr(uattr, &attr))
@@ -3786,7 +3796,7 @@ static int sched_read_attr(struct sched_attr __user *uattr,
                attr->size = usize;
        }
 
-       ret = copy_to_user(uattr, attr, usize);
+       ret = copy_to_user(uattr, attr, attr->size);
        if (ret)
                return -EFAULT;
 
@@ -3804,8 +3814,8 @@ err_size:
  * @uattr: structure containing the extended parameters.
  * @size: sizeof(attr) for fwd/bwd comp.
  */
-SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
-               unsigned int, size)
+SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
+               unsigned int, size, unsigned int, flags)
 {
        struct sched_attr attr = {
                .size = sizeof(struct sched_attr),
@@ -3814,7 +3824,7 @@ SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,
        int retval;
 
        if (!uattr || pid < 0 || size > PAGE_SIZE ||
-           size < SCHED_ATTR_SIZE_VER0)
+           size < SCHED_ATTR_SIZE_VER0 || flags)
                return -EINVAL;
 
        rcu_read_lock();
@@ -7422,6 +7432,7 @@ static int sched_dl_global_constraints(void)
        u64 period = global_rt_period();
        u64 new_bw = to_ratio(period, runtime);
        int cpu, ret = 0;
+       unsigned long flags;
 
        /*
         * Here we want to check the bandwidth not being set to some
@@ -7435,10 +7446,10 @@ static int sched_dl_global_constraints(void)
        for_each_possible_cpu(cpu) {
                struct dl_bw *dl_b = dl_bw_of(cpu);
 
-               raw_spin_lock(&dl_b->lock);
+               raw_spin_lock_irqsave(&dl_b->lock, flags);
                if (new_bw < dl_b->total_bw)
                        ret = -EBUSY;
-               raw_spin_unlock(&dl_b->lock);
+               raw_spin_unlock_irqrestore(&dl_b->lock, flags);
 
                if (ret)
                        break;
@@ -7451,6 +7462,7 @@ static void sched_dl_do_global(void)
 {
        u64 new_bw = -1;
        int cpu;
+       unsigned long flags;
 
        def_dl_bandwidth.dl_period = global_rt_period();
        def_dl_bandwidth.dl_runtime = global_rt_runtime();
@@ -7464,9 +7476,9 @@ static void sched_dl_do_global(void)
        for_each_possible_cpu(cpu) {
                struct dl_bw *dl_b = dl_bw_of(cpu);
 
-               raw_spin_lock(&dl_b->lock);
+               raw_spin_lock_irqsave(&dl_b->lock, flags);
                dl_b->bw = new_bw;
-               raw_spin_unlock(&dl_b->lock);
+               raw_spin_unlock_irqrestore(&dl_b->lock, flags);
        }
 }
 
@@ -7475,7 +7487,8 @@ static int sched_rt_global_validate(void)
        if (sysctl_sched_rt_period <= 0)
                return -EINVAL;
 
-       if (sysctl_sched_rt_runtime > sysctl_sched_rt_period)
+       if ((sysctl_sched_rt_runtime != RUNTIME_INF) &&
+               (sysctl_sched_rt_runtime > sysctl_sched_rt_period))
                return -EINVAL;
 
        return 0;
index 045fc74e3f0928fd73e1924b5b678f7d56654613..5b9bb42b2d47e760f3a7cd17af24ba37d2cf07ea 100644 (file)
@@ -70,7 +70,7 @@ static void cpudl_heapify(struct cpudl *cp, int idx)
 
 static void cpudl_change_key(struct cpudl *cp, int idx, u64 new_dl)
 {
-       WARN_ON(idx > num_present_cpus() || idx == IDX_INVALID);
+       WARN_ON(idx == IDX_INVALID || !cpu_present(idx));
 
        if (dl_time_before(new_dl, cp->elements[idx].dl)) {
                cp->elements[idx].dl = new_dl;
@@ -117,7 +117,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
        }
 
 out:
-       WARN_ON(best_cpu > num_present_cpus() && best_cpu != -1);
+       WARN_ON(best_cpu != -1 && !cpu_present(best_cpu));
 
        return best_cpu;
 }
@@ -137,7 +137,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid)
        int old_idx, new_cpu;
        unsigned long flags;
 
-       WARN_ON(cpu > num_present_cpus());
+       WARN_ON(!cpu_present(cpu));
 
        raw_spin_lock_irqsave(&cp->lock, flags);
        old_idx = cp->cpu_to_idx[cpu];
index 0dd5e0971a0778a3e09ee8a91f5851dfa1dc25a9..6e79b3faa4cd5384754232dc3b74300367afec8e 100644 (file)
@@ -121,7 +121,7 @@ static inline void dl_clear_overload(struct rq *rq)
 
 static void update_dl_migration(struct dl_rq *dl_rq)
 {
-       if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_total > 1) {
+       if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_running > 1) {
                if (!dl_rq->overloaded) {
                        dl_set_overload(rq_of_dl_rq(dl_rq));
                        dl_rq->overloaded = 1;
@@ -135,9 +135,7 @@ static void update_dl_migration(struct dl_rq *dl_rq)
 static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
        struct task_struct *p = dl_task_of(dl_se);
-       dl_rq = &rq_of_dl_rq(dl_rq)->dl;
 
-       dl_rq->dl_nr_total++;
        if (p->nr_cpus_allowed > 1)
                dl_rq->dl_nr_migratory++;
 
@@ -147,9 +145,7 @@ static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 static void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 {
        struct task_struct *p = dl_task_of(dl_se);
-       dl_rq = &rq_of_dl_rq(dl_rq)->dl;
 
-       dl_rq->dl_nr_total--;
        if (p->nr_cpus_allowed > 1)
                dl_rq->dl_nr_migratory--;
 
@@ -566,6 +562,8 @@ int dl_runtime_exceeded(struct rq *rq, struct sched_dl_entity *dl_se)
        return 1;
 }
 
+extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
+
 /*
  * Update the current task's runtime statistics (provided it is still
  * a -deadline task and has not been removed from the dl_rq).
@@ -629,11 +627,13 @@ static void update_curr_dl(struct rq *rq)
                struct rt_rq *rt_rq = &rq->rt;
 
                raw_spin_lock(&rt_rq->rt_runtime_lock);
-               rt_rq->rt_time += delta_exec;
                /*
                 * We'll let actual RT tasks worry about the overflow here, we
-                * have our own CBS to keep us inline -- see above.
+                * have our own CBS to keep us inline; only account when RT
+                * bandwidth is relevant.
                 */
+               if (sched_rt_bandwidth_account(rt_rq))
+                       rt_rq->rt_time += delta_exec;
                raw_spin_unlock(&rt_rq->rt_runtime_lock);
        }
 }
@@ -717,6 +717,7 @@ void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 
        WARN_ON(!dl_prio(prio));
        dl_rq->dl_nr_running++;
+       inc_nr_running(rq_of_dl_rq(dl_rq));
 
        inc_dl_deadline(dl_rq, deadline);
        inc_dl_migration(dl_se, dl_rq);
@@ -730,6 +731,7 @@ void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
        WARN_ON(!dl_prio(prio));
        WARN_ON(!dl_rq->dl_nr_running);
        dl_rq->dl_nr_running--;
+       dec_nr_running(rq_of_dl_rq(dl_rq));
 
        dec_dl_deadline(dl_rq, dl_se->deadline);
        dec_dl_migration(dl_se, dl_rq);
@@ -836,8 +838,6 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 
        if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
                enqueue_pushable_dl_task(rq, p);
-
-       inc_nr_running(rq);
 }
 
 static void __dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
@@ -850,8 +850,6 @@ static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 {
        update_curr_dl(rq);
        __dequeue_task_dl(rq, p, flags);
-
-       dec_nr_running(rq);
 }
 
 /*
index 966cc2bfcb77586d2ce9c55986aae2a3f2dce521..9b4c4f3201301a269bd66718650899274f204bc6 100644 (file)
@@ -1757,6 +1757,8 @@ void task_numa_work(struct callback_head *work)
                        start = end;
                        if (pages <= 0)
                                goto out;
+
+                       cond_resched();
                } while (end != vma->vm_end);
        }
 
@@ -6999,15 +7001,15 @@ static void switched_from_fair(struct rq *rq, struct task_struct *p)
        struct cfs_rq *cfs_rq = cfs_rq_of(se);
 
        /*
-        * Ensure the task's vruntime is normalized, so that when its
+        * Ensure the task's vruntime is normalized, so that when it's
         * switched back to the fair class the enqueue_entity(.flags=0) will
         * do the right thing.
         *
-        * If it was on_rq, then the dequeue_entity(.flags=0) will already
-        * have normalized the vruntime, if it was !on_rq, then only when
+        * If it's on_rq, then the dequeue_entity(.flags=0) will already
+        * have normalized the vruntime, if it's !on_rq, then only when
         * the task is sleeping will it still have non-normalized vruntime.
         */
-       if (!se->on_rq && p->state != TASK_RUNNING) {
+       if (!p->on_rq && p->state != TASK_RUNNING) {
                /*
                 * Fix up our vruntime so that the current sleep doesn't
                 * cause 'unlimited' sleep bonus.
index a2740b775b456ed27c56ad088007c83e1873458b..1999021042c7010c6e5e86539b9c0b9a03519dcd 100644 (file)
@@ -538,6 +538,14 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
 
 #endif /* CONFIG_RT_GROUP_SCHED */
 
+bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
+{
+       struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
+
+       return (hrtimer_active(&rt_b->rt_period_timer) ||
+               rt_rq->rt_time < rt_b->rt_runtime);
+}
+
 #ifdef CONFIG_SMP
 /*
  * We ran out of runtime, see if we can borrow some from our neighbours.
index c2119fd20f8b6dc2042a80603d44223ab9365dec..f964add50f3863805f725e8fc13b447806f41022 100644 (file)
@@ -462,7 +462,6 @@ struct dl_rq {
        } earliest_dl;
 
        unsigned long dl_nr_migratory;
-       unsigned long dl_nr_total;
        int overloaded;
 
        /*
index b7a10048a32c11fb473515d9075ef2b0782a563a..4f18e754c23ea51dfc732dba85aa5db186c79789 100644 (file)
@@ -55,60 +55,33 @@ struct seccomp_filter {
        atomic_t usage;
        struct seccomp_filter *prev;
        unsigned short len;  /* Instruction count */
-       struct sock_filter insns[];
+       struct sock_filter_int insnsi[];
 };
 
 /* Limit any path through the tree to 256KB worth of instructions. */
 #define MAX_INSNS_PER_PATH ((1 << 18) / sizeof(struct sock_filter))
 
-/**
- * get_u32 - returns a u32 offset into data
- * @data: a unsigned 64 bit value
- * @index: 0 or 1 to return the first or second 32-bits
- *
- * This inline exists to hide the length of unsigned long.  If a 32-bit
- * unsigned long is passed in, it will be extended and the top 32-bits will be
- * 0. If it is a 64-bit unsigned long, then whatever data is resident will be
- * properly returned.
- *
+/*
  * Endianness is explicitly ignored and left for BPF program authors to manage
  * as per the specific architecture.
  */
-static inline u32 get_u32(u64 data, int index)
+static void populate_seccomp_data(struct seccomp_data *sd)
 {
-       return ((u32 *)&data)[index];
-}
+       struct task_struct *task = current;
+       struct pt_regs *regs = task_pt_regs(task);
 
-/* Helper for bpf_load below. */
-#define BPF_DATA(_name) offsetof(struct seccomp_data, _name)
-/**
- * bpf_load: checks and returns a pointer to the requested offset
- * @off: offset into struct seccomp_data to load from
- *
- * Returns the requested 32-bits of data.
- * seccomp_check_filter() should assure that @off is 32-bit aligned
- * and not out of bounds.  Failure to do so is a BUG.
- */
-u32 seccomp_bpf_load(int off)
-{
-       struct pt_regs *regs = task_pt_regs(current);
-       if (off == BPF_DATA(nr))
-               return syscall_get_nr(current, regs);
-       if (off == BPF_DATA(arch))
-               return syscall_get_arch(current, regs);
-       if (off >= BPF_DATA(args[0]) && off < BPF_DATA(args[6])) {
-               unsigned long value;
-               int arg = (off - BPF_DATA(args[0])) / sizeof(u64);
-               int index = !!(off % sizeof(u64));
-               syscall_get_arguments(current, regs, arg, 1, &value);
-               return get_u32(value, index);
-       }
-       if (off == BPF_DATA(instruction_pointer))
-               return get_u32(KSTK_EIP(current), 0);
-       if (off == BPF_DATA(instruction_pointer) + sizeof(u32))
-               return get_u32(KSTK_EIP(current), 1);
-       /* seccomp_check_filter should make this impossible. */
-       BUG();
+       sd->nr = syscall_get_nr(task, regs);
+       sd->arch = syscall_get_arch(task, regs);
+
+       /* Unroll syscall_get_args to help gcc on arm. */
+       syscall_get_arguments(task, regs, 0, 1, (unsigned long *) &sd->args[0]);
+       syscall_get_arguments(task, regs, 1, 1, (unsigned long *) &sd->args[1]);
+       syscall_get_arguments(task, regs, 2, 1, (unsigned long *) &sd->args[2]);
+       syscall_get_arguments(task, regs, 3, 1, (unsigned long *) &sd->args[3]);
+       syscall_get_arguments(task, regs, 4, 1, (unsigned long *) &sd->args[4]);
+       syscall_get_arguments(task, regs, 5, 1, (unsigned long *) &sd->args[5]);
+
+       sd->instruction_pointer = KSTK_EIP(task);
 }
 
 /**
@@ -133,17 +106,17 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
 
                switch (code) {
                case BPF_S_LD_W_ABS:
-                       ftest->code = BPF_S_ANC_SECCOMP_LD_W;
+                       ftest->code = BPF_LDX | BPF_W | BPF_ABS;
                        /* 32-bit aligned and not out of bounds. */
                        if (k >= sizeof(struct seccomp_data) || k & 3)
                                return -EINVAL;
                        continue;
                case BPF_S_LD_W_LEN:
-                       ftest->code = BPF_S_LD_IMM;
+                       ftest->code = BPF_LD | BPF_IMM;
                        ftest->k = sizeof(struct seccomp_data);
                        continue;
                case BPF_S_LDX_W_LEN:
-                       ftest->code = BPF_S_LDX_IMM;
+                       ftest->code = BPF_LDX | BPF_IMM;
                        ftest->k = sizeof(struct seccomp_data);
                        continue;
                /* Explicitly include allowed calls. */
@@ -185,6 +158,7 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
                case BPF_S_JMP_JGT_X:
                case BPF_S_JMP_JSET_K:
                case BPF_S_JMP_JSET_X:
+                       sk_decode_filter(ftest, ftest);
                        continue;
                default:
                        return -EINVAL;
@@ -202,18 +176,21 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
 static u32 seccomp_run_filters(int syscall)
 {
        struct seccomp_filter *f;
+       struct seccomp_data sd;
        u32 ret = SECCOMP_RET_ALLOW;
 
        /* Ensure unexpected behavior doesn't result in failing open. */
        if (WARN_ON(current->seccomp.filter == NULL))
                return SECCOMP_RET_KILL;
 
+       populate_seccomp_data(&sd);
+
        /*
         * All filters in the list are evaluated and the lowest BPF return
         * value always takes priority (ignoring the DATA).
         */
        for (f = current->seccomp.filter; f; f = f->prev) {
-               u32 cur_ret = sk_run_filter(NULL, f->insns);
+               u32 cur_ret = sk_run_filter_int_seccomp(&sd, f->insnsi);
                if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
                        ret = cur_ret;
        }
@@ -231,6 +208,8 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
        struct seccomp_filter *filter;
        unsigned long fp_size = fprog->len * sizeof(struct sock_filter);
        unsigned long total_insns = fprog->len;
+       struct sock_filter *fp;
+       int new_len;
        long ret;
 
        if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
@@ -252,28 +231,43 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
                                     CAP_SYS_ADMIN) != 0)
                return -EACCES;
 
-       /* Allocate a new seccomp_filter */
-       filter = kzalloc(sizeof(struct seccomp_filter) + fp_size,
-                        GFP_KERNEL|__GFP_NOWARN);
-       if (!filter)
+       fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
+       if (!fp)
                return -ENOMEM;
-       atomic_set(&filter->usage, 1);
-       filter->len = fprog->len;
 
        /* Copy the instructions from fprog. */
        ret = -EFAULT;
-       if (copy_from_user(filter->insns, fprog->filter, fp_size))
-               goto fail;
+       if (copy_from_user(fp, fprog->filter, fp_size))
+               goto free_prog;
 
        /* Check and rewrite the fprog via the skb checker */
-       ret = sk_chk_filter(filter->insns, filter->len);
+       ret = sk_chk_filter(fp, fprog->len);
        if (ret)
-               goto fail;
+               goto free_prog;
 
        /* Check and rewrite the fprog for seccomp use */
-       ret = seccomp_check_filter(filter->insns, filter->len);
+       ret = seccomp_check_filter(fp, fprog->len);
+       if (ret)
+               goto free_prog;
+
+       /* Convert 'sock_filter' insns to 'sock_filter_int' insns */
+       ret = sk_convert_filter(fp, fprog->len, NULL, &new_len);
+       if (ret)
+               goto free_prog;
+
+       /* Allocate a new seccomp_filter */
+       filter = kzalloc(sizeof(struct seccomp_filter) +
+                        sizeof(struct sock_filter_int) * new_len,
+                        GFP_KERNEL|__GFP_NOWARN);
+       if (!filter)
+               goto free_prog;
+
+       ret = sk_convert_filter(fp, fprog->len, filter->insnsi, &new_len);
        if (ret)
-               goto fail;
+               goto free_filter;
+
+       atomic_set(&filter->usage, 1);
+       filter->len = new_len;
 
        /*
         * If there is an existing filter, make it the prev and don't drop its
@@ -282,8 +276,11 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
        filter->prev = current->seccomp.filter;
        current->seccomp.filter = filter;
        return 0;
-fail:
+
+free_filter:
        kfree(filter);
+free_prog:
+       kfree(fp);
        return ret;
 }
 
index 84571e09c9079e8887f73a0f24beefe58e00ff77..01fbae5b97b765199feccfbb6f985c1309dc3475 100644 (file)
@@ -293,7 +293,7 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
         */
        smp_call_function_single(min(cpu1, cpu2),
                                 &irq_cpu_stop_queue_work,
-                                &call_args, 0);
+                                &call_args, 1);
        lg_local_unlock(&stop_cpus_lock);
        preempt_enable();
 
index 7a925ba456fb5d617d19b98daf2ca39356c4eca6..a6a5bf53e86d25575f90518399407a4fb65a85ed 100644 (file)
  * HZ shrinks, so values greater than 8 overflow 32bits when
  * HZ=100.
  */
+#if HZ < 34
+#define JIFFIES_SHIFT  6
+#elif HZ < 67
+#define JIFFIES_SHIFT  7
+#else
 #define JIFFIES_SHIFT  8
+#endif
 
 static cycle_t jiffies_read(struct clocksource *cs)
 {
index 0abb364642818e4ef842ab2f3631d15cb80400f2..4d23dc4d8139988e13946ee48d37a76333c916c0 100644 (file)
@@ -116,20 +116,42 @@ static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
 void __init sched_clock_register(u64 (*read)(void), int bits,
                                 unsigned long rate)
 {
+       u64 res, wrap, new_mask, new_epoch, cyc, ns;
+       u32 new_mult, new_shift;
+       ktime_t new_wrap_kt;
        unsigned long r;
-       u64 res, wrap;
        char r_unit;
 
        if (cd.rate > rate)
                return;
 
        WARN_ON(!irqs_disabled());
-       read_sched_clock = read;
-       sched_clock_mask = CLOCKSOURCE_MASK(bits);
-       cd.rate = rate;
 
        /* calculate the mult/shift to convert counter ticks to ns. */
-       clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 3600);
+       clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600);
+
+       new_mask = CLOCKSOURCE_MASK(bits);
+
+       /* calculate how many ns until we wrap */
+       wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask);
+       new_wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
+
+       /* update epoch for new counter and update epoch_ns from old counter*/
+       new_epoch = read();
+       cyc = read_sched_clock();
+       ns = cd.epoch_ns + cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
+                         cd.mult, cd.shift);
+
+       raw_write_seqcount_begin(&cd.seq);
+       read_sched_clock = read;
+       sched_clock_mask = new_mask;
+       cd.rate = rate;
+       cd.wrap_kt = new_wrap_kt;
+       cd.mult = new_mult;
+       cd.shift = new_shift;
+       cd.epoch_cyc = new_epoch;
+       cd.epoch_ns = ns;
+       raw_write_seqcount_end(&cd.seq);
 
        r = rate;
        if (r >= 4000000) {
@@ -141,22 +163,12 @@ void __init sched_clock_register(u64 (*read)(void), int bits,
        } else
                r_unit = ' ';
 
-       /* calculate how many ns until we wrap */
-       wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask);
-       cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
-
        /* calculate the ns resolution of this counter */
-       res = cyc_to_ns(1ULL, cd.mult, cd.shift);
+       res = cyc_to_ns(1ULL, new_mult, new_shift);
+
        pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
                bits, r, r_unit, res, wrap);
 
-       update_sched_clock();
-
-       /*
-        * Ensure that sched_clock() starts off at 0ns
-        */
-       cd.epoch_ns = 0;
-
        /* Enable IRQ time accounting if we have a fast enough sched_clock */
        if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
                enable_sched_clock_irqtime();
index 43780ab5e279b1a6f6bb0e6251dfcdb29640af40..98977a57ac72d2a221ed78731b62d67a2e1778fb 100644 (file)
@@ -756,6 +756,7 @@ out:
 static void tick_broadcast_clear_oneshot(int cpu)
 {
        cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
+       cpumask_clear_cpu(cpu, tick_broadcast_pending_mask);
 }
 
 static void tick_broadcast_init_next_event(struct cpumask *mask,
index 294b8a271a04223786827b6fffb58fd7e90fbcaf..fc4da2d97f9b6e280b2e29a525e478958cb495d4 100644 (file)
@@ -2397,6 +2397,13 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
        write &= RB_WRITE_MASK;
        tail = write - length;
 
+       /*
+        * If this is the first commit on the page, then it has the same
+        * timestamp as the page itself.
+        */
+       if (!tail)
+               delta = 0;
+
        /* See if we shot pass the end of this buffer page */
        if (unlikely(write > BUF_PAGE_SIZE))
                return rb_move_tail(cpu_buffer, length, tail,
index 815c878f409bd94e08777d1b9f83b1553f4a2e24..24c1f23825579df4f2bf46e2dca98e6af8fb4abd 100644 (file)
@@ -1600,15 +1600,31 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
 
+static struct ring_buffer *temp_buffer;
+
 struct ring_buffer_event *
 trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
                          struct ftrace_event_file *ftrace_file,
                          int type, unsigned long len,
                          unsigned long flags, int pc)
 {
+       struct ring_buffer_event *entry;
+
        *current_rb = ftrace_file->tr->trace_buffer.buffer;
-       return trace_buffer_lock_reserve(*current_rb,
+       entry = trace_buffer_lock_reserve(*current_rb,
                                         type, len, flags, pc);
+       /*
+        * If tracing is off, but we have triggers enabled
+        * we still need to look at the event data. Use the temp_buffer
+        * to store the trace event for the tigger to use. It's recusive
+        * safe and will not be recorded anywhere.
+        */
+       if (!entry && ftrace_file->flags & FTRACE_EVENT_FL_TRIGGER_COND) {
+               *current_rb = temp_buffer;
+               entry = trace_buffer_lock_reserve(*current_rb,
+                                                 type, len, flags, pc);
+       }
+       return entry;
 }
 EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
 
@@ -6494,11 +6510,16 @@ __init static int tracer_alloc_buffers(void)
 
        raw_spin_lock_init(&global_trace.start_lock);
 
+       /* Used for event triggers */
+       temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE);
+       if (!temp_buffer)
+               goto out_free_cpumask;
+
        /* TODO: make the number of buffers hot pluggable with CPUS */
        if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {
                printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
                WARN_ON(1);
-               goto out_free_cpumask;
+               goto out_free_temp_buffer;
        }
 
        if (global_trace.buffer_disabled)
@@ -6540,6 +6561,8 @@ __init static int tracer_alloc_buffers(void)
 
        return 0;
 
+out_free_temp_buffer:
+       ring_buffer_free(temp_buffer);
 out_free_cpumask:
        free_percpu(global_trace.trace_buffer.data);
 #ifdef CONFIG_TRACER_MAX_TRACE
index e71ffd4eccb5b4d7a7b0234dd72e525b1c647550..7b16d40bd64d934d2be40e146bf8baa8e074487d 100644 (file)
 
 DEFINE_MUTEX(event_mutex);
 
-DEFINE_MUTEX(event_storage_mutex);
-EXPORT_SYMBOL_GPL(event_storage_mutex);
-
-char event_storage[EVENT_STORAGE_SIZE];
-EXPORT_SYMBOL_GPL(event_storage);
-
 LIST_HEAD(ftrace_events);
 static LIST_HEAD(ftrace_common_fields);
 
@@ -1777,6 +1771,16 @@ static void trace_module_add_events(struct module *mod)
 {
        struct ftrace_event_call **call, **start, **end;
 
+       if (!mod->num_trace_events)
+               return;
+
+       /* Don't add infrastructure for mods without tracepoints */
+       if (trace_module_has_bad_taint(mod)) {
+               pr_err("%s: module has bad taint, not creating trace events\n",
+                      mod->name);
+               return;
+       }
+
        start = mod->trace_events;
        end = mod->trace_events + mod->num_trace_events;
 
index 7c3e3e72e2b6bd2f0a6bd929ff67526497281b4a..ee0a5098ac43adca42f1631450f6f8330782cd5c 100644 (file)
@@ -95,15 +95,12 @@ static void __always_unused ____ftrace_check_##name(void)           \
 #undef __array
 #define __array(type, item, len)                                       \
        do {                                                            \
+               char *type_str = #type"["__stringify(len)"]";           \
                BUILD_BUG_ON(len > MAX_FILTER_STR_VAL);                 \
-               mutex_lock(&event_storage_mutex);                       \
-               snprintf(event_storage, sizeof(event_storage),          \
-                        "%s[%d]", #type, len);                         \
-               ret = trace_define_field(event_call, event_storage, #item, \
+               ret = trace_define_field(event_call, type_str, #item,   \
                                 offsetof(typeof(field), item),         \
                                 sizeof(field.item),                    \
                                 is_signed_type(type), filter_type);    \
-               mutex_unlock(&event_storage_mutex);                     \
                if (ret)                                                \
                        return ret;                                     \
        } while (0);
index 29f26540e9c9550fd1c099512e7b20beb21ce234..031cc5655a514d2bcf89f930388dcddda396986f 100644 (file)
@@ -631,6 +631,11 @@ void tracepoint_iter_reset(struct tracepoint_iter *iter)
 EXPORT_SYMBOL_GPL(tracepoint_iter_reset);
 
 #ifdef CONFIG_MODULES
+bool trace_module_has_bad_taint(struct module *mod)
+{
+       return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP));
+}
+
 static int tracepoint_module_coming(struct module *mod)
 {
        struct tp_module *tp_mod, *iter;
@@ -641,7 +646,7 @@ static int tracepoint_module_coming(struct module *mod)
         * module headers (for forced load), to make sure we don't cause a crash.
         * Staging and out-of-tree GPL modules are fine.
         */
-       if (mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP)))
+       if (trace_module_has_bad_taint(mod))
                return 0;
        mutex_lock(&tracepoints_mutex);
        tp_mod = kmalloc(sizeof(struct tp_module), GFP_KERNEL);
index 240fb62cf3945aa0f7b601b343db65312a42f345..dd06439b9c84fe80463121905339c41493710998 100644 (file)
@@ -225,7 +225,7 @@ static u32 map_id_up(struct uid_gid_map *map, u32 id)
  *
  *     When there is no mapping defined for the user-namespace uid
  *     pair INVALID_UID is returned.  Callers are expected to test
- *     for and handle handle INVALID_UID being returned.  INVALID_UID
+ *     for and handle INVALID_UID being returned.  INVALID_UID
  *     may be tested for using uid_valid().
  */
 kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
index 82ef9f3b7473a81ef5004362c7281ae9f4aea82a..193e977a10eaeb6a7f9ca5927d08f558d68df434 100644 (file)
@@ -1851,6 +1851,12 @@ static void destroy_worker(struct worker *worker)
        if (worker->flags & WORKER_IDLE)
                pool->nr_idle--;
 
+       /*
+        * Once WORKER_DIE is set, the kworker may destroy itself at any
+        * point.  Pin to ensure the task stays until we're done with it.
+        */
+       get_task_struct(worker->task);
+
        list_del_init(&worker->entry);
        worker->flags |= WORKER_DIE;
 
@@ -1859,6 +1865,7 @@ static void destroy_worker(struct worker *worker)
        spin_unlock_irq(&pool->lock);
 
        kthread_stop(worker->task);
+       put_task_struct(worker->task);
        kfree(worker);
 
        spin_lock_irq(&pool->lock);
index 2defd1308b045c46389a6232391999914573deb6..98f2d7e91a9114e5e124e42bef00d7935708e521 100644 (file)
@@ -424,111 +424,134 @@ void debug_dma_dump_mappings(struct device *dev)
 EXPORT_SYMBOL(debug_dma_dump_mappings);
 
 /*
- * For each page mapped (initial page in the case of
- * dma_alloc_coherent/dma_map_{single|page}, or each page in a
- * scatterlist) insert into this tree using the pfn as the key. At
+ * For each mapping (initial cacheline in the case of
+ * dma_alloc_coherent/dma_map_page, initial cacheline in each page of a
+ * scatterlist, or the cacheline specified in dma_map_single) insert
+ * into this tree using the cacheline as the key. At
  * dma_unmap_{single|sg|page} or dma_free_coherent delete the entry.  If
- * the pfn already exists at insertion time add a tag as a reference
+ * the entry already exists at insertion time add a tag as a reference
  * count for the overlapping mappings.  For now, the overlap tracking
- * just ensures that 'unmaps' balance 'maps' before marking the pfn
- * idle, but we should also be flagging overlaps as an API violation.
+ * just ensures that 'unmaps' balance 'maps' before marking the
+ * cacheline idle, but we should also be flagging overlaps as an API
+ * violation.
  *
  * Memory usage is mostly constrained by the maximum number of available
  * dma-debug entries in that we need a free dma_debug_entry before
- * inserting into the tree.  In the case of dma_map_{single|page} and
- * dma_alloc_coherent there is only one dma_debug_entry and one pfn to
- * track per event.  dma_map_sg(), on the other hand,
- * consumes a single dma_debug_entry, but inserts 'nents' entries into
- * the tree.
+ * inserting into the tree.  In the case of dma_map_page and
+ * dma_alloc_coherent there is only one dma_debug_entry and one
+ * dma_active_cacheline entry to track per event.  dma_map_sg(), on the
+ * other hand, consumes a single dma_debug_entry, but inserts 'nents'
+ * entries into the tree.
  *
  * At any time debug_dma_assert_idle() can be called to trigger a
- * warning if the given page is in the active set.
+ * warning if any cachelines in the given page are in the active set.
  */
-static RADIX_TREE(dma_active_pfn, GFP_NOWAIT);
+static RADIX_TREE(dma_active_cacheline, GFP_NOWAIT);
 static DEFINE_SPINLOCK(radix_lock);
-#define ACTIVE_PFN_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define ACTIVE_CACHELINE_MAX_OVERLAP ((1 << RADIX_TREE_MAX_TAGS) - 1)
+#define CACHELINE_PER_PAGE_SHIFT (PAGE_SHIFT - L1_CACHE_SHIFT)
+#define CACHELINES_PER_PAGE (1 << CACHELINE_PER_PAGE_SHIFT)
 
-static int active_pfn_read_overlap(unsigned long pfn)
+static phys_addr_t to_cacheline_number(struct dma_debug_entry *entry)
+{
+       return (entry->pfn << CACHELINE_PER_PAGE_SHIFT) +
+               (entry->offset >> L1_CACHE_SHIFT);
+}
+
+static int active_cacheline_read_overlap(phys_addr_t cln)
 {
        int overlap = 0, i;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
-               if (radix_tree_tag_get(&dma_active_pfn, pfn, i))
+               if (radix_tree_tag_get(&dma_active_cacheline, cln, i))
                        overlap |= 1 << i;
        return overlap;
 }
 
-static int active_pfn_set_overlap(unsigned long pfn, int overlap)
+static int active_cacheline_set_overlap(phys_addr_t cln, int overlap)
 {
        int i;
 
-       if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
+       if (overlap > ACTIVE_CACHELINE_MAX_OVERLAP || overlap < 0)
                return overlap;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
                if (overlap & 1 << i)
-                       radix_tree_tag_set(&dma_active_pfn, pfn, i);
+                       radix_tree_tag_set(&dma_active_cacheline, cln, i);
                else
-                       radix_tree_tag_clear(&dma_active_pfn, pfn, i);
+                       radix_tree_tag_clear(&dma_active_cacheline, cln, i);
 
        return overlap;
 }
 
-static void active_pfn_inc_overlap(unsigned long pfn)
+static void active_cacheline_inc_overlap(phys_addr_t cln)
 {
-       int overlap = active_pfn_read_overlap(pfn);
+       int overlap = active_cacheline_read_overlap(cln);
 
-       overlap = active_pfn_set_overlap(pfn, ++overlap);
+       overlap = active_cacheline_set_overlap(cln, ++overlap);
 
        /* If we overflowed the overlap counter then we're potentially
         * leaking dma-mappings.  Otherwise, if maps and unmaps are
         * balanced then this overflow may cause false negatives in
-        * debug_dma_assert_idle() as the pfn may be marked idle
+        * debug_dma_assert_idle() as the cacheline may be marked idle
         * prematurely.
         */
-       WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
-                 "DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
-                 ACTIVE_PFN_MAX_OVERLAP, pfn);
+       WARN_ONCE(overlap > ACTIVE_CACHELINE_MAX_OVERLAP,
+                 "DMA-API: exceeded %d overlapping mappings of cacheline %pa\n",
+                 ACTIVE_CACHELINE_MAX_OVERLAP, &cln);
 }
 
-static int active_pfn_dec_overlap(unsigned long pfn)
+static int active_cacheline_dec_overlap(phys_addr_t cln)
 {
-       int overlap = active_pfn_read_overlap(pfn);
+       int overlap = active_cacheline_read_overlap(cln);
 
-       return active_pfn_set_overlap(pfn, --overlap);
+       return active_cacheline_set_overlap(cln, --overlap);
 }
 
-static int active_pfn_insert(struct dma_debug_entry *entry)
+static int active_cacheline_insert(struct dma_debug_entry *entry)
 {
+       phys_addr_t cln = to_cacheline_number(entry);
        unsigned long flags;
        int rc;
 
+       /* If the device is not writing memory then we don't have any
+        * concerns about the cpu consuming stale data.  This mitigates
+        * legitimate usages of overlapping mappings.
+        */
+       if (entry->direction == DMA_TO_DEVICE)
+               return 0;
+
        spin_lock_irqsave(&radix_lock, flags);
-       rc = radix_tree_insert(&dma_active_pfn, entry->pfn, entry);
+       rc = radix_tree_insert(&dma_active_cacheline, cln, entry);
        if (rc == -EEXIST)
-               active_pfn_inc_overlap(entry->pfn);
+               active_cacheline_inc_overlap(cln);
        spin_unlock_irqrestore(&radix_lock, flags);
 
        return rc;
 }
 
-static void active_pfn_remove(struct dma_debug_entry *entry)
+static void active_cacheline_remove(struct dma_debug_entry *entry)
 {
+       phys_addr_t cln = to_cacheline_number(entry);
        unsigned long flags;
 
+       /* ...mirror the insert case */
+       if (entry->direction == DMA_TO_DEVICE)
+               return;
+
        spin_lock_irqsave(&radix_lock, flags);
        /* since we are counting overlaps the final put of the
-        * entry->pfn will occur when the overlap count is 0.
-        * active_pfn_dec_overlap() returns -1 in that case
+        * cacheline will occur when the overlap count is 0.
+        * active_cacheline_dec_overlap() returns -1 in that case
         */
-       if (active_pfn_dec_overlap(entry->pfn) < 0)
-               radix_tree_delete(&dma_active_pfn, entry->pfn);
+       if (active_cacheline_dec_overlap(cln) < 0)
+               radix_tree_delete(&dma_active_cacheline, cln);
        spin_unlock_irqrestore(&radix_lock, flags);
 }
 
 /**
  * debug_dma_assert_idle() - assert that a page is not undergoing dma
- * @page: page to lookup in the dma_active_pfn tree
+ * @page: page to lookup in the dma_active_cacheline tree
  *
  * Place a call to this routine in cases where the cpu touching the page
  * before the dma completes (page is dma_unmapped) will lead to data
@@ -536,22 +559,38 @@ static void active_pfn_remove(struct dma_debug_entry *entry)
  */
 void debug_dma_assert_idle(struct page *page)
 {
+       static struct dma_debug_entry *ents[CACHELINES_PER_PAGE];
+       struct dma_debug_entry *entry = NULL;
+       void **results = (void **) &ents;
+       unsigned int nents, i;
        unsigned long flags;
-       struct dma_debug_entry *entry;
+       phys_addr_t cln;
 
        if (!page)
                return;
 
+       cln = (phys_addr_t) page_to_pfn(page) << CACHELINE_PER_PAGE_SHIFT;
        spin_lock_irqsave(&radix_lock, flags);
-       entry = radix_tree_lookup(&dma_active_pfn, page_to_pfn(page));
+       nents = radix_tree_gang_lookup(&dma_active_cacheline, results, cln,
+                                      CACHELINES_PER_PAGE);
+       for (i = 0; i < nents; i++) {
+               phys_addr_t ent_cln = to_cacheline_number(ents[i]);
+
+               if (ent_cln == cln) {
+                       entry = ents[i];
+                       break;
+               } else if (ent_cln >= cln + CACHELINES_PER_PAGE)
+                       break;
+       }
        spin_unlock_irqrestore(&radix_lock, flags);
 
        if (!entry)
                return;
 
+       cln = to_cacheline_number(entry);
        err_printk(entry->dev, entry,
-                  "DMA-API: cpu touching an active dma mapped page "
-                  "[pfn=0x%lx]\n", entry->pfn);
+                  "DMA-API: cpu touching an active dma mapped cacheline [cln=%pa]\n",
+                  &cln);
 }
 
 /*
@@ -568,9 +607,9 @@ static void add_dma_entry(struct dma_debug_entry *entry)
        hash_bucket_add(bucket, entry);
        put_hash_bucket(bucket, &flags);
 
-       rc = active_pfn_insert(entry);
+       rc = active_cacheline_insert(entry);
        if (rc == -ENOMEM) {
-               pr_err("DMA-API: pfn tracking ENOMEM, dma-debug disabled\n");
+               pr_err("DMA-API: cacheline tracking ENOMEM, dma-debug disabled\n");
                global_disable = true;
        }
 
@@ -631,7 +670,7 @@ static void dma_entry_free(struct dma_debug_entry *entry)
 {
        unsigned long flags;
 
-       active_pfn_remove(entry);
+       active_cacheline_remove(entry);
 
        /*
         * add to beginning of the list - this way the entries are
index 4dc1b990aa2339b572bd31d18b917dc3a1e161df..34fd931b54b53ac10c64d1320b2f54c299679ff1 100644 (file)
@@ -9,7 +9,7 @@ if FONT_SUPPORT
 
 config FONTS
        bool "Select compiled-in fonts"
-       depends on FRAMEBUFFER_CONSOLE
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        help
          Say Y here if you would like to use fonts other than the default
          your frame buffer console usually use.
@@ -22,7 +22,7 @@ config FONTS
 
 config FONT_8x8
        bool "VGA 8x8 font" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        default y if !SPARC && !FONTS
        help
          This is the "high resolution" font for the VGA frame buffer (the one
@@ -45,7 +45,7 @@ config FONT_8x16
 
 config FONT_6x11
        bool "Mac console 6x11 font (not supported by all drivers)" if FONTS
-       depends on FRAMEBUFFER_CONSOLE
+       depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
        default y if !SPARC && !FONTS && MAC
        help
          Small console font with Macintosh-style high-half glyphs.  Some Mac
index 7be235f1a70bed4c0e4b5c54b7af566e095a4396..93d145e5539c2e1bd0a9e8fc014739c178e6d0fc 100644 (file)
@@ -54,9 +54,7 @@ static inline void move_tags(unsigned *dst, unsigned *dst_nr,
 /*
  * Try to steal tags from a remote cpu's percpu freelist.
  *
- * We first check how many percpu freelists have tags - we don't steal tags
- * unless enough percpu freelists have tags on them that it's possible more than
- * half the total tags could be stuck on remote percpu freelists.
+ * We first check how many percpu freelists have tags
  *
  * Then we iterate through the cpus until we find some tags - we don't attempt
  * to find the "best" cpu to steal from, to keep cacheline bouncing to a
@@ -69,8 +67,7 @@ static inline void steal_tags(struct percpu_ida *pool,
        struct percpu_ida_cpu *remote;
 
        for (cpus_have_tags = cpumask_weight(&pool->cpus_have_tags);
-            cpus_have_tags * pool->percpu_max_size > pool->nr_tags / 2;
-            cpus_have_tags--) {
+            cpus_have_tags; cpus_have_tags--) {
                cpu = cpumask_next(cpu, &pool->cpus_have_tags);
 
                if (cpu >= nr_cpu_ids) {
index 7811ed3b4e701c2e0d82368a8bae457279ca3246..bd4a8dfdf0b8052cdaedd0b3478eea4138ac100a 100644 (file)
@@ -1253,8 +1253,10 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item)
 
                node = indirect_to_ptr(node);
                max_index = radix_tree_maxindex(node->height);
-               if (cur_index > max_index)
+               if (cur_index > max_index) {
+                       rcu_read_unlock();
                        break;
+               }
 
                cur_index = __locate(node, item, cur_index, &found_index);
                rcu_read_unlock();
index 1e5b2df442916de82ef497f844c068724f8cd555..61489677870007e273301209438ac4913562b140 100644 (file)
@@ -244,8 +244,19 @@ static void __prandom_reseed(bool late)
        static bool latch = false;
        static DEFINE_SPINLOCK(lock);
 
+       /* Asking for random bytes might result in bytes getting
+        * moved into the nonblocking pool and thus marking it
+        * as initialized. In this case we would double back into
+        * this function and attempt to do a late reseed.
+        * Ignore the pointless attempt to reseed again if we're
+        * already waiting for bytes when the nonblocking pool
+        * got initialized.
+        */
+
        /* only allow initial seeding (late == false) once */
-       spin_lock_irqsave(&lock, flags);
+       if (!spin_trylock_irqsave(&lock, flags))
+               return;
+
        if (latch && !late)
                goto out;
        latch = true;
index 2d9f1504d75e26d45ddf58fe2db8c048ecbc8d83..2888024e0b0abea6b6f37f4531ad0f8dfec5c7b3 100644 (file)
@@ -575,5 +575,5 @@ config PGTABLE_MAPPING
          then you should select this. This causes zsmalloc to use page table
          mapping rather than copying for object mapping.
 
-         You can check speed with zsmalloc benchmark[1].
-         [1] https://github.com/spartacus06/zsmalloc
+         You can check speed with zsmalloc benchmark:
+         https://github.com/spartacus06/zsmapbench
index b48c5259ea33dfed9e4c08c956d8e30a36480c42..918577595ea8695298cd21ecab7acaca35b1eb92 100644 (file)
@@ -251,7 +251,6 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 {
        int nr_scanned = 0, total_isolated = 0;
        struct page *cursor, *valid_page = NULL;
-       unsigned long nr_strict_required = end_pfn - blockpfn;
        unsigned long flags;
        bool locked = false;
 
@@ -264,11 +263,12 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                nr_scanned++;
                if (!pfn_valid_within(blockpfn))
-                       continue;
+                       goto isolate_fail;
+
                if (!valid_page)
                        valid_page = page;
                if (!PageBuddy(page))
-                       continue;
+                       goto isolate_fail;
 
                /*
                 * The zone lock must be held to isolate freepages.
@@ -289,12 +289,10 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
 
                /* Recheck this is a buddy page under lock */
                if (!PageBuddy(page))
-                       continue;
+                       goto isolate_fail;
 
                /* Found a free page, break it into order-0 pages */
                isolated = split_free_page(page);
-               if (!isolated && strict)
-                       break;
                total_isolated += isolated;
                for (i = 0; i < isolated; i++) {
                        list_add(&page->lru, freelist);
@@ -305,7 +303,15 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                if (isolated) {
                        blockpfn += isolated - 1;
                        cursor += isolated - 1;
+                       continue;
                }
+
+isolate_fail:
+               if (strict)
+                       break;
+               else
+                       continue;
+
        }
 
        trace_mm_compaction_isolate_freepages(nr_scanned, total_isolated);
@@ -315,7 +321,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
         * pages requested were isolated. If there were any failures, 0 is
         * returned and CMA will fail.
         */
-       if (strict && nr_strict_required > total_isolated)
+       if (strict && blockpfn < end_pfn)
                total_isolated = 0;
 
        if (locked)
index bbc4d660221ac4e514e24d49ce140b25ad5364d2..34feba60a17e6dce30b2cdfa929926ad5a450bee 100644 (file)
 
 #include "internal.h"
 
+static int mm_counter(struct page *page)
+{
+       return PageAnon(page) ? MM_ANONPAGES : MM_FILEPAGES;
+}
+
 static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long addr, pte_t *ptep)
 {
        pte_t pte = *ptep;
+       struct page *page;
+       swp_entry_t entry;
 
        if (pte_present(pte)) {
-               struct page *page;
-
                flush_cache_page(vma, addr, pte_pfn(pte));
                pte = ptep_clear_flush(vma, addr, ptep);
                page = vm_normal_page(vma, addr, pte);
                if (page) {
                        if (pte_dirty(pte))
                                set_page_dirty(page);
+                       update_hiwater_rss(mm);
+                       dec_mm_counter(mm, mm_counter(page));
                        page_remove_rmap(page);
                        page_cache_release(page);
+               }
+       } else {        /* zap_pte() is not called when pte_none() */
+               if (!pte_file(pte)) {
                        update_hiwater_rss(mm);
-                       dec_mm_counter(mm, MM_FILEPAGES);
+                       entry = pte_to_swp_entry(pte);
+                       if (non_swap_entry(entry)) {
+                               if (is_migration_entry(entry)) {
+                                       page = migration_entry_to_page(entry);
+                                       dec_mm_counter(mm, mm_counter(page));
+                               }
+                       } else {
+                               free_swap_and_cache(entry);
+                               dec_mm_counter(mm, MM_SWAPENTS);
+                       }
                }
-       } else {
-               if (!pte_file(pte))
-                       free_swap_and_cache(pte_to_swp_entry(pte));
                pte_clear_not_present_full(mm, addr, ptep, 0);
        }
 }
index 82166bf974e14262ecfb064ea7c173d006d3ab98..1546655a2d78afe4dc1c954b5e0ccff77ba3437f 100644 (file)
@@ -1166,8 +1166,10 @@ alloc:
                } else {
                        ret = do_huge_pmd_wp_page_fallback(mm, vma, address,
                                        pmd, orig_pmd, page, haddr);
-                       if (ret & VM_FAULT_OOM)
+                       if (ret & VM_FAULT_OOM) {
                                split_huge_page(page);
+                               ret |= VM_FAULT_FALLBACK;
+                       }
                        put_page(page);
                }
                count_vm_event(THP_FAULT_FALLBACK);
@@ -1179,9 +1181,10 @@ alloc:
                if (page) {
                        split_huge_page(page);
                        put_page(page);
-               }
+               } else
+                       split_huge_page_pmd(vma, address, pmd);
+               ret |= VM_FAULT_FALLBACK;
                count_vm_event(THP_FAULT_FALLBACK);
-               ret |= VM_FAULT_OOM;
                goto out;
        }
 
@@ -1545,6 +1548,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                                entry = pmd_mknonnuma(entry);
                        entry = pmd_modify(entry, newprot);
                        ret = HPAGE_PMD_NR;
+                       set_pmd_at(mm, addr, pmd, entry);
                        BUG_ON(pmd_write(entry));
                } else {
                        struct page *page = pmd_page(*pmd);
@@ -1557,16 +1561,10 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
                         */
                        if (!is_huge_zero_page(page) &&
                            !pmd_numa(*pmd)) {
-                               entry = *pmd;
-                               entry = pmd_mknuma(entry);
+                               pmdp_set_numa(mm, addr, pmd);
                                ret = HPAGE_PMD_NR;
                        }
                }
-
-               /* Set PMD if cleared earlier */
-               if (ret == HPAGE_PMD_NR)
-                       set_pmd_at(mm, addr, pmd, entry);
-
                spin_unlock(ptl);
        }
 
@@ -1963,7 +1961,7 @@ out:
        return ret;
 }
 
-#define VM_NO_THP (VM_SPECIAL|VM_MIXEDMAP|VM_HUGETLB|VM_SHARED|VM_MAYSHARE)
+#define VM_NO_THP (VM_SPECIAL | VM_HUGETLB | VM_SHARED | VM_MAYSHARE)
 
 int hugepage_madvise(struct vm_area_struct *vma,
                     unsigned long *vm_flags, int advice)
index aa4c7c7250c11a95b9676b70c7cc38f987d88717..68710e80994afed815c58b59a1a3cf421df8101f 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -444,7 +444,7 @@ static void break_cow(struct rmap_item *rmap_item)
 static struct page *page_trans_compound_anon(struct page *page)
 {
        if (PageTransCompound(page)) {
-               struct page *head = compound_trans_head(page);
+               struct page *head = compound_head(page);
                /*
                 * head may actually be splitted and freed from under
                 * us but it's ok here.
index 53385cd4e6f02cfae85f99a2629f735094130c78..5b6b0039f725032de5d63376aa0388e49bd3192d 100644 (file)
@@ -1127,8 +1127,8 @@ skip_node:
         * skipping css reference should be safe.
         */
        if (next_css) {
-               if ((next_css->flags & CSS_ONLINE) &&
-                               (next_css == &root->css || css_tryget(next_css)))
+               if ((next_css == &root->css) ||
+                   ((next_css->flags & CSS_ONLINE) && css_tryget(next_css)))
                        return mem_cgroup_from_css(next_css);
 
                prev_css = next_css;
@@ -1687,7 +1687,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
         * protects memcg_name and makes sure that parallel ooms do not
         * interleave
         */
-       static DEFINE_SPINLOCK(oom_info_lock);
+       static DEFINE_MUTEX(oom_info_lock);
        struct cgroup *task_cgrp;
        struct cgroup *mem_cgrp;
        static char memcg_name[PATH_MAX];
@@ -1698,7 +1698,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
        if (!p)
                return;
 
-       spin_lock(&oom_info_lock);
+       mutex_lock(&oom_info_lock);
        rcu_read_lock();
 
        mem_cgrp = memcg->css.cgroup;
@@ -1767,7 +1767,7 @@ done:
 
                pr_cont("\n");
        }
-       spin_unlock(&oom_info_lock);
+       mutex_unlock(&oom_info_lock);
 }
 
 /*
@@ -6595,6 +6595,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
        struct mem_cgroup_event *event, *tmp;
+       struct cgroup_subsys_state *iter;
 
        /*
         * Unregister events and notify userspace.
@@ -6611,7 +6612,14 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        kmem_cgroup_css_offline(memcg);
 
        mem_cgroup_invalidate_reclaim_iterators(memcg);
-       mem_cgroup_reparent_charges(memcg);
+
+       /*
+        * This requires that offlining is serialized.  Right now that is
+        * guaranteed because css_killed_work_fn() holds the cgroup_mutex.
+        */
+       css_for_each_descendant_post(iter, css)
+               mem_cgroup_reparent_charges(mem_cgroup_from_css(iter));
+
        mem_cgroup_destroy_all_caches(memcg);
        vmpressure_cleanup(&memcg->vmpressure);
 }
index 4f08a2d61487f3c45dc01638c31b6aff689ce6e7..90002ea43638cd0dd669d12092837714ec3113f3 100644 (file)
@@ -945,8 +945,10 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
                         * to it. Similarly, page lock is shifted.
                         */
                        if (hpage != p) {
-                               put_page(hpage);
-                               get_page(p);
+                               if (!(flags & MF_COUNT_INCREASED)) {
+                                       put_page(hpage);
+                                       get_page(p);
+                               }
                                lock_page(p);
                                unlock_page(hpage);
                                *hpagep = p;
@@ -1649,7 +1651,7 @@ int soft_offline_page(struct page *page, int flags)
 {
        int ret;
        unsigned long pfn = page_to_pfn(page);
-       struct page *hpage = compound_trans_head(page);
+       struct page *hpage = compound_head(page);
 
        if (PageHWPoison(page)) {
                pr_info("soft offline: %#lx page already poisoned\n", pfn);
index be6a0c0d4ae081d48edd26f09d37f67cc70b1c52..22dfa617bddb69af777298c45739a0113f965b13 100644 (file)
@@ -3348,6 +3348,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                if (ret & VM_FAULT_LOCKED)
                        unlock_page(vmf.page);
                ret = VM_FAULT_HWPOISON;
+               page_cache_release(vmf.page);
                goto uncharge_out;
        }
 
@@ -3703,7 +3704,6 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (unlikely(is_vm_hugetlb_page(vma)))
                return hugetlb_fault(mm, vma, address, flags);
 
-retry:
        pgd = pgd_offset(mm, address);
        pud = pud_alloc(mm, pgd, address);
        if (!pud)
@@ -3741,20 +3741,13 @@ retry:
                        if (dirty && !pmd_write(orig_pmd)) {
                                ret = do_huge_pmd_wp_page(mm, vma, address, pmd,
                                                          orig_pmd);
-                               /*
-                                * If COW results in an oom, the huge pmd will
-                                * have been split, so retry the fault on the
-                                * pte for a smaller charge.
-                                */
-                               if (unlikely(ret & VM_FAULT_OOM))
-                                       goto retry;
-                               return ret;
+                               if (!(ret & VM_FAULT_FALLBACK))
+                                       return ret;
                        } else {
                                huge_pmd_set_accessed(mm, vma, address, pmd,
                                                      orig_pmd, dirty);
+                               return 0;
                        }
-
-                       return 0;
                }
        }
 
index 482a33d89134fd83e15d5f6863dae57f5cb05aac..bed48809e5d01c14513a1395a12a3c4098341755 100644 (file)
@@ -177,6 +177,37 @@ out:
        return SWAP_AGAIN;
 }
 
+/*
+ * Congratulations to trinity for discovering this bug.
+ * mm/fremap.c's remap_file_pages() accepts any range within a single vma to
+ * convert that vma to VM_NONLINEAR; and generic_file_remap_pages() will then
+ * replace the specified range by file ptes throughout (maybe populated after).
+ * If page migration finds a page within that range, while it's still located
+ * by vma_interval_tree rather than lost to i_mmap_nonlinear list, no problem:
+ * zap_pte() clears the temporary migration entry before mmap_sem is dropped.
+ * But if the migrating page is in a part of the vma outside the range to be
+ * remapped, then it will not be cleared, and remove_migration_ptes() needs to
+ * deal with it.  Fortunately, this part of the vma is of course still linear,
+ * so we just need to use linear location on the nonlinear list.
+ */
+static int remove_linear_migration_ptes_from_nonlinear(struct page *page,
+               struct address_space *mapping, void *arg)
+{
+       struct vm_area_struct *vma;
+       /* hugetlbfs does not support remap_pages, so no huge pgoff worries */
+       pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT);
+       unsigned long addr;
+
+       list_for_each_entry(vma,
+               &mapping->i_mmap_nonlinear, shared.nonlinear) {
+
+               addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+               if (addr >= vma->vm_start && addr < vma->vm_end)
+                       remove_migration_pte(page, vma, addr, arg);
+       }
+       return SWAP_AGAIN;
+}
+
 /*
  * Get rid of all migration entries and replace them by
  * references to the indicated page.
@@ -186,6 +217,7 @@ static void remove_migration_ptes(struct page *old, struct page *new)
        struct rmap_walk_control rwc = {
                .rmap_one = remove_migration_pte,
                .arg = old,
+               .file_nonlinear = remove_linear_migration_ptes_from_nonlinear,
        };
 
        rmap_walk(new, &rwc);
@@ -1158,7 +1190,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
                                        pm->node);
        else
                return alloc_pages_exact_node(pm->node,
-                               GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
+                               GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0);
 }
 
 /*
@@ -1544,9 +1576,9 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
        struct page *newpage;
 
        newpage = alloc_pages_exact_node(nid,
-                                        (GFP_HIGHUSER_MOVABLE | GFP_THISNODE |
-                                         __GFP_NOMEMALLOC | __GFP_NORETRY |
-                                         __GFP_NOWARN) &
+                                        (GFP_HIGHUSER_MOVABLE |
+                                         __GFP_THISNODE | __GFP_NOMEMALLOC |
+                                         __GFP_NORETRY | __GFP_NOWARN) &
                                         ~GFP_IOFS, 0);
 
        return newpage;
@@ -1747,7 +1779,8 @@ int migrate_misplaced_transhuge_page(struct mm_struct *mm,
                goto out_dropref;
 
        new_page = alloc_pages_node(node,
-               (GFP_TRANSHUGE | GFP_THISNODE) & ~__GFP_WAIT, HPAGE_PMD_ORDER);
+               (GFP_TRANSHUGE | __GFP_THISNODE) & ~__GFP_WAIT,
+               HPAGE_PMD_ORDER);
        if (!new_page)
                goto out_fail;
 
index 7332c1785744fa0517a213b489e9c5b6bf350937..769a67a158037197341742104d2a9023cb1e03a0 100644 (file)
@@ -58,36 +58,27 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                                if (pte_numa(ptent))
                                        ptent = pte_mknonnuma(ptent);
                                ptent = pte_modify(ptent, newprot);
+                               /*
+                                * Avoid taking write faults for pages we
+                                * know to be dirty.
+                                */
+                               if (dirty_accountable && pte_dirty(ptent))
+                                       ptent = pte_mkwrite(ptent);
+                               ptep_modify_prot_commit(mm, addr, pte, ptent);
                                updated = true;
                        } else {
                                struct page *page;
 
-                               ptent = *pte;
                                page = vm_normal_page(vma, addr, oldpte);
                                if (page && !PageKsm(page)) {
                                        if (!pte_numa(oldpte)) {
-                                               ptent = pte_mknuma(ptent);
-                                               set_pte_at(mm, addr, pte, ptent);
+                                               ptep_set_numa(mm, addr, pte);
                                                updated = true;
                                        }
                                }
                        }
-
-                       /*
-                        * Avoid taking write faults for pages we know to be
-                        * dirty.
-                        */
-                       if (dirty_accountable && pte_dirty(ptent)) {
-                               ptent = pte_mkwrite(ptent);
-                               updated = true;
-                       }
-
                        if (updated)
                                pages++;
-
-                       /* Only !prot_numa always clears the pte */
-                       if (!prot_numa)
-                               ptep_modify_prot_commit(mm, addr, pte, ptent);
                } else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) {
                        swp_entry_t entry = pte_to_swp_entry(oldpte);
 
index e3758a09a009747bd17cb75442d0fcae69a74cc4..3bac76ae4b30ec8a62042bdff9644e87ee181d3c 100644 (file)
@@ -369,9 +369,11 @@ void prep_compound_page(struct page *page, unsigned long order)
        __SetPageHead(page);
        for (i = 1; i < nr_pages; i++) {
                struct page *p = page + i;
-               __SetPageTail(p);
                set_page_count(p, 0);
                p->first_page = page;
+               /* Make sure p->first_page is always valid for PageTail() */
+               smp_wmb();
+               __SetPageTail(p);
        }
 }
 
@@ -1236,6 +1238,15 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
        }
        local_irq_restore(flags);
 }
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+       return (gfp_mask & GFP_THISNODE) == GFP_THISNODE;
+}
+#else
+static bool gfp_thisnode_allocation(gfp_t gfp_mask)
+{
+       return false;
+}
 #endif
 
 /*
@@ -1572,7 +1583,13 @@ again:
                                          get_pageblock_migratetype(page));
        }
 
-       __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+       /*
+        * NOTE: GFP_THISNODE allocations do not partake in the kswapd
+        * aging protocol, so they can't be fair.
+        */
+       if (!gfp_thisnode_allocation(gfp_flags))
+               __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+
        __count_zone_vm_events(PGALLOC, zone, 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
@@ -1944,8 +1961,12 @@ zonelist_scan:
                 * ultimately fall back to remote zones that do not
                 * partake in the fairness round-robin cycle of this
                 * zonelist.
+                *
+                * NOTE: GFP_THISNODE allocations do not partake in
+                * the kswapd aging protocol, so they can't be fair.
                 */
-               if (alloc_flags & ALLOC_WMARK_LOW) {
+               if ((alloc_flags & ALLOC_WMARK_LOW) &&
+                   !gfp_thisnode_allocation(gfp_mask)) {
                        if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
                                continue;
                        if (!zone_local(preferred_zone, zone))
@@ -2501,8 +2522,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
         * allowed per node queues are empty and that nodes are
         * over allocated.
         */
-       if (IS_ENABLED(CONFIG_NUMA) &&
-                       (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
+       if (gfp_thisnode_allocation(gfp_mask))
                goto nopage;
 
 restart:
index d9d42316a99a917ff6562c7cbc54dd50a085a1f6..8fc049f9a5a6c5d511ac7a5ac0dd41c698ed99a3 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1360,8 +1360,9 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
 }
 
 static int try_to_unmap_nonlinear(struct page *page,
-               struct address_space *mapping, struct vm_area_struct *vma)
+               struct address_space *mapping, void *arg)
 {
+       struct vm_area_struct *vma;
        int ret = SWAP_AGAIN;
        unsigned long cursor;
        unsigned long max_nl_cursor = 0;
@@ -1663,7 +1664,7 @@ static int rmap_walk_file(struct page *page, struct rmap_walk_control *rwc)
        if (list_empty(&mapping->i_mmap_nonlinear))
                goto done;
 
-       ret = rwc->file_nonlinear(page, mapping, vma);
+       ret = rwc->file_nonlinear(page, mapping, rwc->arg);
 
 done:
        mutex_unlock(&mapping->i_mmap_mutex);
index 7e3e0458bce4180d115469b8ce622afef9b1e367..25f14ad8f817443bda93901aa8ab0b626280f297 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1004,21 +1004,19 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
 static void add_full(struct kmem_cache *s,
        struct kmem_cache_node *n, struct page *page)
 {
-       lockdep_assert_held(&n->list_lock);
-
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
+       lockdep_assert_held(&n->list_lock);
        list_add(&page->lru, &n->full);
 }
 
 static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct page *page)
 {
-       lockdep_assert_held(&n->list_lock);
-
        if (!(s->flags & SLAB_STORE_USER))
                return;
 
+       lockdep_assert_held(&n->list_lock);
        list_del(&page->lru);
 }
 
@@ -1520,11 +1518,9 @@ static void discard_slab(struct kmem_cache *s, struct page *page)
 /*
  * Management of partially allocated slabs.
  */
-static inline void add_partial(struct kmem_cache_node *n,
-                               struct page *page, int tail)
+static inline void
+__add_partial(struct kmem_cache_node *n, struct page *page, int tail)
 {
-       lockdep_assert_held(&n->list_lock);
-
        n->nr_partial++;
        if (tail == DEACTIVATE_TO_TAIL)
                list_add_tail(&page->lru, &n->partial);
@@ -1532,15 +1528,27 @@ static inline void add_partial(struct kmem_cache_node *n,
                list_add(&page->lru, &n->partial);
 }
 
-static inline void remove_partial(struct kmem_cache_node *n,
-                                       struct page *page)
+static inline void add_partial(struct kmem_cache_node *n,
+                               struct page *page, int tail)
 {
        lockdep_assert_held(&n->list_lock);
+       __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);
+}
+
 /*
  * Remove slab from the partial list, freeze it and
  * return the pointer to the freelist.
@@ -2906,12 +2914,10 @@ static void early_kmem_cache_node_alloc(int node)
        inc_slabs_node(kmem_cache_node, node, page->objects);
 
        /*
-        * the lock is for lockdep's sake, not for any actual
-        * race protection
+        * No locks need to be taken here as it has just been
+        * initialized and there is no concurrent access.
         */
-       spin_lock(&n->list_lock);
-       add_partial(n, page, DEACTIVATE_TO_HEAD);
-       spin_unlock(&n->list_lock);
+       __add_partial(n, page, DEACTIVATE_TO_HEAD);
 }
 
 static void free_kmem_cache_nodes(struct kmem_cache *s)
@@ -3197,7 +3203,7 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
 
        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,
index b31ba67d440ac997a05de372e831046bf98d9070..0092097b3f4ce5e22844759a9e264ef143d05c7c 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -98,7 +98,7 @@ static void put_compound_page(struct page *page)
        }
 
        /* __split_huge_page_refcount can run under us */
-       page_head = compound_trans_head(page);
+       page_head = compound_head(page);
 
        /*
         * THP can not break up slab pages so avoid taking
@@ -253,7 +253,7 @@ bool __get_page_tail(struct page *page)
         */
        unsigned long flags;
        bool got;
-       struct page *page_head = compound_trans_head(page);
+       struct page *page_head = compound_head(page);
 
        /* Ref to put_compound_page() comment. */
        if (!__compound_tail_refcounted(page_head)) {
index 196970a4541f0c07108eff49b7cb8d12fd930b06..d4042e75f7c7e7c7d498c4fcc33c90f1d1de2bff 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mm.h>
 #include <linux/vmstat.h>
 #include <linux/eventfd.h>
+#include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/printk.h>
 #include <linux/vmpressure.h>
index ec9909935fb60850ed3635e1636f568c8c88bbf0..175273f38cb1bd59f5aeb88cb8c815033475dfe8 100644 (file)
@@ -307,9 +307,11 @@ static void vlan_sync_address(struct net_device *dev,
 static void vlan_transfer_features(struct net_device *dev,
                                   struct net_device *vlandev)
 {
+       struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev);
+
        vlandev->gso_max_size = dev->gso_max_size;
 
-       if (dev->features & NETIF_F_HW_VLAN_CTAG_TX)
+       if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto))
                vlandev->hard_header_len = dev->hard_header_len;
        else
                vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN;
index 5704ed9c3a23bb13d1d5b41f36d6575fd3ec3ed9..9d010a09ab9880a6eb15cee0524b46be53d76587 100644 (file)
@@ -38,9 +38,9 @@ struct vlan_info {
 static inline unsigned int vlan_proto_idx(__be16 proto)
 {
        switch (proto) {
-       case __constant_htons(ETH_P_8021Q):
+       case htons(ETH_P_8021Q):
                return VLAN_PROTO_8021Q;
-       case __constant_htons(ETH_P_8021AD):
+       case htons(ETH_P_8021AD):
                return VLAN_PROTO_8021AD;
        default:
                BUG();
index 6ee48aac776fbe84db68a503d9aca10ca45b0081..3c32bd257b73975a33ba104c1c3b3797d9f29843 100644 (file)
@@ -22,11 +22,11 @@ bool vlan_do_receive(struct sk_buff **skbp)
                return false;
 
        skb->dev = vlan_dev;
-       if (skb->pkt_type == PACKET_OTHERHOST) {
+       if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
                /* Our lower layer thinks this is not local, let's make sure.
                 * This allows the VLAN to have a different MAC than the
                 * underlying device, and still route correctly. */
-               if (ether_addr_equal(eth_hdr(skb)->h_dest, vlan_dev->dev_addr))
+               if (ether_addr_equal_64bits(eth_hdr(skb)->h_dest, vlan_dev->dev_addr))
                        skb->pkt_type = PACKET_HOST;
        }
 
@@ -106,6 +106,12 @@ u16 vlan_dev_vlan_id(const struct net_device *dev)
 }
 EXPORT_SYMBOL(vlan_dev_vlan_id);
 
+__be16 vlan_dev_vlan_proto(const struct net_device *dev)
+{
+       return vlan_dev_priv(dev)->vlan_proto;
+}
+EXPORT_SYMBOL(vlan_dev_vlan_proto);
+
 static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
 {
        if (skb_cow(skb, skb_headroom(skb)) < 0)
index de51c48c439382db712761747188dc72061c82b0..6f142f03716d04effac77f0e2210879eff3daddb 100644 (file)
@@ -538,6 +538,9 @@ static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev
        struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
        struct net_device *real_dev = vlan->real_dev;
 
+       if (saddr == NULL)
+               saddr = dev->dev_addr;
+
        return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
 }
 
@@ -556,7 +559,7 @@ static const struct net_device_ops vlan_netdev_ops;
 static int vlan_dev_init(struct net_device *dev)
 {
        struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
-       int subclass = 0, i;
+       int subclass = 0;
 
        netif_carrier_off(dev);
 
@@ -575,6 +578,9 @@ static int vlan_dev_init(struct net_device *dev)
 
        dev->features |= real_dev->vlan_features | NETIF_F_LLTX;
        dev->gso_max_size = real_dev->gso_max_size;
+       if (dev->features & NETIF_F_VLAN_FEATURES)
+               netdev_warn(real_dev, "VLAN features are set incorrectly.  Q-in-Q configurations may not work correctly.\n");
+
 
        /* ipv6 shared card related stuff */
        dev->dev_id = real_dev->dev_id;
@@ -589,7 +595,8 @@ static int vlan_dev_init(struct net_device *dev)
 #endif
 
        dev->needed_headroom = real_dev->needed_headroom;
-       if (real_dev->features & NETIF_F_HW_VLAN_CTAG_TX) {
+       if (vlan_hw_offload_capable(real_dev->features,
+                                   vlan_dev_priv(dev)->vlan_proto)) {
                dev->header_ops      = &vlan_passthru_header_ops;
                dev->hard_header_len = real_dev->hard_header_len;
        } else {
@@ -606,17 +613,10 @@ static int vlan_dev_init(struct net_device *dev)
 
        vlan_dev_set_lockdep_class(dev, subclass);
 
-       vlan_dev_priv(dev)->vlan_pcpu_stats = alloc_percpu(struct vlan_pcpu_stats);
+       vlan_dev_priv(dev)->vlan_pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats);
        if (!vlan_dev_priv(dev)->vlan_pcpu_stats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct vlan_pcpu_stats *vlan_stat;
-               vlan_stat = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
-               u64_stats_init(&vlan_stat->syncp);
-       }
-
-
        return 0;
 }
 
@@ -682,13 +682,13 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, st
 
                        p = per_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats, i);
                        do {
-                               start = u64_stats_fetch_begin_bh(&p->syncp);
+                               start = u64_stats_fetch_begin_irq(&p->syncp);
                                rxpackets       = p->rx_packets;
                                rxbytes         = p->rx_bytes;
                                rxmulticast     = p->rx_multicast;
                                txpackets       = p->tx_packets;
                                txbytes         = p->tx_bytes;
-                       } while (u64_stats_fetch_retry_bh(&p->syncp, start));
+                       } while (u64_stats_fetch_retry_irq(&p->syncp, start));
 
                        stats->rx_packets       += rxpackets;
                        stats->rx_bytes         += rxbytes;
@@ -711,20 +711,19 @@ static void vlan_dev_poll_controller(struct net_device *dev)
        return;
 }
 
-static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo,
-                                 gfp_t gfp)
+static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
 {
        struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
        struct net_device *real_dev = vlan->real_dev;
        struct netpoll *netpoll;
        int err = 0;
 
-       netpoll = kzalloc(sizeof(*netpoll), gfp);
+       netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
        err = -ENOMEM;
        if (!netpoll)
                goto out;
 
-       err = __netpoll_setup(netpoll, real_dev, gfp);
+       err = __netpoll_setup(netpoll, real_dev);
        if (err) {
                kfree(netpoll);
                goto out;
index c7e634af85165613822074b28ceeca4af7153ae7..8ac8a5cc214331253e591fe26f6c3b39a00d5023 100644 (file)
@@ -56,8 +56,8 @@ static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
 
        if (data[IFLA_VLAN_PROTOCOL]) {
                switch (nla_get_be16(data[IFLA_VLAN_PROTOCOL])) {
-               case __constant_htons(ETH_P_8021Q):
-               case __constant_htons(ETH_P_8021AD):
+               case htons(ETH_P_8021Q):
+               case htons(ETH_P_8021AD):
                        break;
                default:
                        return -EPROTONOSUPPORT;
index a5e4d2dcb03e8c98eae243e1dd1b82cea68bd227..9186550d77a61b84c8f310ad7cd8e602ed116980 100644 (file)
@@ -204,7 +204,7 @@ free_and_return:
        return ret;
 }
 
-struct p9_fcall *p9_fcall_alloc(int alloc_msize)
+static struct p9_fcall *p9_fcall_alloc(int alloc_msize)
 {
        struct p9_fcall *fc;
        fc = kmalloc(sizeof(struct p9_fcall) + alloc_msize, GFP_NOFS);
index cd1e1ede73a45c2516091263c937f45024616c4e..ac2666c1d01127ab5ac73946377c6edd1a3ffb67 100644 (file)
@@ -340,7 +340,10 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
                int count = nr_pages;
                while (nr_pages) {
                        s = rest_of_page(data);
-                       pages[index++] = kmap_to_page(data);
+                       if (is_vmalloc_addr(data))
+                               pages[index++] = vmalloc_to_page(data);
+                       else
+                               pages[index++] = kmap_to_page(data);
                        data += s;
                        nr_pages--;
                }
index d27b86dfb0e92bf467b95f7e488f736cff8db657..d1c55d8dd0a2538eaabe403ceeb26896c00adf66 100644 (file)
@@ -926,7 +926,7 @@ static struct aarp_entry *iter_next(struct aarp_iter_state *iter, loff_t *pos)
        struct aarp_entry *entry;
 
  rescan:
-       while(ct < AARP_HASH_SIZE) {
+       while (ct < AARP_HASH_SIZE) {
                for (entry = table[ct]; entry; entry = entry->next) {
                        if (!pos || ++off == *pos) {
                                iter->table = table;
@@ -995,7 +995,7 @@ static const char *dt2str(unsigned long ticks)
 {
        static char buf[32];
 
-       sprintf(buf, "%ld.%02ld", ticks / HZ, ((ticks % HZ) * 100 ) / HZ);
+       sprintf(buf, "%ld.%02ld", ticks / HZ, ((ticks % HZ) * 100) / HZ);
 
        return buf;
 }
index 02806c6b2ff36c86bc15d5da4230fbadb8d0a538..786ee2f83d5fea1dbfd6bb2660544d7f88e1eff2 100644 (file)
@@ -293,7 +293,7 @@ static int atif_probe_device(struct atalk_iface *atif)
 
 /* Perform AARP probing for a proxy address */
 static int atif_proxy_probe_device(struct atalk_iface *atif,
-                                  struct atalk_addrproxy_addr)
+                                  struct atalk_addr *proxy_addr)
 {
        int netrange = ntohs(atif->nets.nr_lastnet) -
                        ntohs(atif->nets.nr_firstnet) + 1;
@@ -581,7 +581,7 @@ out:
 }
 
 /* Delete a route. Find it and discard it */
-static int atrtr_delete(struct atalk_addr * addr)
+static int atrtr_delete(struct atalk_addr *addr)
 {
        struct atalk_route **r = &atalk_routes;
        int retval = 0;
@@ -936,11 +936,11 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
        int i, copy;
 
        /* checksum stuff in header space */
-       if ( (copy = start - offset) > 0) {
+       if ((copy = start - offset) > 0) {
                if (copy > len)
                        copy = len;
                sum = atalk_sum_partial(skb->data + offset, copy, sum);
-               if ( (len -= copy) == 0)
+               if ((len -= copy) == 0)
                        return sum;
 
                offset += copy;
@@ -1151,7 +1151,7 @@ static int atalk_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                        goto out;
 
                at->src_net  = addr->sat_addr.s_net = ap->s_net;
-               at->src_node = addr->sat_addr.s_node= ap->s_node;
+               at->src_node = addr->sat_addr.s_node = ap->s_node;
        } else {
                err = -EADDRNOTAVAIL;
                if (!atalk_find_interface(addr->sat_addr.s_net,
@@ -1790,53 +1790,53 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        void __user *argp = (void __user *)arg;
 
        switch (cmd) {
-               /* Protocol layer */
-               case TIOCOUTQ: {
-                       long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
+       /* Protocol layer */
+       case TIOCOUTQ: {
+               long amount = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
 
-                       if (amount < 0)
-                               amount = 0;
-                       rc = put_user(amount, (int __user *)argp);
-                       break;
-               }
-               case TIOCINQ: {
-                       /*
-                        * These two are safe on a single CPU system as only
-                        * user tasks fiddle here
-                        */
-                       struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
-                       long amount = 0;
+               if (amount < 0)
+                       amount = 0;
+               rc = put_user(amount, (int __user *)argp);
+               break;
+       }
+       case TIOCINQ: {
+               /*
+                * These two are safe on a single CPU system as only
+                * user tasks fiddle here
+                */
+               struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
+               long amount = 0;
 
-                       if (skb)
-                               amount = skb->len - sizeof(struct ddpehdr);
-                       rc = put_user(amount, (int __user *)argp);
-                       break;
-               }
-               case SIOCGSTAMP:
-                       rc = sock_get_timestamp(sk, argp);
-                       break;
-               case SIOCGSTAMPNS:
-                       rc = sock_get_timestampns(sk, argp);
-                       break;
-               /* Routing */
-               case SIOCADDRT:
-               case SIOCDELRT:
-                       rc = -EPERM;
-                       if (capable(CAP_NET_ADMIN))
-                               rc = atrtr_ioctl(cmd, argp);
-                       break;
-               /* Interface */
-               case SIOCGIFADDR:
-               case SIOCSIFADDR:
-               case SIOCGIFBRDADDR:
-               case SIOCATALKDIFADDR:
-               case SIOCDIFADDR:
-               case SIOCSARP:          /* proxy AARP */
-               case SIOCDARP:          /* proxy AARP */
-                       rtnl_lock();
-                       rc = atif_ioctl(cmd, argp);
-                       rtnl_unlock();
-                       break;
+               if (skb)
+               amount = skb->len - sizeof(struct ddpehdr);
+               rc = put_user(amount, (int __user *)argp);
+               break;
+       }
+       case SIOCGSTAMP:
+               rc = sock_get_timestamp(sk, argp);
+               break;
+       case SIOCGSTAMPNS:
+               rc = sock_get_timestampns(sk, argp);
+               break;
+       /* Routing */
+       case SIOCADDRT:
+       case SIOCDELRT:
+               rc = -EPERM;
+               if (capable(CAP_NET_ADMIN))
+                       rc = atrtr_ioctl(cmd, argp);
+               break;
+       /* Interface */
+       case SIOCGIFADDR:
+       case SIOCSIFADDR:
+       case SIOCGIFBRDADDR:
+       case SIOCATALKDIFADDR:
+       case SIOCDIFADDR:
+       case SIOCSARP:          /* proxy AARP */
+       case SIOCDARP:          /* proxy AARP */
+               rtnl_lock();
+               rc = atif_ioctl(cmd, argp);
+               rtnl_unlock();
+               break;
        }
 
        return rc;
index b71ff6b234f2bb1c6d97915eb5a4fb6ab4d1851d..91dc58f1124dd976e4cca35af2407eb2c0e25ecc 100644 (file)
@@ -1492,7 +1492,7 @@ static void __exit atm_mpoa_cleanup(void)
 
        mpc_proc_clean();
 
-       del_timer(&mpc_timer);
+       del_timer_sync(&mpc_timer);
        unregister_netdevice_notifier(&mpoa_notifier);
        deregister_atm_ioctl(&atm_ioctl_ops);
 
index fa780b76630e4def219fc5f464554a4361721229..11660a3aab5ae0b7e0f3f2a111c6e6ab2081de59 100644 (file)
@@ -50,6 +50,15 @@ config BATMAN_ADV_NC
          If you think that your network does not need this feature you
          can safely disable it and save some space.
 
+config BATMAN_ADV_MCAST
+       bool "Multicast optimisation"
+       depends on BATMAN_ADV
+       default n
+       help
+         This option enables the multicast optimisation which aims to
+         reduce the air overhead while improving the reliability of
+         multicast messages.
+
 config BATMAN_ADV_DEBUG
        bool "B.A.T.M.A.N. debugging"
        depends on BATMAN_ADV
index 42df18f877e9304a515a30f2122ae0c324984356..eb7d8c0388e4a32a52ba076460463a722d0db612 100644 (file)
@@ -36,3 +36,4 @@ batman-adv-y += send.o
 batman-adv-y += soft-interface.o
 batman-adv-y += sysfs.o
 batman-adv-y += translation-table.o
+batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o
index 512159bf607f0d4a3b09eae9af101775a8b56441..b3bd4ec3fd9452f0d1f9a99dd4782260ab65c818 100644 (file)
@@ -241,19 +241,19 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr)
        size = bat_priv->num_ifaces * sizeof(uint8_t);
        orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC);
        if (!orig_node->bat_iv.bcast_own_sum)
-               goto free_bcast_own;
+               goto free_orig_node;
 
        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)
-               goto free_bcast_own;
+               goto free_orig_node;
 
        return orig_node;
 
-free_bcast_own:
-       kfree(orig_node->bat_iv.bcast_own);
 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);
 
        return NULL;
@@ -266,7 +266,7 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
                        struct batadv_orig_node *orig_neigh)
 {
        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
-       struct batadv_neigh_node *neigh_node;
+       struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
 
        neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node);
        if (!neigh_node)
@@ -281,14 +281,24 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
        neigh_node->orig_node = orig_neigh;
        neigh_node->if_incoming = hard_iface;
 
-       batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
-                  "Creating new neighbor %pM for orig_node %pM on interface %s\n",
-                  neigh_addr, orig_node->orig, hard_iface->net_dev->name);
-
        spin_lock_bh(&orig_node->neigh_list_lock);
-       hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+       tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface,
+                                              neigh_addr);
+       if (!tmp_neigh_node) {
+               hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
+       } else {
+               kfree(neigh_node);
+               batadv_hardif_free_ref(hard_iface);
+               neigh_node = tmp_neigh_node;
+       }
        spin_unlock_bh(&orig_node->neigh_list_lock);
 
+       if (!tmp_neigh_node)
+               batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
+                          "Creating new neighbor %pM for orig_node %pM on interface %s\n",
+                          neigh_addr, orig_node->orig,
+                          hard_iface->net_dev->name);
+
 out:
        return neigh_node;
 }
@@ -337,10 +347,10 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
        unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
 
        batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
-       memcpy(batadv_ogm_packet->orig,
-              hard_iface->net_dev->dev_addr, ETH_ALEN);
-       memcpy(batadv_ogm_packet->prev_sender,
-              hard_iface->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(batadv_ogm_packet->orig,
+                       hard_iface->net_dev->dev_addr);
+       ether_addr_copy(batadv_ogm_packet->prev_sender,
+                       hard_iface->net_dev->dev_addr);
 }
 
 static void
@@ -820,7 +830,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node,
        tvlv_len = ntohs(batadv_ogm_packet->tvlv_len);
 
        batadv_ogm_packet->ttl--;
-       memcpy(batadv_ogm_packet->prev_sender, ethhdr->h_source, ETH_ALEN);
+       ether_addr_copy(batadv_ogm_packet->prev_sender, ethhdr->h_source);
 
        /* apply hop penalty */
        batadv_ogm_packet->tq = batadv_hop_penalty(batadv_ogm_packet->tq,
index 05f0712be5e7fe3b1fe357d454e6eb9e6c779fc5..6f0d9ec3795059fdc5319574b65b24c08aaf2790 100644 (file)
@@ -191,7 +191,7 @@ batadv_backbone_hash_find(struct batadv_priv *bat_priv,
        if (!hash)
                return NULL;
 
-       memcpy(search_entry.orig, addr, ETH_ALEN);
+       ether_addr_copy(search_entry.orig, addr);
        search_entry.vid = vid;
 
        index = batadv_choose_backbone_gw(&search_entry, hash->size);
@@ -305,7 +305,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac,
                /* normal claim frame
                 * set Ethernet SRC to the clients mac
                 */
-               memcpy(ethhdr->h_source, mac, ETH_ALEN);
+               ether_addr_copy(ethhdr->h_source, mac);
                batadv_dbg(BATADV_DBG_BLA, bat_priv,
                           "bla_send_claim(): CLAIM %pM on vid %d\n", mac,
                           BATADV_PRINT_VID(vid));
@@ -314,7 +314,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac,
                /* unclaim frame
                 * set HW SRC to the clients mac
                 */
-               memcpy(hw_src, mac, ETH_ALEN);
+               ether_addr_copy(hw_src, mac);
                batadv_dbg(BATADV_DBG_BLA, bat_priv,
                           "bla_send_claim(): UNCLAIM %pM on vid %d\n", mac,
                           BATADV_PRINT_VID(vid));
@@ -323,7 +323,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac,
                /* announcement frame
                 * set HW SRC to the special mac containg the crc
                 */
-               memcpy(hw_src, mac, ETH_ALEN);
+               ether_addr_copy(hw_src, mac);
                batadv_dbg(BATADV_DBG_BLA, bat_priv,
                           "bla_send_claim(): ANNOUNCE of %pM on vid %d\n",
                           ethhdr->h_source, BATADV_PRINT_VID(vid));
@@ -333,8 +333,8 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac,
                 * set HW SRC and header destination to the receiving backbone
                 * gws mac
                 */
-               memcpy(hw_src, mac, ETH_ALEN);
-               memcpy(ethhdr->h_dest, mac, ETH_ALEN);
+               ether_addr_copy(hw_src, mac);
+               ether_addr_copy(ethhdr->h_dest, mac);
                batadv_dbg(BATADV_DBG_BLA, bat_priv,
                           "bla_send_claim(): REQUEST of %pM to %pM on vid %d\n",
                           ethhdr->h_source, ethhdr->h_dest,
@@ -395,7 +395,7 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig,
        entry->bat_priv = bat_priv;
        atomic_set(&entry->request_sent, 0);
        atomic_set(&entry->wait_periods, 0);
-       memcpy(entry->orig, orig, ETH_ALEN);
+       ether_addr_copy(entry->orig, orig);
 
        /* one for the hash, one for returning */
        atomic_set(&entry->refcount, 2);
@@ -563,7 +563,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
        struct batadv_bla_claim search_claim;
        int hash_added;
 
-       memcpy(search_claim.addr, mac, ETH_ALEN);
+       ether_addr_copy(search_claim.addr, mac);
        search_claim.vid = vid;
        claim = batadv_claim_hash_find(bat_priv, &search_claim);
 
@@ -573,7 +573,7 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
                if (!claim)
                        return;
 
-               memcpy(claim->addr, mac, ETH_ALEN);
+               ether_addr_copy(claim->addr, mac);
                claim->vid = vid;
                claim->lasttime = jiffies;
                claim->backbone_gw = backbone_gw;
@@ -624,7 +624,7 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv,
 {
        struct batadv_bla_claim search_claim, *claim;
 
-       memcpy(search_claim.addr, mac, ETH_ALEN);
+       ether_addr_copy(search_claim.addr, mac);
        search_claim.vid = vid;
        claim = batadv_claim_hash_find(bat_priv, &search_claim);
        if (!claim)
@@ -882,7 +882,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
        proto = ethhdr->h_proto;
        headlen = ETH_HLEN;
        if (vid & BATADV_VLAN_HAS_TAG) {
-               vhdr = (struct vlan_ethhdr *)ethhdr;
+               vhdr = vlan_eth_hdr(skb);
                proto = vhdr->h_vlan_encapsulated_proto;
                headlen += VLAN_HLEN;
        }
@@ -1103,8 +1103,8 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
                                                oldif->net_dev->dev_addr))
                                continue;
 
-                       memcpy(backbone_gw->orig,
-                              primary_if->net_dev->dev_addr, ETH_ALEN);
+                       ether_addr_copy(backbone_gw->orig,
+                                       primary_if->net_dev->dev_addr);
                        /* send an announce frame so others will ask for our
                         * claims and update their tables.
                         */
@@ -1310,7 +1310,7 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
        entry = &bat_priv->bla.bcast_duplist[curr];
        entry->crc = crc;
        entry->entrytime = jiffies;
-       memcpy(entry->orig, bcast_packet->orig, ETH_ALEN);
+       ether_addr_copy(entry->orig, bcast_packet->orig);
        bat_priv->bla.bcast_duplist_curr = curr;
 
 out:
@@ -1458,7 +1458,7 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
                if (is_multicast_ether_addr(ethhdr->h_dest) && is_bcast)
                        goto handled;
 
-       memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
+       ether_addr_copy(search_claim.addr, ethhdr->h_source);
        search_claim.vid = vid;
        claim = batadv_claim_hash_find(bat_priv, &search_claim);
 
@@ -1547,9 +1547,6 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
        if (!atomic_read(&bat_priv->bridge_loop_avoidance))
                goto allow;
 
-       /* in VLAN case, the mac header might not be set. */
-       skb_reset_mac_header(skb);
-
        if (batadv_bla_process_claim(bat_priv, primary_if, skb))
                goto handled;
 
@@ -1560,7 +1557,7 @@ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
                if (is_multicast_ether_addr(ethhdr->h_dest))
                        goto handled;
 
-       memcpy(search_claim.addr, ethhdr->h_source, ETH_ALEN);
+       ether_addr_copy(search_claim.addr, ethhdr->h_source);
        search_claim.vid = vid;
 
        claim = batadv_claim_hash_find(bat_priv, &search_claim);
index edee50411892f9ddaafd44a63163e24e79a3ae75..b25fd64d727b0d6e8227671f860b133095df5100 100644 (file)
@@ -277,7 +277,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
        /* if this entry is already known, just update it */
        if (dat_entry) {
                if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
-                       memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
+                       ether_addr_copy(dat_entry->mac_addr, mac_addr);
                dat_entry->last_update = jiffies;
                batadv_dbg(BATADV_DBG_DAT, bat_priv,
                           "Entry updated: %pI4 %pM (vid: %d)\n",
@@ -292,7 +292,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
 
        dat_entry->ip = ip;
        dat_entry->vid = vid;
-       memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
+       ether_addr_copy(dat_entry->mac_addr, mac_addr);
        dat_entry->last_update = jiffies;
        atomic_set(&dat_entry->refcount, 2);
 
@@ -1027,6 +1027,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
        if (!skb_new)
                goto out;
 
+       /* the rest of the TX path assumes that the mac_header offset pointing
+        * to the inner Ethernet header has been set, therefore reset it now.
+        */
+       skb_reset_mac_header(skb_new);
+
        if (vid & BATADV_VLAN_HAS_TAG)
                skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
                                          vid & VLAN_VID_MASK);
index ac9be9b67a252a0a8b23088e08bdbbd49b9981b0..d76e1d06c5b53019230aee93ba39730ab60987e1 100644 (file)
@@ -25,6 +25,9 @@
 
 #include <linux/if_arp.h>
 
+/**
+ * BATADV_DAT_ADDR_MAX - maximum address value in the DHT space
+ */
 #define BATADV_DAT_ADDR_MAX ((batadv_dat_addr_t)~(batadv_dat_addr_t)0)
 
 void batadv_dat_status_update(struct net_device *net_dev);
index 88df9b1d552de529b20cb699c303ec76034dee12..bcc4bea632fa69ead6567e016f2f265840f7968b 100644 (file)
@@ -449,8 +449,8 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
        frag_header.reserved = 0;
        frag_header.no = 0;
        frag_header.total_size = htons(skb->len);
-       memcpy(frag_header.orig, primary_if->net_dev->dev_addr, ETH_ALEN);
-       memcpy(frag_header.dest, orig_node->orig, ETH_ALEN);
+       ether_addr_copy(frag_header.orig, primary_if->net_dev->dev_addr);
+       ether_addr_copy(frag_header.dest, orig_node->orig);
 
        /* Eat and send fragments from the tail of skb */
        while (skb->len > max_fragment_size) {
index 55cf2260d295b6f4002d438ed34b52382ed7eeea..c835e137423bb9ec70b98b5130d5a33c12f9b139 100644 (file)
@@ -389,8 +389,6 @@ out:
                batadv_neigh_ifinfo_free_ref(router_gw_tq);
        if (router_orig_tq)
                batadv_neigh_ifinfo_free_ref(router_orig_tq);
-
-       return;
 }
 
 /**
@@ -680,7 +678,7 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
        if (!pskb_may_pull(skb, *header_len + ETH_HLEN))
                return BATADV_DHCP_NO;
 
-       ethhdr = (struct ethhdr *)skb->data;
+       ethhdr = eth_hdr(skb);
        proto = ethhdr->h_proto;
        *header_len += ETH_HLEN;
 
@@ -689,7 +687,7 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
                if (!pskb_may_pull(skb, *header_len + VLAN_HLEN))
                        return BATADV_DHCP_NO;
 
-               vhdr = (struct vlan_ethhdr *)skb->data;
+               vhdr = vlan_eth_hdr(skb);
                proto = vhdr->h_vlan_encapsulated_proto;
                *header_len += VLAN_HLEN;
        }
@@ -728,7 +726,7 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
                return BATADV_DHCP_NO;
 
        /* skb->data might have been reallocated by pskb_may_pull() */
-       ethhdr = (struct ethhdr *)skb->data;
+       ethhdr = eth_hdr(skb);
        if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
                ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
 
@@ -765,7 +763,7 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len,
                if (*p != ETH_ALEN)
                        return BATADV_DHCP_NO;
 
-               memcpy(chaddr, skb->data + chaddr_offset, ETH_ALEN);
+               ether_addr_copy(chaddr, skb->data + chaddr_offset);
        }
 
        return ret;
index 3d417d3641c6d83a4ecb4f87bdf48d4f26d48242..b851cc58085330acbab02848fedf3cb01751a060 100644 (file)
@@ -241,7 +241,7 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
 {
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        const struct batadv_hard_iface *hard_iface;
-       int min_mtu = ETH_DATA_LEN;
+       int min_mtu = INT_MAX;
 
        rcu_read_lock();
        list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
@@ -256,8 +256,6 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
        }
        rcu_read_unlock();
 
-       atomic_set(&bat_priv->packet_size_max, min_mtu);
-
        if (atomic_read(&bat_priv->fragmentation) == 0)
                goto out;
 
@@ -268,13 +266,21 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface)
        min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE);
        min_mtu -= sizeof(struct batadv_frag_packet);
        min_mtu *= BATADV_FRAG_MAX_FRAGMENTS;
-       atomic_set(&bat_priv->packet_size_max, min_mtu);
-
-       /* with fragmentation enabled we can fragment external packets easily */
-       min_mtu = min_t(int, min_mtu, ETH_DATA_LEN);
 
 out:
-       return min_mtu - batadv_max_header_len();
+       /* report to the other components the maximum amount of bytes that
+        * batman-adv can send over the wire (without considering the payload
+        * overhead). For example, this value is used by TT to compute the
+        * maximum local table table size
+        */
+       atomic_set(&bat_priv->packet_size_max, min_mtu);
+
+       /* the real soft-interface MTU is computed by removing the payload
+        * overhead from the maximum amount of bytes that was just computed.
+        *
+        * However batman-adv does not support MTUs bigger than ETH_DATA_LEN
+        */
+       return min_t(int, min_mtu - batadv_max_header_len(), ETH_DATA_LEN);
 }
 
 /* adjusts the MTU if a new interface with a smaller MTU appeared. */
index abb9d6e0388be65a20e0c19d377f7bdda47ea1da..161ef8f17d2ef273615bfaad9e9c728fbe754acc 100644 (file)
@@ -158,6 +158,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
        struct batadv_orig_node *orig_node = NULL;
        struct batadv_neigh_node *neigh_node = NULL;
        size_t packet_len = sizeof(struct batadv_icmp_packet);
+       uint8_t *addr;
 
        if (len < sizeof(struct batadv_icmp_header)) {
                batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
@@ -227,10 +228,10 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
                        goto dst_unreach;
 
                icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmp_header;
-               if (packet_len == sizeof(*icmp_packet_rr))
-                       memcpy(icmp_packet_rr->rr,
-                              neigh_node->if_incoming->net_dev->dev_addr,
-                              ETH_ALEN);
+               if (packet_len == sizeof(*icmp_packet_rr)) {
+                       addr = neigh_node->if_incoming->net_dev->dev_addr;
+                       ether_addr_copy(icmp_packet_rr->rr[0], addr);
+               }
 
                break;
        default:
@@ -250,7 +251,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff,
                goto free_skb;
        }
 
-       memcpy(icmp_header->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(icmp_header->orig, primary_if->net_dev->dev_addr);
 
        batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
        goto out;
index 66ae135b9f273abdea581f2fc8eaa5ecb74254f0..d1183e882167c3cd75aa842c94c612818e250d30 100644 (file)
@@ -34,6 +34,7 @@
 #include "gateway_client.h"
 #include "bridge_loop_avoidance.h"
 #include "distributed-arp-table.h"
+#include "multicast.h"
 #include "gateway_common.h"
 #include "hash.h"
 #include "bat_algo.h"
@@ -110,6 +111,9 @@ int batadv_mesh_init(struct net_device *soft_iface)
        spin_lock_init(&bat_priv->tt.last_changeset_lock);
        spin_lock_init(&bat_priv->tt.commit_lock);
        spin_lock_init(&bat_priv->gw.list_lock);
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       spin_lock_init(&bat_priv->mcast.want_lists_lock);
+#endif
        spin_lock_init(&bat_priv->tvlv.container_list_lock);
        spin_lock_init(&bat_priv->tvlv.handler_list_lock);
        spin_lock_init(&bat_priv->softif_vlan_list_lock);
@@ -117,9 +121,17 @@ int batadv_mesh_init(struct net_device *soft_iface)
        INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
        INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
        INIT_HLIST_HEAD(&bat_priv->gw.list);
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       INIT_HLIST_HEAD(&bat_priv->mcast.want_all_unsnoopables_list);
+       INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv4_list);
+       INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list);
+#endif
        INIT_LIST_HEAD(&bat_priv->tt.changes_list);
        INIT_LIST_HEAD(&bat_priv->tt.req_list);
        INIT_LIST_HEAD(&bat_priv->tt.roam_list);
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       INIT_HLIST_HEAD(&bat_priv->mcast.mla_list);
+#endif
        INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
        INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
        INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
@@ -145,6 +157,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
                goto err;
 
        batadv_gw_init(bat_priv);
+       batadv_mcast_init(bat_priv);
 
        atomic_set(&bat_priv->gw.reselect, 0);
        atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE);
@@ -169,6 +182,8 @@ void batadv_mesh_free(struct net_device *soft_iface)
        batadv_dat_free(bat_priv);
        batadv_bla_free(bat_priv);
 
+       batadv_mcast_free(bat_priv);
+
        /* Free the TT and the originator tables only after having terminated
         * all the other depending components which may use these structures for
         * their purposes.
@@ -1133,8 +1148,8 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src,
        unicast_tvlv_packet->reserved = 0;
        unicast_tvlv_packet->tvlv_len = htons(tvlv_len);
        unicast_tvlv_packet->align = 0;
-       memcpy(unicast_tvlv_packet->src, src, ETH_ALEN);
-       memcpy(unicast_tvlv_packet->dst, dst, ETH_ALEN);
+       ether_addr_copy(unicast_tvlv_packet->src, src);
+       ether_addr_copy(unicast_tvlv_packet->dst, dst);
 
        tvlv_buff = (unsigned char *)(unicast_tvlv_packet + 1);
        tvlv_hdr = (struct batadv_tvlv_hdr *)tvlv_buff;
index 9374f1a51348514d7b5af1eb6767128bac4d744d..770dc890ceefdb712f254b378c825cbeab255742 100644 (file)
@@ -24,7 +24,7 @@
 #define BATADV_DRIVER_DEVICE "batman-adv"
 
 #ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2014.1.0"
+#define BATADV_SOURCE_VERSION "2014.2.0"
 #endif
 
 /* B.A.T.M.A.N. parameters */
@@ -176,6 +176,8 @@ enum batadv_uev_type {
 #include <linux/percpu.h>
 #include <linux/slab.h>
 #include <net/sock.h>          /* struct sock */
+#include <net/addrconf.h>      /* ipv6 address stuff */
+#include <linux/ip.h>
 #include <net/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/seq_file.h>
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
new file mode 100644 (file)
index 0000000..8c7ca81
--- /dev/null
@@ -0,0 +1,748 @@
+/* Copyright (C) 2014 B.A.T.M.A.N. contributors:
+ *
+ * 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
+ * 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"
+#include "multicast.h"
+#include "originator.h"
+#include "hard-interface.h"
+#include "translation-table.h"
+#include "multicast.h"
+
+/**
+ * batadv_mcast_mla_softif_get - get softif multicast listeners
+ * @dev: the device to collect multicast addresses from
+ * @mcast_list: a list to put found addresses into
+ *
+ * Collect multicast addresses of the local multicast listeners
+ * on the given soft interface, dev, in the given mcast_list.
+ *
+ * Returns -ENOMEM on memory allocation error or the number of
+ * items added to the mcast_list otherwise.
+ */
+static int batadv_mcast_mla_softif_get(struct net_device *dev,
+                                      struct hlist_head *mcast_list)
+{
+       struct netdev_hw_addr *mc_list_entry;
+       struct batadv_hw_addr *new;
+       int ret = 0;
+
+       netif_addr_lock_bh(dev);
+       netdev_for_each_mc_addr(mc_list_entry, dev) {
+               new = kmalloc(sizeof(*new), GFP_ATOMIC);
+               if (!new) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               ether_addr_copy(new->addr, mc_list_entry->addr);
+               hlist_add_head(&new->list, mcast_list);
+               ret++;
+       }
+       netif_addr_unlock_bh(dev);
+
+       return ret;
+}
+
+/**
+ * batadv_mcast_mla_is_duplicate - check whether an address is in a list
+ * @mcast_addr: the multicast address to check
+ * @mcast_list: the list with multicast addresses to search in
+ *
+ * Returns true if the given address is already in the given list.
+ * Otherwise returns false.
+ */
+static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr,
+                                         struct hlist_head *mcast_list)
+{
+       struct batadv_hw_addr *mcast_entry;
+
+       hlist_for_each_entry(mcast_entry, mcast_list, list)
+               if (batadv_compare_eth(mcast_entry->addr, mcast_addr))
+                       return true;
+
+       return false;
+}
+
+/**
+ * batadv_mcast_mla_list_free - free a list of multicast addresses
+ * @mcast_list: the list to free
+ *
+ * Removes and frees all items in the given mcast_list.
+ */
+static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list)
+{
+       struct batadv_hw_addr *mcast_entry;
+       struct hlist_node *tmp;
+
+       hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
+               hlist_del(&mcast_entry->list);
+               kfree(mcast_entry);
+       }
+}
+
+/**
+ * batadv_mcast_mla_tt_retract - clean up multicast listener announcements
+ * @bat_priv: the bat priv with all the soft interface information
+ * @mcast_list: a list of addresses which should _not_ be removed
+ *
+ * Retracts the announcement of any multicast listener from the
+ * translation table except the ones listed in the given mcast_list.
+ *
+ * If mcast_list is NULL then all are retracted.
+ */
+static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv,
+                                       struct hlist_head *mcast_list)
+{
+       struct batadv_hw_addr *mcast_entry;
+       struct hlist_node *tmp;
+
+       hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list,
+                                 list) {
+               if (mcast_list &&
+                   batadv_mcast_mla_is_duplicate(mcast_entry->addr,
+                                                 mcast_list))
+                       continue;
+
+               batadv_tt_local_remove(bat_priv, mcast_entry->addr,
+                                      BATADV_NO_FLAGS,
+                                      "mcast TT outdated", false);
+
+               hlist_del(&mcast_entry->list);
+               kfree(mcast_entry);
+       }
+}
+
+/**
+ * batadv_mcast_mla_tt_add - add multicast listener announcements
+ * @bat_priv: the bat priv with all the soft interface information
+ * @mcast_list: a list of addresses which are going to get added
+ *
+ * Adds multicast listener announcements from the given mcast_list to the
+ * translation table if they have not been added yet.
+ */
+static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
+                                   struct hlist_head *mcast_list)
+{
+       struct batadv_hw_addr *mcast_entry;
+       struct hlist_node *tmp;
+
+       if (!mcast_list)
+               return;
+
+       hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) {
+               if (batadv_mcast_mla_is_duplicate(mcast_entry->addr,
+                                                 &bat_priv->mcast.mla_list))
+                       continue;
+
+               if (!batadv_tt_local_add(bat_priv->soft_iface,
+                                        mcast_entry->addr, BATADV_NO_FLAGS,
+                                        BATADV_NULL_IFINDEX, BATADV_NO_MARK))
+                       continue;
+
+               hlist_del(&mcast_entry->list);
+               hlist_add_head(&mcast_entry->list, &bat_priv->mcast.mla_list);
+       }
+}
+
+/**
+ * batadv_mcast_has_bridge - check whether the soft-iface is bridged
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Checks whether there is a bridge on top of our soft interface. Returns
+ * true if so, false otherwise.
+ */
+static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
+{
+       struct net_device *upper = bat_priv->soft_iface;
+
+       rcu_read_lock();
+       do {
+               upper = netdev_master_upper_dev_get_rcu(upper);
+       } while (upper && !(upper->priv_flags & IFF_EBRIDGE));
+       rcu_read_unlock();
+
+       return upper;
+}
+
+/**
+ * batadv_mcast_mla_tvlv_update - update multicast tvlv
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Updates the own multicast tvlv with our current multicast related settings,
+ * capabilities and inabilities.
+ *
+ * Returns true if the tvlv container is registered afterwards. Otherwise
+ * returns false.
+ */
+static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv)
+{
+       struct batadv_tvlv_mcast_data mcast_data;
+
+       mcast_data.flags = BATADV_NO_FLAGS;
+       memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
+
+       /* Avoid attaching MLAs, if there is a bridge on top of our soft
+        * interface, we don't support that yet (TODO)
+        */
+       if (batadv_mcast_has_bridge(bat_priv)) {
+               if (bat_priv->mcast.enabled) {
+                       batadv_tvlv_container_unregister(bat_priv,
+                                                        BATADV_TVLV_MCAST, 1);
+                       bat_priv->mcast.enabled = false;
+               }
+
+               return false;
+       }
+
+       if (!bat_priv->mcast.enabled ||
+           mcast_data.flags != bat_priv->mcast.flags) {
+               batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
+                                              &mcast_data, sizeof(mcast_data));
+               bat_priv->mcast.flags = mcast_data.flags;
+               bat_priv->mcast.enabled = true;
+       }
+
+       return true;
+}
+
+/**
+ * batadv_mcast_mla_update - update the own MLAs
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Updates the own multicast listener announcements in the translation
+ * table as well as the own, announced multicast tvlv container.
+ */
+void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
+{
+       struct net_device *soft_iface = bat_priv->soft_iface;
+       struct hlist_head mcast_list = HLIST_HEAD_INIT;
+       int ret;
+
+       if (!batadv_mcast_mla_tvlv_update(bat_priv))
+               goto update;
+
+       ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list);
+       if (ret < 0)
+               goto out;
+
+update:
+       batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
+       batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
+
+out:
+       batadv_mcast_mla_list_free(&mcast_list);
+}
+
+/**
+ * batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the IPv4 packet to check
+ * @is_unsnoopable: stores whether the destination is snoopable
+ *
+ * Checks whether the given IPv4 packet has the potential to be forwarded with a
+ * mode more optimal than classic flooding.
+ *
+ * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM in case of
+ * memory allocation failure.
+ */
+static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
+                                            struct sk_buff *skb,
+                                            bool *is_unsnoopable)
+{
+       struct iphdr *iphdr;
+
+       /* We might fail due to out-of-memory -> drop it */
+       if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
+               return -ENOMEM;
+
+       iphdr = ip_hdr(skb);
+
+       /* TODO: Implement Multicast Router Discovery (RFC4286),
+        * then allow scope > link local, too
+        */
+       if (!ipv4_is_local_multicast(iphdr->daddr))
+               return -EINVAL;
+
+       /* link-local multicast listeners behind a bridge are
+        * not snoopable (see RFC4541, section 2.1.2.2)
+        */
+       *is_unsnoopable = true;
+
+       return 0;
+}
+
+/**
+ * batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the IPv6 packet to check
+ * @is_unsnoopable: stores whether the destination is snoopable
+ *
+ * Checks whether the given IPv6 packet has the potential to be forwarded with a
+ * mode more optimal than classic flooding.
+ *
+ * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out
+ * of memory.
+ */
+static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
+                                            struct sk_buff *skb,
+                                            bool *is_unsnoopable)
+{
+       struct ipv6hdr *ip6hdr;
+
+       /* We might fail due to out-of-memory -> drop it */
+       if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
+               return -ENOMEM;
+
+       ip6hdr = ipv6_hdr(skb);
+
+       /* TODO: Implement Multicast Router Discovery (RFC4286),
+        * then allow scope > link local, too
+        */
+       if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL)
+               return -EINVAL;
+
+       /* link-local-all-nodes multicast listeners behind a bridge are
+        * not snoopable (see RFC4541, section 3, paragraph 3)
+        */
+       if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
+               *is_unsnoopable = true;
+
+       return 0;
+}
+
+/**
+ * batadv_mcast_forw_mode_check - check for optimized forwarding potential
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the multicast frame to check
+ * @is_unsnoopable: stores whether the destination is snoopable
+ *
+ * Checks whether the given multicast ethernet frame has the potential to be
+ * forwarded with a mode more optimal than classic flooding.
+ *
+ * If so then returns 0. Otherwise -EINVAL is returned or -ENOMEM if we are out
+ * of memory.
+ */
+static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
+                                       struct sk_buff *skb,
+                                       bool *is_unsnoopable)
+{
+       struct ethhdr *ethhdr = eth_hdr(skb);
+
+       if (!atomic_read(&bat_priv->multicast_mode))
+               return -EINVAL;
+
+       if (atomic_read(&bat_priv->mcast.num_disabled))
+               return -EINVAL;
+
+       switch (ntohs(ethhdr->h_proto)) {
+       case ETH_P_IP:
+               return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
+                                                        is_unsnoopable);
+       case ETH_P_IPV6:
+               return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
+                                                        is_unsnoopable);
+       default:
+               return -EINVAL;
+       }
+}
+
+/**
+ * batadv_mcast_want_all_ip_count - count nodes with unspecific mcast interest
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: ethernet header of a packet
+ *
+ * Returns the number of nodes which want all IPv4 multicast traffic if the
+ * given ethhdr is from an IPv4 packet or the number of nodes which want all
+ * IPv6 traffic if it matches an IPv6 packet.
+ */
+static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
+                                              struct ethhdr *ethhdr)
+{
+       switch (ntohs(ethhdr->h_proto)) {
+       case ETH_P_IP:
+               return atomic_read(&bat_priv->mcast.num_want_all_ipv4);
+       case ETH_P_IPV6:
+               return atomic_read(&bat_priv->mcast.num_want_all_ipv6);
+       default:
+               /* we shouldn't be here... */
+               return 0;
+       }
+}
+
+/**
+ * batadv_mcast_forw_tt_node_get - get a multicast tt node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: the ether header containing the multicast destination
+ *
+ * Returns an orig_node matching the multicast address provided by ethhdr
+ * via a translation table lookup. This increases the returned nodes refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
+                             struct ethhdr *ethhdr)
+{
+       return batadv_transtable_search(bat_priv, ethhdr->h_source,
+                                       ethhdr->h_dest, BATADV_NO_FLAGS);
+}
+
+/**
+ * batadv_mcast_want_forw_ipv4_node_get - get a node with an ipv4 flag
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 flag set and
+ * increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_ipv4_node_get(struct batadv_priv *bat_priv)
+{
+       struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_orig_node,
+                                &bat_priv->mcast.want_all_ipv4_list,
+                                mcast_want_all_ipv4_node) {
+               if (!atomic_inc_not_zero(&orig_node->refcount))
+                       continue;
+
+               orig_node = tmp_orig_node;
+               break;
+       }
+       rcu_read_unlock();
+
+       return orig_node;
+}
+
+/**
+ * batadv_mcast_want_forw_ipv6_node_get - get a node with an ipv6 flag
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV6 flag set
+ * and increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_ipv6_node_get(struct batadv_priv *bat_priv)
+{
+       struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_orig_node,
+                                &bat_priv->mcast.want_all_ipv6_list,
+                                mcast_want_all_ipv6_node) {
+               if (!atomic_inc_not_zero(&orig_node->refcount))
+                       continue;
+
+               orig_node = tmp_orig_node;
+               break;
+       }
+       rcu_read_unlock();
+
+       return orig_node;
+}
+
+/**
+ * batadv_mcast_want_forw_ip_node_get - get a node with an ipv4/ipv6 flag
+ * @bat_priv: the bat priv with all the soft interface information
+ * @ethhdr: an ethernet header to determine the protocol family from
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_IPV4 or
+ * BATADV_MCAST_WANT_ALL_IPV6 flag, depending on the provided ethhdr, set and
+ * increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_ip_node_get(struct batadv_priv *bat_priv,
+                             struct ethhdr *ethhdr)
+{
+       switch (ntohs(ethhdr->h_proto)) {
+       case ETH_P_IP:
+               return batadv_mcast_forw_ipv4_node_get(bat_priv);
+       case ETH_P_IPV6:
+               return batadv_mcast_forw_ipv6_node_get(bat_priv);
+       default:
+               /* we shouldn't be here... */
+               return NULL;
+       }
+}
+
+/**
+ * batadv_mcast_want_forw_unsnoop_node_get - get a node with an unsnoopable flag
+ * @bat_priv: the bat priv with all the soft interface information
+ *
+ * Returns an orig_node which has the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag
+ * set and increases its refcount.
+ */
+static struct batadv_orig_node *
+batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv)
+{
+       struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_orig_node,
+                                &bat_priv->mcast.want_all_unsnoopables_list,
+                                mcast_want_all_unsnoopables_node) {
+               if (!atomic_inc_not_zero(&orig_node->refcount))
+                       continue;
+
+               orig_node = tmp_orig_node;
+               break;
+       }
+       rcu_read_unlock();
+
+       return orig_node;
+}
+
+/**
+ * batadv_mcast_forw_mode - check on how to forward a multicast packet
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: The multicast packet to check
+ * @orig: an originator to be set to forward the skb to
+ *
+ * Returns the forwarding mode as enum batadv_forw_mode and in case of
+ * BATADV_FORW_SINGLE set the orig to the single originator the skb
+ * should be forwarded to.
+ */
+enum batadv_forw_mode
+batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                      struct batadv_orig_node **orig)
+{
+       int ret, tt_count, ip_count, unsnoop_count, total_count;
+       bool is_unsnoopable = false;
+       struct ethhdr *ethhdr;
+
+       ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable);
+       if (ret == -ENOMEM)
+               return BATADV_FORW_NONE;
+       else if (ret < 0)
+               return BATADV_FORW_ALL;
+
+       ethhdr = eth_hdr(skb);
+
+       tt_count = batadv_tt_global_hash_count(bat_priv, ethhdr->h_dest,
+                                              BATADV_NO_FLAGS);
+       ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
+       unsnoop_count = !is_unsnoopable ? 0 :
+                       atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
+
+       total_count = tt_count + ip_count + unsnoop_count;
+
+       switch (total_count) {
+       case 1:
+               if (tt_count)
+                       *orig = batadv_mcast_forw_tt_node_get(bat_priv, ethhdr);
+               else if (ip_count)
+                       *orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr);
+               else if (unsnoop_count)
+                       *orig = batadv_mcast_forw_unsnoop_node_get(bat_priv);
+
+               if (*orig)
+                       return BATADV_FORW_SINGLE;
+
+               /* fall through */
+       case 0:
+               return BATADV_FORW_NONE;
+       default:
+               return BATADV_FORW_ALL;
+       }
+}
+
+/**
+ * batadv_mcast_want_unsnoop_update - update unsnoop counter and list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the orig_node which multicast state might have changed of
+ * @mcast_flags: flags indicating the new multicast state
+ *
+ * If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator,
+ * orig, has toggled then this method updates counter and list accordingly.
+ */
+static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
+                                            struct batadv_orig_node *orig,
+                                            uint8_t mcast_flags)
+{
+       /* switched from flag unset to set */
+       if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
+           !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) {
+               atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_add_head_rcu(&orig->mcast_want_all_unsnoopables_node,
+                                  &bat_priv->mcast.want_all_unsnoopables_list);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       /* switched from flag set to unset */
+       } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) &&
+                  orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) {
+               atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_del_rcu(&orig->mcast_want_all_unsnoopables_node);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       }
+}
+
+/**
+ * batadv_mcast_want_ipv4_update - update want-all-ipv4 counter and list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the orig_node which multicast state might have changed of
+ * @mcast_flags: flags indicating the new multicast state
+ *
+ * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has
+ * toggled then this method updates counter and list accordingly.
+ */
+static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
+                                         struct batadv_orig_node *orig,
+                                         uint8_t mcast_flags)
+{
+       /* switched from flag unset to set */
+       if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 &&
+           !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) {
+               atomic_inc(&bat_priv->mcast.num_want_all_ipv4);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_add_head_rcu(&orig->mcast_want_all_ipv4_node,
+                                  &bat_priv->mcast.want_all_ipv4_list);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       /* switched from flag set to unset */
+       } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) &&
+                  orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) {
+               atomic_dec(&bat_priv->mcast.num_want_all_ipv4);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_del_rcu(&orig->mcast_want_all_ipv4_node);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       }
+}
+
+/**
+ * batadv_mcast_want_ipv6_update - update want-all-ipv6 counter and list
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the orig_node which multicast state might have changed of
+ * @mcast_flags: flags indicating the new multicast state
+ *
+ * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has
+ * toggled then this method updates counter and list accordingly.
+ */
+static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
+                                         struct batadv_orig_node *orig,
+                                         uint8_t mcast_flags)
+{
+       /* switched from flag unset to set */
+       if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 &&
+           !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) {
+               atomic_inc(&bat_priv->mcast.num_want_all_ipv6);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_add_head_rcu(&orig->mcast_want_all_ipv6_node,
+                                  &bat_priv->mcast.want_all_ipv6_list);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       /* switched from flag set to unset */
+       } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) &&
+                  orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) {
+               atomic_dec(&bat_priv->mcast.num_want_all_ipv6);
+
+               spin_lock_bh(&bat_priv->mcast.want_lists_lock);
+               hlist_del_rcu(&orig->mcast_want_all_ipv6_node);
+               spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
+       }
+}
+
+/**
+ * batadv_mcast_tvlv_ogm_handler_v1 - process incoming multicast tvlv container
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig: the orig_node of the ogm
+ * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
+ * @tvlv_value: tvlv buffer containing the multicast data
+ * @tvlv_value_len: tvlv buffer length
+ */
+static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
+                                            struct batadv_orig_node *orig,
+                                            uint8_t flags,
+                                            void *tvlv_value,
+                                            uint16_t tvlv_value_len)
+{
+       bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
+       uint8_t mcast_flags = BATADV_NO_FLAGS;
+       bool orig_initialized;
+
+       orig_initialized = orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST;
+
+       /* If mcast support is turned on decrease the disabled mcast node
+        * counter only if we had increased it for this node before. If this
+        * is a completely new orig_node no need to decrease the counter.
+        */
+       if (orig_mcast_enabled &&
+           !(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) {
+               if (orig_initialized)
+                       atomic_dec(&bat_priv->mcast.num_disabled);
+               orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST;
+       /* If mcast support is being switched off increase the disabled
+        * mcast node counter.
+        */
+       } else if (!orig_mcast_enabled &&
+                  orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) {
+               atomic_inc(&bat_priv->mcast.num_disabled);
+               orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST;
+       }
+
+       orig->capa_initialized |= BATADV_ORIG_CAPA_HAS_MCAST;
+
+       if (orig_mcast_enabled && tvlv_value &&
+           (tvlv_value_len >= sizeof(mcast_flags)))
+               mcast_flags = *(uint8_t *)tvlv_value;
+
+       batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags);
+       batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags);
+       batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
+
+       orig->mcast_flags = mcast_flags;
+}
+
+/**
+ * batadv_mcast_init - initialize the multicast optimizations structures
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_mcast_init(struct batadv_priv *bat_priv)
+{
+       batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1,
+                                    NULL, BATADV_TVLV_MCAST, 1,
+                                    BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
+}
+
+/**
+ * batadv_mcast_free - free the multicast optimizations structures
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+void batadv_mcast_free(struct batadv_priv *bat_priv)
+{
+       batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
+       batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
+
+       batadv_mcast_mla_tt_retract(bat_priv, NULL);
+}
+
+/**
+ * batadv_mcast_purge_orig - reset originator global mcast state modifications
+ * @orig: the originator which is going to get purged
+ */
+void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
+{
+       struct batadv_priv *bat_priv = orig->bat_priv;
+
+       if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST))
+               atomic_dec(&bat_priv->mcast.num_disabled);
+
+       batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
+       batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
+       batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
+}
diff --git a/net/batman-adv/multicast.h b/net/batman-adv/multicast.h
new file mode 100644 (file)
index 0000000..73b5d45
--- /dev/null
@@ -0,0 +1,80 @@
+/* Copyright (C) 2014 B.A.T.M.A.N. contributors:
+ *
+ * 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
+ * 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 _NET_BATMAN_ADV_MULTICAST_H_
+#define _NET_BATMAN_ADV_MULTICAST_H_
+
+/**
+ * batadv_forw_mode - the way a packet should be forwarded as
+ * @BATADV_FORW_ALL: forward the packet to all nodes (currently via classic
+ *  flooding)
+ * @BATADV_FORW_SINGLE: forward the packet to a single node (currently via the
+ *  BATMAN unicast routing protocol)
+ * @BATADV_FORW_NONE: don't forward, drop it
+ */
+enum batadv_forw_mode {
+       BATADV_FORW_ALL,
+       BATADV_FORW_SINGLE,
+       BATADV_FORW_NONE,
+};
+
+#ifdef CONFIG_BATMAN_ADV_MCAST
+
+void batadv_mcast_mla_update(struct batadv_priv *bat_priv);
+
+enum batadv_forw_mode
+batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                      struct batadv_orig_node **mcast_single_orig);
+
+void batadv_mcast_init(struct batadv_priv *bat_priv);
+
+void batadv_mcast_free(struct batadv_priv *bat_priv);
+
+void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node);
+
+#else
+
+static inline void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
+{
+       return;
+}
+
+static inline enum batadv_forw_mode
+batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                      struct batadv_orig_node **mcast_single_orig)
+{
+       return BATADV_FORW_ALL;
+}
+
+static inline int batadv_mcast_init(struct batadv_priv *bat_priv)
+{
+       return 0;
+}
+
+static inline void batadv_mcast_free(struct batadv_priv *bat_priv)
+{
+       return;
+}
+
+static inline void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node)
+{
+       return;
+}
+
+#endif /* CONFIG_BATMAN_ADV_MCAST */
+
+#endif /* _NET_BATMAN_ADV_MULTICAST_H_ */
index f1b604d88dc3c2124c86083f36e5bafaad50b9bc..a9546fe541ebb0ff8905fd3fe82d48e48302ce9e 100644 (file)
@@ -819,7 +819,7 @@ static struct batadv_nc_node
 
        /* Initialize nc_node */
        INIT_LIST_HEAD(&nc_node->list);
-       memcpy(nc_node->addr, orig_node->orig, ETH_ALEN);
+       ether_addr_copy(nc_node->addr, orig_node->orig);
        nc_node->orig_node = orig_neigh_node;
        atomic_set(&nc_node->refcount, 2);
 
@@ -941,8 +941,8 @@ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv,
        spin_lock_init(&nc_path->packet_list_lock);
        atomic_set(&nc_path->refcount, 2);
        nc_path->last_valid = jiffies;
-       memcpy(nc_path->next_hop, dst, ETH_ALEN);
-       memcpy(nc_path->prev_hop, src, ETH_ALEN);
+       ether_addr_copy(nc_path->next_hop, dst);
+       ether_addr_copy(nc_path->prev_hop, src);
 
        batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_path %pM -> %pM\n",
                   nc_path->prev_hop,
@@ -1114,15 +1114,15 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
        coded_packet->ttl = packet1->ttl;
 
        /* Info about first unicast packet */
-       memcpy(coded_packet->first_source, first_source, ETH_ALEN);
-       memcpy(coded_packet->first_orig_dest, packet1->dest, ETH_ALEN);
+       ether_addr_copy(coded_packet->first_source, first_source);
+       ether_addr_copy(coded_packet->first_orig_dest, packet1->dest);
        coded_packet->first_crc = packet_id1;
        coded_packet->first_ttvn = packet1->ttvn;
 
        /* Info about second unicast packet */
-       memcpy(coded_packet->second_dest, second_dest, ETH_ALEN);
-       memcpy(coded_packet->second_source, second_source, ETH_ALEN);
-       memcpy(coded_packet->second_orig_dest, packet2->dest, ETH_ALEN);
+       ether_addr_copy(coded_packet->second_dest, second_dest);
+       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;
        coded_packet->second_ttl = packet2->ttl;
        coded_packet->second_ttvn = packet2->ttvn;
@@ -1349,8 +1349,8 @@ static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv,
 
        /* Set the mac header as if we actually sent the packet uncoded */
        ethhdr = eth_hdr(skb);
-       memcpy(ethhdr->h_source, ethhdr->h_dest, ETH_ALEN);
-       memcpy(ethhdr->h_dest, eth_dst_new, ETH_ALEN);
+       ether_addr_copy(ethhdr->h_source, ethhdr->h_dest);
+       ether_addr_copy(ethhdr->h_dest, eth_dst_new);
 
        /* Set data pointer to MAC header to mimic packets from our tx path */
        skb_push(skb, ETH_HLEN);
@@ -1636,7 +1636,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
 
        /* Reconstruct original mac header */
        ethhdr = eth_hdr(skb);
-       memcpy(ethhdr, &ethhdr_tmp, sizeof(*ethhdr));
+       *ethhdr = ethhdr_tmp;
 
        /* Select the correct unicast header information based on the location
         * of our mac address in the coded_packet header
@@ -1646,7 +1646,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
                 * so the Ethernet address must be copied to h_dest and
                 * pkt_type changed from PACKET_OTHERHOST to PACKET_HOST
                 */
-               memcpy(ethhdr->h_dest, coded_packet_tmp.second_dest, ETH_ALEN);
+               ether_addr_copy(ethhdr->h_dest, coded_packet_tmp.second_dest);
                skb->pkt_type = PACKET_HOST;
 
                orig_dest = coded_packet_tmp.second_orig_dest;
@@ -1682,7 +1682,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
        unicast_packet->packet_type = BATADV_UNICAST;
        unicast_packet->version = BATADV_COMPAT_VERSION;
        unicast_packet->ttl = ttl;
-       memcpy(unicast_packet->dest, orig_dest, ETH_ALEN);
+       ether_addr_copy(unicast_packet->dest, orig_dest);
        unicast_packet->ttvn = ttvn;
 
        batadv_nc_packet_free(nc_packet);
index 6df12a2e36052b7f8a07dea276565c362890863f..ffd9dfbd9b0e856e35e2ac6ea594739e8feb614d 100644 (file)
@@ -27,6 +27,7 @@
 #include "bridge_loop_avoidance.h"
 #include "network-coding.h"
 #include "fragmentation.h"
+#include "multicast.h"
 
 /* hash class keys */
 static struct lock_class_key batadv_orig_hash_lock_class_key;
@@ -446,7 +447,7 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
        INIT_HLIST_HEAD(&neigh_node->ifinfo_list);
        spin_lock_init(&neigh_node->ifinfo_lock);
 
-       memcpy(neigh_node->addr, neigh_addr, ETH_ALEN);
+       ether_addr_copy(neigh_node->addr, neigh_addr);
        neigh_node->if_incoming = hard_iface;
        neigh_node->orig_node = orig_node;
 
@@ -457,6 +458,42 @@ out:
        return neigh_node;
 }
 
+/**
+ * batadv_neigh_node_get - retrieve a neighbour from the list
+ * @orig_node: originator which the neighbour belongs to
+ * @hard_iface: the interface where this neighbour is connected to
+ * @addr: the address of the neighbour
+ *
+ * Looks for and possibly returns a neighbour belonging to this originator list
+ * which is connected through the provided hard interface.
+ * Returns NULL if the neighbour is not found.
+ */
+struct batadv_neigh_node *
+batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
+                     const struct batadv_hard_iface *hard_iface,
+                     const uint8_t *addr)
+{
+       struct batadv_neigh_node *tmp_neigh_node, *res = NULL;
+
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) {
+               if (!batadv_compare_eth(tmp_neigh_node->addr, addr))
+                       continue;
+
+               if (tmp_neigh_node->if_incoming != hard_iface)
+                       continue;
+
+               if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
+                       continue;
+
+               res = tmp_neigh_node;
+               break;
+       }
+       rcu_read_unlock();
+
+       return res;
+}
+
 /**
  * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object
  * @rcu: rcu pointer of the orig_ifinfo object
@@ -521,6 +558,8 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
        }
        spin_unlock_bh(&orig_node->neigh_list_lock);
 
+       batadv_mcast_purge_orig(orig_node);
+
        /* Free nc_nodes */
        batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
 
@@ -628,15 +667,17 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
        /* extra reference for return */
        atomic_set(&orig_node->refcount, 2);
 
-       orig_node->tt_initialised = false;
        orig_node->bat_priv = bat_priv;
-       memcpy(orig_node->orig, addr, ETH_ALEN);
+       ether_addr_copy(orig_node->orig, addr);
        batadv_dat_init_orig_node_addr(orig_node);
        atomic_set(&orig_node->last_ttvn, 0);
        orig_node->tt_buff = NULL;
        orig_node->tt_buff_len = 0;
        reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
        orig_node->bcast_seqno_reset = reset_time;
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       orig_node->mcast_flags = BATADV_NO_FLAGS;
+#endif
 
        /* create a vlan object for the "untagged" LAN */
        vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
index 37be290f63f6e603cb849e1484311389464682b3..db3a9ed734cb7c858c28d00e53250fd22d15f828 100644 (file)
@@ -29,6 +29,10 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node);
 struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
                                              const uint8_t *addr);
 struct batadv_neigh_node *
+batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
+                     const struct batadv_hard_iface *hard_iface,
+                     const uint8_t *addr);
+struct batadv_neigh_node *
 batadv_neigh_node_new(struct batadv_hard_iface *hard_iface,
                      const uint8_t *neigh_addr,
                      struct batadv_orig_node *orig_node);
index 0a381d1174c1fbb36a7c09173a004800d5d7d420..34e096d2dce1592dcb330daaf5b6c030de32cb93 100644 (file)
@@ -89,6 +89,19 @@ enum batadv_icmp_packettype {
        BATADV_PARAMETER_PROBLEM       = 12,
 };
 
+/**
+ * enum batadv_mcast_flags - flags for multicast capabilities and settings
+ * @BATADV_MCAST_WANT_ALL_UNSNOOPABLES: we want all packets destined for
+ *  224.0.0.0/24 or ff02::1
+ * @BATADV_MCAST_WANT_ALL_IPV4: we want all IPv4 multicast packets
+ * @BATADV_MCAST_WANT_ALL_IPV6: we want all IPv6 multicast packets
+ */
+enum batadv_mcast_flags {
+       BATADV_MCAST_WANT_ALL_UNSNOOPABLES      = BIT(0),
+       BATADV_MCAST_WANT_ALL_IPV4              = BIT(1),
+       BATADV_MCAST_WANT_ALL_IPV6              = BIT(2),
+};
+
 /* tt data subtypes */
 #define BATADV_TT_DATA_TYPE_MASK 0x0F
 
@@ -106,10 +119,30 @@ enum batadv_tt_data_flags {
        BATADV_TT_FULL_TABLE = BIT(4),
 };
 
-/* BATADV_TT_CLIENT flags.
- * Flags from BIT(0) to BIT(7) are sent on the wire, while flags from BIT(8) to
- * BIT(15) are used for local computation only.
- * Flags from BIT(4) to BIT(7) are kept in sync with the rest of the network.
+/**
+ * enum batadv_tt_client_flags - TT client specific flags
+ * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table
+ * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and the new
+ *  update telling its new real location has not been received/sent yet
+ * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi interface.
+ *  This information is used by the "AP Isolation" feature
+ * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This
+ *  information is used by the Extended Isolation feature
+ * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from the table
+ * @BATADV_TT_CLIENT_NEW: this client has been added to the local table but has
+ *  not been announced yet
+ * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it is kept
+ *  in the table for one more originator interval for consistency purposes
+ * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be part of
+ *  the network but no nnode has already announced it
+ *
+ * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire.
+ * Bits from 8 to 15 are called _local flags_ because they are used for local
+ * computations only.
+ *
+ * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with
+ * the other nodes in the network. To achieve this goal these flags are included
+ * in the TT CRC computation.
  */
 enum batadv_tt_client_flags {
        BATADV_TT_CLIENT_DEL     = BIT(0),
@@ -145,6 +178,7 @@ enum batadv_bla_claimframe {
  * @BATADV_TVLV_NC: network coding tvlv
  * @BATADV_TVLV_TT: translation table tvlv
  * @BATADV_TVLV_ROAM: roaming advertisement tvlv
+ * @BATADV_TVLV_MCAST: multicast capability tvlv
  */
 enum batadv_tvlv_type {
        BATADV_TVLV_GW          = 0x01,
@@ -152,6 +186,7 @@ enum batadv_tvlv_type {
        BATADV_TVLV_NC          = 0x03,
        BATADV_TVLV_TT          = 0x04,
        BATADV_TVLV_ROAM        = 0x05,
+       BATADV_TVLV_MCAST       = 0x06,
 };
 
 #pragma pack(2)
@@ -504,4 +539,14 @@ struct batadv_tvlv_roam_adv {
        __be16 vid;
 };
 
+/**
+ * struct batadv_tvlv_mcast_data - payload of a multicast tvlv
+ * @flags: multicast flags announced by the orig node
+ * @reserved: reserved field
+ */
+struct batadv_tvlv_mcast_data {
+       uint8_t flags;
+       uint8_t reserved[3];
+};
+
 #endif /* _NET_BATMAN_ADV_PACKET_H_ */
index 1ed9f7c9ecea4108f00d7beb6c2cb056f5ff87ed..35141534938e76b545de943a7397c60ad23ebff7 100644 (file)
@@ -222,8 +222,8 @@ static int batadv_recv_my_icmp_packet(struct batadv_priv *bat_priv,
 
                icmph = (struct batadv_icmp_header *)skb->data;
 
-               memcpy(icmph->dst, icmph->orig, ETH_ALEN);
-               memcpy(icmph->orig, primary_if->net_dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(icmph->dst, icmph->orig);
+               ether_addr_copy(icmph->orig, primary_if->net_dev->dev_addr);
                icmph->msg_type = BATADV_ECHO_REPLY;
                icmph->ttl = BATADV_TTL;
 
@@ -276,9 +276,8 @@ static int batadv_recv_icmp_ttl_exceeded(struct batadv_priv *bat_priv,
 
        icmp_packet = (struct batadv_icmp_packet *)skb->data;
 
-       memcpy(icmp_packet->dst, icmp_packet->orig, ETH_ALEN);
-       memcpy(icmp_packet->orig, primary_if->net_dev->dev_addr,
-              ETH_ALEN);
+       ether_addr_copy(icmp_packet->dst, icmp_packet->orig);
+       ether_addr_copy(icmp_packet->orig, primary_if->net_dev->dev_addr);
        icmp_packet->msg_type = BATADV_TTL_EXCEEDED;
        icmp_packet->ttl = BATADV_TTL;
 
@@ -341,8 +340,8 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
                if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN)
                        goto out;
 
-               memcpy(&(icmp_packet_rr->rr[icmp_packet_rr->rr_cur]),
-                      ethhdr->h_dest, ETH_ALEN);
+               ether_addr_copy(icmp_packet_rr->rr[icmp_packet_rr->rr_cur],
+                               ethhdr->h_dest);
                icmp_packet_rr->rr_cur++;
        }
 
@@ -664,7 +663,7 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
        }
 
        /* update the packet header */
-       memcpy(unicast_packet->dest, orig_addr, ETH_ALEN);
+       ether_addr_copy(unicast_packet->dest, orig_addr);
        unicast_packet->ttvn = orig_ttvn;
 
        ret = true;
@@ -688,7 +687,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
        int is_old_ttvn;
 
        /* check if there is enough data before accessing it */
-       if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0)
+       if (!pskb_may_pull(skb, hdr_len + ETH_HLEN))
                return 0;
 
        /* create a copy of the skb (in case of for re-routing) to modify it. */
@@ -774,7 +773,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
        if (!primary_if)
                return 0;
 
-       memcpy(unicast_packet->dest, primary_if->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
 
        batadv_hardif_free_ref(primary_if);
 
@@ -918,6 +917,8 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb,
 
        if (ret != NET_RX_SUCCESS)
                ret = batadv_route_unicast_packet(skb, recv_if);
+       else
+               consume_skb(skb);
 
        return ret;
 }
index 579f5f00a385689f29a60ac111adf8b8682e1aa6..3d64ed20c393528793ca4aedd30e21284c51b7ed 100644 (file)
@@ -27,6 +27,7 @@
 #include "originator.h"
 #include "network-coding.h"
 #include "fragmentation.h"
+#include "multicast.h"
 
 static void batadv_send_outstanding_bcast_packet(struct work_struct *work);
 
@@ -59,8 +60,8 @@ int batadv_send_skb_packet(struct sk_buff *skb,
        skb_reset_mac_header(skb);
 
        ethhdr = eth_hdr(skb);
-       memcpy(ethhdr->h_source, hard_iface->net_dev->dev_addr, ETH_ALEN);
-       memcpy(ethhdr->h_dest, dst_addr, ETH_ALEN);
+       ether_addr_copy(ethhdr->h_source, hard_iface->net_dev->dev_addr);
+       ether_addr_copy(ethhdr->h_dest, dst_addr);
        ethhdr->h_proto = htons(ETH_P_BATMAN);
 
        skb_set_network_header(skb, ETH_HLEN);
@@ -165,7 +166,7 @@ batadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size,
        /* set unicast ttl */
        unicast_packet->ttl = BATADV_TTL;
        /* copy the destination for faster routing */
-       memcpy(unicast_packet->dest, orig_node->orig, ETH_ALEN);
+       ether_addr_copy(unicast_packet->dest, orig_node->orig);
        /* set the destination tt version number */
        unicast_packet->ttvn = ttvn;
 
@@ -220,7 +221,7 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
 
        uc_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
        uc_4addr_packet->u.packet_type = BATADV_UNICAST_4ADDR;
-       memcpy(uc_4addr_packet->src, primary_if->net_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(uc_4addr_packet->src, primary_if->net_dev->dev_addr);
        uc_4addr_packet->subtype = packet_subtype;
        uc_4addr_packet->reserved = 0;
 
@@ -248,13 +249,13 @@ out:
  *
  * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
  */
-static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
-                                  struct sk_buff *skb, int packet_type,
-                                  int packet_subtype,
-                                  struct batadv_orig_node *orig_node,
-                                  unsigned short vid)
+int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
+                           struct sk_buff *skb, int packet_type,
+                           int packet_subtype,
+                           struct batadv_orig_node *orig_node,
+                           unsigned short vid)
 {
-       struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+       struct ethhdr *ethhdr;
        struct batadv_unicast_packet *unicast_packet;
        int ret = NET_XMIT_DROP;
 
@@ -279,6 +280,10 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
                goto out;
        }
 
+       /* skb->data might have been reallocated by
+        * batadv_send_skb_prepare_unicast{,_4addr}()
+        */
+       ethhdr = eth_hdr(skb);
        unicast_packet = (struct batadv_unicast_packet *)skb->data;
 
        /* inform the destination node that we are still missing a correct route
@@ -307,6 +312,7 @@ out:
  * @packet_type: the batman unicast packet type to use
  * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
  *  4addr packets)
+ * @dst_hint: can be used to override the destination contained in the skb
  * @vid: the vid to be used to search the translation table
  *
  * Look up the recipient node for the destination address in the ethernet
index aaddaa9661ce49752f11af09700e6f0ab7d9b387..38d0ec1833aed32363a5f1d3a1e471ec972dc3a8 100644 (file)
@@ -36,6 +36,11 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
                                           struct sk_buff *skb,
                                           struct batadv_orig_node *orig_node,
                                           int packet_subtype);
+int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
+                           struct sk_buff *skb, int packet_type,
+                           int packet_subtype,
+                           struct batadv_orig_node *orig_node,
+                           unsigned short vid);
 int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
                                   struct sk_buff *skb, int packet_type,
                                   int packet_subtype, uint8_t *dst_hint,
@@ -47,6 +52,7 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
  * batadv_send_skb_via_tt - send an skb via TT lookup
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the payload to send
+ * @dst_hint: can be used to override the destination contained in the skb
  * @vid: the vid to be used to search the translation table
  *
  * Look up the recipient node for the destination address in the ethernet
@@ -68,6 +74,7 @@ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the payload to send
  * @packet_subtype: the unicast 4addr packet subtype to use
+ * @dst_hint: can be used to override the destination contained in the skb
  * @vid: the vid to be used to search the translation table
  *
  * Look up the recipient node for the destination address in the ethernet
index f82c267e1886ee04cb50339d91e20fa559161737..744a59b85e15ded75f61da8a9fa5a8a87cdb7b8d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include "multicast.h"
 #include "bridge_loop_avoidance.h"
 #include "network-coding.h"
 
@@ -111,8 +112,8 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       memcpy(old_addr, dev->dev_addr, ETH_ALEN);
-       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       ether_addr_copy(old_addr, dev->dev_addr);
+       ether_addr_copy(dev->dev_addr, addr->sa_data);
 
        /* only modify transtable if it has been initialized before */
        if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) {
@@ -170,17 +171,19 @@ static int batadv_interface_tx(struct sk_buff *skb,
        unsigned short vid;
        uint32_t seqno;
        int gw_mode;
+       enum batadv_forw_mode forw_mode;
+       struct batadv_orig_node *mcast_single_orig = NULL;
 
        if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
                goto dropped;
 
        soft_iface->trans_start = jiffies;
        vid = batadv_get_vid(skb, 0);
-       ethhdr = (struct ethhdr *)skb->data;
+       ethhdr = eth_hdr(skb);
 
        switch (ntohs(ethhdr->h_proto)) {
        case ETH_P_8021Q:
-               vhdr = (struct vlan_ethhdr *)skb->data;
+               vhdr = vlan_eth_hdr(skb);
 
                if (vhdr->h_vlan_encapsulated_proto != ethertype)
                        break;
@@ -194,7 +197,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
                goto dropped;
 
        /* skb->data might have been reallocated by batadv_bla_tx() */
-       ethhdr = (struct ethhdr *)skb->data;
+       ethhdr = eth_hdr(skb);
 
        /* Register the client MAC in the transtable */
        if (!is_multicast_ether_addr(ethhdr->h_source)) {
@@ -230,7 +233,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
                /* skb->data may have been modified by
                 * batadv_gw_dhcp_recipient_get()
                 */
-               ethhdr = (struct ethhdr *)skb->data;
+               ethhdr = eth_hdr(skb);
                /* if gw_mode is on, broadcast any non-DHCP message.
                 * All the DHCP packets are going to be sent as unicast
                 */
@@ -247,9 +250,19 @@ static int batadv_interface_tx(struct sk_buff *skb,
                         * directed to a DHCP server
                         */
                        goto dropped;
-       }
 
 send:
+               if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
+                       forw_mode = batadv_mcast_forw_mode(bat_priv, skb,
+                                                          &mcast_single_orig);
+                       if (forw_mode == BATADV_FORW_NONE)
+                               goto dropped;
+
+                       if (forw_mode == BATADV_FORW_SINGLE)
+                               do_bcast = false;
+               }
+       }
+
        batadv_skb_set_priority(skb, 0);
 
        /* ethernet packet should be broadcasted */
@@ -279,8 +292,8 @@ send:
                /* hw address of first interface is the orig mac because only
                 * this mac is known throughout the mesh
                 */
-               memcpy(bcast_packet->orig,
-                      primary_if->net_dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(bcast_packet->orig,
+                               primary_if->net_dev->dev_addr);
 
                /* set broadcast sequence number */
                seqno = atomic_inc_return(&bat_priv->bcast_seqno);
@@ -301,6 +314,10 @@ send:
                        if (ret)
                                goto dropped;
                        ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
+               } else if (mcast_single_orig) {
+                       ret = batadv_send_skb_unicast(bat_priv, skb,
+                                                     BATADV_UNICAST, 0,
+                                                     mcast_single_orig, vid);
                } else {
                        if (batadv_dat_snoop_outgoing_arp_request(bat_priv,
                                                                  skb))
@@ -652,10 +669,7 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
        }
 
        batadv_sysfs_del_meshif(soft_iface);
-
-       rtnl_lock();
-       unregister_netdevice(soft_iface);
-       rtnl_unlock();
+       unregister_netdev(soft_iface);
 }
 
 /**
@@ -691,6 +705,14 @@ static int batadv_softif_init_late(struct net_device *dev)
 #endif
 #ifdef CONFIG_BATMAN_ADV_DAT
        atomic_set(&bat_priv->distributed_arp_table, 1);
+#endif
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       bat_priv->mcast.flags = BATADV_NO_FLAGS;
+       atomic_set(&bat_priv->multicast_mode, 1);
+       atomic_set(&bat_priv->mcast.num_disabled, 0);
+       atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
+       atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0);
+       atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0);
 #endif
        atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
        atomic_set(&bat_priv->gw_sel_class, 20);
index e456bf6bb2844e61560fa961a6984d5ef83a8817..1ebb0d9e2ea547d1c263a6b09d30d81214e4ba33 100644 (file)
@@ -539,6 +539,9 @@ BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE,
                     batadv_post_gw_reselect);
 static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
                   batadv_store_gw_bwidth);
+#ifdef CONFIG_BATMAN_ADV_MCAST
+BATADV_ATTR_SIF_BOOL(multicast_mode, S_IRUGO | S_IWUSR, NULL);
+#endif
 #ifdef CONFIG_BATMAN_ADV_DEBUG
 BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);
 #endif
@@ -557,6 +560,9 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
 #endif
 #ifdef CONFIG_BATMAN_ADV_DAT
        &batadv_attr_distributed_arp_table,
+#endif
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       &batadv_attr_multicast_mode,
 #endif
        &batadv_attr_fragmentation,
        &batadv_attr_routing_algo,
index b6071f675a3e57e159a99dec0c24f88603af9042..d636bde72c9ace9cfbcead01353c955f17923155 100644 (file)
@@ -24,6 +24,7 @@
 #include "originator.h"
 #include "routing.h"
 #include "bridge_loop_avoidance.h"
+#include "multicast.h"
 
 #include <linux/crc32c.h>
 
@@ -96,7 +97,7 @@ batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr,
        if (!hash)
                return NULL;
 
-       memcpy(to_search.addr, addr, ETH_ALEN);
+       ether_addr_copy(to_search.addr, addr);
        to_search.vid = vid;
 
        index = batadv_choose_tt(&to_search, hash->size);
@@ -192,6 +193,31 @@ batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry)
        }
 }
 
+/**
+ * batadv_tt_global_hash_count - count the number of orig entries
+ * @hash: hash table containing the tt entries
+ * @addr: the mac address of the client to count entries for
+ * @vid: VLAN identifier
+ *
+ * Return the number of originators advertising the given address/data
+ * (excluding ourself).
+ */
+int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
+                               const uint8_t *addr, unsigned short vid)
+{
+       struct batadv_tt_global_entry *tt_global_entry;
+       int count;
+
+       tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
+       if (!tt_global_entry)
+               return 0;
+
+       count = atomic_read(&tt_global_entry->orig_list_count);
+       batadv_tt_global_entry_free_ref(tt_global_entry);
+
+       return count;
+}
+
 static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
 {
        struct batadv_tt_orig_list_entry *orig_entry;
@@ -333,7 +359,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
        tt_change_node->change.flags = flags;
        memset(tt_change_node->change.reserved, 0,
               sizeof(tt_change_node->change.reserved));
-       memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN);
+       ether_addr_copy(tt_change_node->change.addr, common->addr);
        tt_change_node->change.vid = htons(common->vid);
 
        del_op_requested = flags & BATADV_TT_CLIENT_DEL;
@@ -484,7 +510,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 {
        struct batadv_priv *bat_priv = netdev_priv(soft_iface);
        struct batadv_tt_local_entry *tt_local;
-       struct batadv_tt_global_entry *tt_global;
+       struct batadv_tt_global_entry *tt_global = NULL;
        struct net_device *in_dev = NULL;
        struct hlist_head *head;
        struct batadv_tt_orig_list_entry *orig_entry;
@@ -497,7 +523,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
                in_dev = dev_get_by_index(&init_net, ifindex);
 
        tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
-       tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
+
+       if (!is_multicast_ether_addr(addr))
+               tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
 
        if (tt_local) {
                tt_local->last_seen = jiffies;
@@ -549,7 +577,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
                   addr, BATADV_PRINT_VID(vid),
                   (uint8_t)atomic_read(&bat_priv->tt.vn));
 
-       memcpy(tt_local->common.addr, addr, ETH_ALEN);
+       ether_addr_copy(tt_local->common.addr, addr);
        /* The local entry has to be marked as NEW to avoid to send it in
         * a full table response going out before the next ttvn increment
         * (consistency check)
@@ -562,8 +590,11 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
        tt_local->last_seen = jiffies;
        tt_local->common.added_at = tt_local->last_seen;
 
-       /* the batman interface mac address should never be purged */
-       if (batadv_compare_eth(addr, soft_iface->dev_addr))
+       /* the batman interface mac and multicast addresses should never be
+        * purged
+        */
+       if (batadv_compare_eth(addr, soft_iface->dev_addr) ||
+           is_multicast_ether_addr(addr))
                tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
 
        hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
@@ -1219,6 +1250,8 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
        hlist_add_head_rcu(&orig_entry->list,
                           &tt_global->orig_list);
        spin_unlock_bh(&tt_global->list_lock);
+       atomic_inc(&tt_global->orig_list_count);
+
 out:
        if (orig_entry)
                batadv_tt_orig_list_entry_free_ref(orig_entry);
@@ -1277,7 +1310,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
                        goto out;
 
                common = &tt_global_entry->common;
-               memcpy(common->addr, tt_addr, ETH_ALEN);
+               ether_addr_copy(common->addr, tt_addr);
                common->vid = vid;
 
                common->flags = flags;
@@ -1292,6 +1325,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
                common->added_at = jiffies;
 
                INIT_HLIST_HEAD(&tt_global_entry->orig_list);
+               atomic_set(&tt_global_entry->orig_list_count, 0);
                spin_lock_init(&tt_global_entry->list_lock);
 
                hash_added = batadv_hash_add(bat_priv->tt.global_hash,
@@ -1361,6 +1395,11 @@ add_orig_entry:
        ret = true;
 
 out_remove:
+       /* Do not remove multicast addresses from the local hash on
+        * global additions
+        */
+       if (is_multicast_ether_addr(tt_addr))
+               goto out;
 
        /* remove address from local hash if present */
        local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
@@ -1552,6 +1591,25 @@ out:
        return 0;
 }
 
+/**
+ * batadv_tt_global_del_orig_entry - remove and free an orig_entry
+ * @tt_global_entry: the global entry to remove the orig_entry from
+ * @orig_entry: the orig entry to remove and free
+ *
+ * Remove an orig_entry from its list in the given tt_global_entry and
+ * free this orig_entry afterwards.
+ */
+static void
+batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry,
+                               struct batadv_tt_orig_list_entry *orig_entry)
+{
+       batadv_tt_global_size_dec(orig_entry->orig_node,
+                                 tt_global_entry->common.vid);
+       atomic_dec(&tt_global_entry->orig_list_count);
+       hlist_del_rcu(&orig_entry->list);
+       batadv_tt_orig_list_entry_free_ref(orig_entry);
+}
+
 /* deletes the orig list of a tt_global_entry */
 static void
 batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
@@ -1562,20 +1620,26 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
 
        spin_lock_bh(&tt_global_entry->list_lock);
        head = &tt_global_entry->orig_list;
-       hlist_for_each_entry_safe(orig_entry, safe, head, list) {
-               hlist_del_rcu(&orig_entry->list);
-               batadv_tt_global_size_dec(orig_entry->orig_node,
-                                         tt_global_entry->common.vid);
-               batadv_tt_orig_list_entry_free_ref(orig_entry);
-       }
+       hlist_for_each_entry_safe(orig_entry, safe, head, list)
+               batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry);
        spin_unlock_bh(&tt_global_entry->list_lock);
 }
 
+/**
+ * batadv_tt_global_del_orig_node - remove orig_node from a global tt entry
+ * @bat_priv: the bat priv with all the soft interface information
+ * @tt_global_entry: the global entry to remove the orig_node from
+ * @orig_node: the originator announcing the client
+ * @message: message to append to the log on deletion
+ *
+ * Remove the given orig_node and its according orig_entry from the given
+ * global tt entry.
+ */
 static void
-batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
-                               struct batadv_tt_global_entry *tt_global_entry,
-                               struct batadv_orig_node *orig_node,
-                               const char *message)
+batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv,
+                              struct batadv_tt_global_entry *tt_global_entry,
+                              struct batadv_orig_node *orig_node,
+                              const char *message)
 {
        struct hlist_head *head;
        struct hlist_node *safe;
@@ -1592,10 +1656,8 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
                                   orig_node->orig,
                                   tt_global_entry->common.addr,
                                   BATADV_PRINT_VID(vid), message);
-                       hlist_del_rcu(&orig_entry->list);
-                       batadv_tt_global_size_dec(orig_node,
-                                                 tt_global_entry->common.vid);
-                       batadv_tt_orig_list_entry_free_ref(orig_entry);
+                       batadv_tt_global_del_orig_entry(tt_global_entry,
+                                                       orig_entry);
                }
        }
        spin_unlock_bh(&tt_global_entry->list_lock);
@@ -1637,8 +1699,8 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
                /* there is another entry, we can simply delete this
                 * one and can still use the other one.
                 */
-               batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
-                                               orig_node, message);
+               batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
+                                              orig_node, message);
 }
 
 /**
@@ -1664,8 +1726,8 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
                goto out;
 
        if (!roaming) {
-               batadv_tt_global_del_orig_entry(bat_priv, tt_global_entry,
-                                               orig_node, message);
+               batadv_tt_global_del_orig_node(bat_priv, tt_global_entry,
+                                              orig_node, message);
 
                if (hlist_empty(&tt_global_entry->orig_list))
                        batadv_tt_global_free(bat_priv, tt_global_entry,
@@ -1748,8 +1810,8 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
                                                 struct batadv_tt_global_entry,
                                                 common);
 
-                       batadv_tt_global_del_orig_entry(bat_priv, tt_global,
-                                                       orig_node, message);
+                       batadv_tt_global_del_orig_node(bat_priv, tt_global,
+                                                      orig_node, message);
 
                        if (hlist_empty(&tt_global->orig_list)) {
                                vid = tt_global->common.vid;
@@ -1763,7 +1825,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
                }
                spin_unlock_bh(list_lock);
        }
-       orig_node->tt_initialised = false;
+       orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT;
 }
 
 static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
@@ -1975,6 +2037,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
        struct hlist_head *head;
        uint32_t i, crc_tmp, crc = 0;
        uint8_t flags;
+       __be16 tmp_vid;
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -2011,8 +2074,11 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
                                                             orig_node))
                                continue;
 
-                       crc_tmp = crc32c(0, &tt_common->vid,
-                                        sizeof(tt_common->vid));
+                       /* use network order to read the VID: this ensures that
+                        * every node reads the bytes in the same order.
+                        */
+                       tmp_vid = htons(tt_common->vid);
+                       crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
 
                        /* compute the CRC on flags that have to be kept in sync
                         * among nodes
@@ -2046,6 +2112,7 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv,
        struct hlist_head *head;
        uint32_t i, crc_tmp, crc = 0;
        uint8_t flags;
+       __be16 tmp_vid;
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -2064,8 +2131,11 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv,
                        if (tt_common->flags & BATADV_TT_CLIENT_NEW)
                                continue;
 
-                       crc_tmp = crc32c(0, &tt_common->vid,
-                                        sizeof(tt_common->vid));
+                       /* use network order to read the VID: this ensures that
+                        * every node reads the bytes in the same order.
+                        */
+                       tmp_vid = htons(tt_common->vid);
+                       crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
 
                        /* compute the CRC on flags that have to be kept in sync
                         * among nodes
@@ -2152,7 +2222,7 @@ batadv_new_tt_req_node(struct batadv_priv *bat_priv,
        if (!tt_req_node)
                goto unlock;
 
-       memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
+       ether_addr_copy(tt_req_node->addr, orig_node->orig);
        tt_req_node->issued_at = jiffies;
 
        list_add(&tt_req_node->list, &bat_priv->tt.req_list);
@@ -2232,8 +2302,7 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
                        if ((valid_cb) && (!valid_cb(tt_common_entry, cb_data)))
                                continue;
 
-                       memcpy(tt_change->addr, tt_common_entry->addr,
-                              ETH_ALEN);
+                       ether_addr_copy(tt_change->addr, tt_common_entry->addr);
                        tt_change->flags = tt_common_entry->flags;
                        tt_change->vid = htons(tt_common_entry->vid);
                        memset(tt_change->reserved, 0,
@@ -2262,6 +2331,7 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
 {
        struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
        struct batadv_orig_node_vlan *vlan;
+       uint32_t crc;
        int i;
 
        /* check if each received CRC matches the locally stored one */
@@ -2281,7 +2351,10 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
                if (!vlan)
                        return false;
 
-               if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc))
+               crc = vlan->tt.crc;
+               batadv_orig_node_vlan_free_ref(vlan);
+
+               if (crc != ntohl(tt_vlan_tmp->crc))
                        return false;
        }
 
@@ -2712,7 +2785,7 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
                                return;
                }
        }
-       orig_node->tt_initialised = true;
+       orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT;
 }
 
 static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
@@ -2920,7 +2993,7 @@ static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv,
                tt_roam_node->first_time = jiffies;
                atomic_set(&tt_roam_node->counter,
                           BATADV_ROAMING_MAX_COUNT - 1);
-               memcpy(tt_roam_node->addr, client, ETH_ALEN);
+               ether_addr_copy(tt_roam_node->addr, client);
 
                list_add(&tt_roam_node->list, &bat_priv->tt.roam_list);
                ret = true;
@@ -3109,6 +3182,9 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
  */
 static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
 {
+       /* Update multicast addresses in local translation table */
+       batadv_mcast_mla_update(bat_priv);
+
        if (atomic_read(&bat_priv->tt.local_changes) < 1) {
                if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
                        batadv_tt_tvlv_container_update(bat_priv);
@@ -3199,13 +3275,15 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
        uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
        struct batadv_tvlv_tt_vlan_data *tt_vlan;
        bool full_table = true;
+       bool has_tt_init;
 
        tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
+       has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT;
+
        /* orig table not initialised AND first diff is in the OGM OR the ttvn
         * increased by one -> we can apply the attached changes
         */
-       if ((!orig_node->tt_initialised && ttvn == 1) ||
-           ttvn - orig_ttvn == 1) {
+       if ((!has_tt_init && ttvn == 1) || ttvn - orig_ttvn == 1) {
                /* the OGM could not contain the changes due to their size or
                 * because they have already been sent BATADV_TT_OGM_APPEND_MAX
                 * times.
@@ -3218,7 +3296,6 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
 
                spin_lock_bh(&orig_node->tt_lock);
 
-               tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
                batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
                                         ttvn, tt_change);
 
@@ -3246,7 +3323,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
                /* if we missed more than one change or our tables are not
                 * in sync anymore -> request fresh tt data
                 */
-               if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
+               if (!has_tt_init || ttvn != orig_ttvn ||
                    !batadv_tt_global_check_crc(orig_node, tt_vlan,
                                                tt_num_vlan)) {
 request_table:
index 20a1d7861ded99ecb18cace18af3b85f06fbe018..ad84d7b89e399930132ac2537d66222eb4712119 100644 (file)
@@ -29,6 +29,8 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset);
 void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
                               struct batadv_orig_node *orig_node,
                               int32_t match_vid, const char *message);
+int batadv_tt_global_hash_count(struct batadv_priv *bat_priv,
+                               const uint8_t *addr, unsigned short vid);
 struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
                                                  const uint8_t *src,
                                                  const uint8_t *addr,
index 78370ab31f9c2f7db1793ecedb0735eb4d8fa087..34891a56773f09ebcccab01fe3191b1a56651aed 100644 (file)
@@ -24,8 +24,9 @@
 
 #ifdef CONFIG_BATMAN_ADV_DAT
 
-/* batadv_dat_addr_t is the type used for all DHT addresses. If it is changed,
- * BATADV_DAT_ADDR_MAX is changed as well.
+/**
+ * batadv_dat_addr_t - it is the type used for all DHT addresses. If it is
+ *  changed, BATADV_DAT_ADDR_MAX is changed as well.
  *
  * *Please be careful: batadv_dat_addr_t must be UNSIGNED*
  */
@@ -163,7 +164,7 @@ struct batadv_vlan_tt {
 };
 
 /**
- * batadv_orig_node_vlan - VLAN specific data per orig_node
+ * struct batadv_orig_node_vlan - VLAN specific data per orig_node
  * @vid: the VLAN identifier
  * @tt: VLAN specific TT attributes
  * @list: list node for orig_node::vlan_list
@@ -204,14 +205,18 @@ struct batadv_orig_bat_iv {
  * @batadv_dat_addr_t:  address of the orig node in the distributed hash
  * @last_seen: time when last packet from this node was received
  * @bcast_seqno_reset: time when the broadcast seqno window was reset
+ * @mcast_flags: multicast flags announced by the orig node
+ * @mcast_want_all_unsnoop_node: a list node for the
+ *  mcast.want_all_unsnoopables list
+ * @mcast_want_all_ipv4_node: a list node for the mcast.want_all_ipv4 list
+ * @mcast_want_all_ipv6_node: a list node for the mcast.want_all_ipv6 list
  * @capabilities: announced capabilities of this originator
+ * @capa_initialized: bitfield to remember whether a capability was initialized
  * @last_ttvn: last seen translation table version number
  * @tt_buff: last tt changeset this node received from the orig node
  * @tt_buff_len: length of the last tt changeset this node received from the
  *  orig node
  * @tt_buff_lock: lock that protects tt_buff and tt_buff_len
- * @tt_initialised: bool keeping track of whether or not this node have received
- *  any translation table information from the orig node yet
  * @tt_lock: prevents from updating the table while reading it. Table update is
  *  made up by two operations (data structure update and metdata -CRC/TTVN-
  *  recalculation) and they have to be executed atomically in order to avoid
@@ -247,12 +252,18 @@ struct batadv_orig_node {
 #endif
        unsigned long last_seen;
        unsigned long bcast_seqno_reset;
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       uint8_t mcast_flags;
+       struct hlist_node mcast_want_all_unsnoopables_node;
+       struct hlist_node mcast_want_all_ipv4_node;
+       struct hlist_node mcast_want_all_ipv6_node;
+#endif
        uint8_t capabilities;
+       uint8_t capa_initialized;
        atomic_t last_ttvn;
        unsigned char *tt_buff;
        int16_t tt_buff_len;
        spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */
-       bool tt_initialised;
        /* prevents from changing the table while reading it */
        spinlock_t tt_lock;
        DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
@@ -282,10 +293,15 @@ struct batadv_orig_node {
  * enum batadv_orig_capabilities - orig node capabilities
  * @BATADV_ORIG_CAPA_HAS_DAT: orig node has distributed arp table enabled
  * @BATADV_ORIG_CAPA_HAS_NC: orig node has network coding enabled
+ * @BATADV_ORIG_CAPA_HAS_TT: orig node has tt capability
+ * @BATADV_ORIG_CAPA_HAS_MCAST: orig node has some multicast capability
+ *  (= orig node announces a tvlv of type BATADV_TVLV_MCAST)
  */
 enum batadv_orig_capabilities {
        BATADV_ORIG_CAPA_HAS_DAT = BIT(0),
        BATADV_ORIG_CAPA_HAS_NC = BIT(1),
+       BATADV_ORIG_CAPA_HAS_TT = BIT(2),
+       BATADV_ORIG_CAPA_HAS_MCAST = BIT(3),
 };
 
 /**
@@ -334,7 +350,7 @@ struct batadv_neigh_node {
 };
 
 /**
- * struct batadv_neigh_node_bat_iv - neighbor information per outgoing
+ * struct batadv_neigh_ifinfo_bat_iv - neighbor information per outgoing
  *  interface for BATMAN IV
  * @tq_recv: ring buffer of received TQ values from this neigh node
  * @tq_index: ring buffer index
@@ -544,7 +560,7 @@ struct batadv_priv_bla {
 #endif
 
 /**
- * struct batadv_debug_log - debug logging data
+ * struct batadv_priv_debug_log - debug logging data
  * @log_buff: buffer holding the logs (ring bufer)
  * @log_start: index of next character to read
  * @log_end: index of next character to write
@@ -607,6 +623,39 @@ struct batadv_priv_dat {
 };
 #endif
 
+#ifdef CONFIG_BATMAN_ADV_MCAST
+/**
+ * struct batadv_priv_mcast - per mesh interface mcast data
+ * @mla_list: list of multicast addresses we are currently announcing via TT
+ * @want_all_unsnoopables_list: a list of orig_nodes wanting all unsnoopable
+ *  multicast traffic
+ * @want_all_ipv4_list: a list of orig_nodes wanting all IPv4 multicast traffic
+ * @want_all_ipv6_list: a list of orig_nodes wanting all IPv6 multicast traffic
+ * @flags: the flags we have last sent in our mcast tvlv
+ * @enabled: whether the multicast tvlv is currently enabled
+ * @num_disabled: number of nodes that have no mcast tvlv
+ * @num_want_all_unsnoopables: number of nodes wanting unsnoopable IP traffic
+ * @num_want_all_ipv4: counter for items in want_all_ipv4_list
+ * @num_want_all_ipv6: counter for items in want_all_ipv6_list
+ * @want_lists_lock: lock for protecting modifications to mcast want lists
+ *  (traversals are rcu-locked)
+ */
+struct batadv_priv_mcast {
+       struct hlist_head mla_list;
+       struct hlist_head want_all_unsnoopables_list;
+       struct hlist_head want_all_ipv4_list;
+       struct hlist_head want_all_ipv6_list;
+       uint8_t flags;
+       bool enabled;
+       atomic_t num_disabled;
+       atomic_t num_want_all_unsnoopables;
+       atomic_t num_want_all_ipv4;
+       atomic_t num_want_all_ipv6;
+       /* protects want_all_{unsnoopables,ipv4,ipv6}_list */
+       spinlock_t want_lists_lock;
+};
+#endif
+
 /**
  * struct batadv_priv_nc - per mesh interface network coding private data
  * @work: work queue callback item for cleanup
@@ -672,6 +721,8 @@ struct batadv_softif_vlan {
  *  enabled
  * @distributed_arp_table: bool indicating whether distributed ARP table is
  *  enabled
+ * @multicast_mode: Enable or disable multicast optimizations on this node's
+ *  sender/originating side
  * @gw_mode: gateway operation: off, client or server (see batadv_gw_modes)
  * @gw_sel_class: gateway selection class (applies if gw_mode client)
  * @orig_interval: OGM broadcast interval in milliseconds
@@ -702,6 +753,7 @@ struct batadv_softif_vlan {
  * @tt: translation table data
  * @tvlv: type-version-length-value data
  * @dat: distributed arp table data
+ * @mcast: multicast data
  * @network_coding: bool indicating whether network coding is enabled
  * @batadv_priv_nc: network coding data
  */
@@ -720,6 +772,9 @@ struct batadv_priv {
 #endif
 #ifdef CONFIG_BATMAN_ADV_DAT
        atomic_t distributed_arp_table;
+#endif
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       atomic_t multicast_mode;
 #endif
        atomic_t gw_mode;
        atomic_t gw_sel_class;
@@ -759,6 +814,9 @@ struct batadv_priv {
 #ifdef CONFIG_BATMAN_ADV_DAT
        struct batadv_priv_dat dat;
 #endif
+#ifdef CONFIG_BATMAN_ADV_MCAST
+       struct batadv_priv_mcast mcast;
+#endif
 #ifdef CONFIG_BATMAN_ADV_NC
        atomic_t network_coding;
        struct batadv_priv_nc nc;
@@ -881,12 +939,14 @@ struct batadv_tt_local_entry {
  * struct batadv_tt_global_entry - translation table global entry data
  * @common: general translation table data
  * @orig_list: list of orig nodes announcing this non-mesh client
+ * @orig_list_count: number of items in the orig_list
  * @list_lock: lock protecting orig_list
  * @roam_at: time at which TT_GLOBAL_ROAM was set
  */
 struct batadv_tt_global_entry {
        struct batadv_tt_common_entry common;
        struct hlist_head orig_list;
+       atomic_t orig_list_count;
        spinlock_t list_lock;   /* protects orig_list */
        unsigned long roam_at;
 };
@@ -1004,8 +1064,8 @@ struct batadv_nc_packet {
 };
 
 /**
- * batadv_skb_cb - control buffer structure used to store private data relevant
- *  to batman-adv in the skb->cb buffer in skbs.
+ * struct batadv_skb_cb - control buffer structure used to store private data
+ *  relevant to batman-adv in the skb->cb buffer in skbs.
  * @decoded: Marks a skb as decoded, which is checked when searching for coding
  *  opportunities in network-coding.c
  */
@@ -1115,6 +1175,16 @@ struct batadv_dat_entry {
        struct rcu_head rcu;
 };
 
+/**
+ * struct batadv_hw_addr - a list entry for a MAC address
+ * @list: list node for the linking of entries
+ * @addr: the MAC address of this list entry
+ */
+struct batadv_hw_addr {
+       struct hlist_node list;
+       unsigned char addr[ETH_ALEN];
+};
+
 /**
  * struct batadv_dat_candidate - candidate destination for DAT operations
  * @type: the type of the selected candidate. It can one of the following:
index adb3ea04adaaa73d3faf4db783f096e91e93321e..73492b91105ac0aba10aec738415128d0582bfc5 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "6lowpan.h"
 
-#include "../ieee802154/6lowpan.h" /* for the compression support */
+#include <net/6lowpan.h> /* for the compression support */
 
 #define IFACE_NAME_TEMPLATE "bt%d"
 #define EUI64_ADDR_LEN 8
index 292e619db8961c82e7c3aa7f3280cb4236176ab8..d9fb9345144238f61372fdb21ca57c08b9471efd 100644 (file)
@@ -430,6 +430,16 @@ static void hidp_del_timer(struct hidp_session *session)
                del_timer(&session->timer);
 }
 
+static void hidp_process_report(struct hidp_session *session,
+                               int type, const u8 *data, int len, int intr)
+{
+       if (len > HID_MAX_BUFFER_SIZE)
+               len = HID_MAX_BUFFER_SIZE;
+
+       memcpy(session->input_buf, data, len);
+       hid_input_report(session->hid, type, session->input_buf, len, intr);
+}
+
 static void hidp_process_handshake(struct hidp_session *session,
                                        unsigned char param)
 {
@@ -502,7 +512,8 @@ static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
                        hidp_input_report(session, skb);
 
                if (session->hid)
-                       hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0);
+                       hidp_process_report(session, HID_INPUT_REPORT,
+                                           skb->data, skb->len, 0);
                break;
 
        case HIDP_DATA_RTYPE_OTHER:
@@ -584,7 +595,8 @@ static void hidp_recv_intr_frame(struct hidp_session *session,
                        hidp_input_report(session, skb);
 
                if (session->hid) {
-                       hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1);
+                       hidp_process_report(session, HID_INPUT_REPORT,
+                                           skb->data, skb->len, 1);
                        BT_DBG("report len %d", skb->len);
                }
        } else {
index ab5241400cf78a9d7371d7a866d58aeba0d8043a..8798492a6e9971fff198344b580fa5ec3f17b8be 100644 (file)
@@ -24,6 +24,7 @@
 #define __HIDP_H
 
 #include <linux/types.h>
+#include <linux/hid.h>
 #include <linux/kref.h>
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/l2cap.h>
@@ -179,6 +180,9 @@ struct hidp_session {
 
        /* Used in hidp_output_raw_report() */
        int output_report_success; /* boolean */
+
+       /* temporary input buffer */
+       u8 input_buf[HID_MAX_BUFFER_SIZE];
 };
 
 /* HIDP init defines */
index e4401a531afbd4bc1b22819282ff1a6d1b539bb0..3e2da2cb72db1725f064ec21d3ce6ab8765532c1 100644 (file)
@@ -49,14 +49,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        brstats->tx_bytes += skb->len;
        u64_stats_update_end(&brstats->syncp);
 
-       if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
-               goto out;
-
        BR_INPUT_SKB_CB(skb)->brdev = dev;
 
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
 
+       if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
+               goto out;
+
        if (is_broadcast_ether_addr(dest))
                br_flood_deliver(br, skb, false);
        else if (is_multicast_ether_addr(dest)) {
@@ -88,18 +88,11 @@ out:
 static int br_dev_init(struct net_device *dev)
 {
        struct net_bridge *br = netdev_priv(dev);
-       int i;
 
-       br->stats = alloc_percpu(struct pcpu_sw_netstats);
+       br->stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!br->stats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *br_dev_stats;
-               br_dev_stats = per_cpu_ptr(br->stats, i);
-               u64_stats_init(&br_dev_stats->syncp);
-       }
-
        return 0;
 }
 
@@ -143,9 +136,9 @@ static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
                const struct pcpu_sw_netstats *bstats
                        = per_cpu_ptr(br->stats, cpu);
                do {
-                       start = u64_stats_fetch_begin_bh(&bstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&bstats->syncp);
                        memcpy(&tmp, bstats, sizeof(tmp));
-               } while (u64_stats_fetch_retry_bh(&bstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&bstats->syncp, start));
                sum.tx_bytes   += tmp.tx_bytes;
                sum.tx_packets += tmp.tx_packets;
                sum.rx_bytes   += tmp.rx_bytes;
@@ -187,8 +180,7 @@ static int br_set_mac_address(struct net_device *dev, void *p)
 
        spin_lock_bh(&br->lock);
        if (!ether_addr_equal(dev->dev_addr, addr->sa_data)) {
-               memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
-               br_fdb_change_mac_address(br, addr->sa_data);
+               /* Mac address will be changed in br_stp_change_bridge_id(). */
                br_stp_change_bridge_id(br, addr->sa_data);
        }
        spin_unlock_bh(&br->lock);
@@ -226,8 +218,34 @@ static void br_netpoll_cleanup(struct net_device *dev)
                br_netpoll_disable(p);
 }
 
-static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni,
-                           gfp_t gfp)
+static int __br_netpoll_enable(struct net_bridge_port *p)
+{
+       struct netpoll *np;
+       int err;
+
+       np = kzalloc(sizeof(*p->np), GFP_KERNEL);
+       if (!np)
+               return -ENOMEM;
+
+       err = __netpoll_setup(np, p->dev);
+       if (err) {
+               kfree(np);
+               return err;
+       }
+
+       p->np = np;
+       return err;
+}
+
+int br_netpoll_enable(struct net_bridge_port *p)
+{
+       if (!p->br->dev->npinfo)
+               return 0;
+
+       return __br_netpoll_enable(p);
+}
+
+static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
 {
        struct net_bridge *br = netdev_priv(dev);
        struct net_bridge_port *p;
@@ -236,7 +254,7 @@ static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni,
        list_for_each_entry(p, &br->port_list, list) {
                if (!p->dev)
                        continue;
-               err = br_netpoll_enable(p, gfp);
+               err = __br_netpoll_enable(p);
                if (err)
                        goto fail;
        }
@@ -249,28 +267,6 @@ fail:
        goto out;
 }
 
-int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
-{
-       struct netpoll *np;
-       int err;
-
-       if (!p->br->dev->npinfo)
-               return 0;
-
-       np = kzalloc(sizeof(*p->np), gfp);
-       if (!np)
-               return -ENOMEM;
-
-       err = __netpoll_setup(np, p->dev, gfp);
-       if (err) {
-               kfree(np);
-               return err;
-       }
-
-       p->np = np;
-       return err;
-}
-
 void br_netpoll_disable(struct net_bridge_port *p)
 {
        struct netpoll *np = p->np;
@@ -370,7 +366,7 @@ void br_dev_setup(struct net_device *dev)
        br->bridge_id.prio[0] = 0x80;
        br->bridge_id.prio[1] = 0x00;
 
-       memcpy(br->group_addr, eth_reserved_addr_base, ETH_ALEN);
+       ether_addr_copy(br->group_addr, eth_reserved_addr_base);
 
        br->stp_enabled = BR_NO_STP;
        br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
index c5f5a4a933f4302d34fd35abff160287af496919..9203d5a1943fbd4ba272ae38e742d8692093f7f1 100644 (file)
@@ -27,6 +27,9 @@
 #include "br_private.h"
 
 static struct kmem_cache *br_fdb_cache __read_mostly;
+static struct net_bridge_fdb_entry *fdb_find(struct hlist_head *head,
+                                            const unsigned char *addr,
+                                            __u16 vid);
 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
                      const unsigned char *addr, u16 vid);
 static void fdb_notify(struct net_bridge *br,
@@ -89,11 +92,57 @@ static void fdb_delete(struct net_bridge *br, struct net_bridge_fdb_entry *f)
        call_rcu(&f->rcu, fdb_rcu_free);
 }
 
+/* Delete a local entry if no other port had the same address. */
+static void fdb_delete_local(struct net_bridge *br,
+                            const struct net_bridge_port *p,
+                            struct net_bridge_fdb_entry *f)
+{
+       const unsigned char *addr = f->addr.addr;
+       u16 vid = f->vlan_id;
+       struct net_bridge_port *op;
+
+       /* Maybe another port has same hw addr? */
+       list_for_each_entry(op, &br->port_list, list) {
+               if (op != p && ether_addr_equal(op->dev->dev_addr, addr) &&
+                   (!vid || nbp_vlan_find(op, vid))) {
+                       f->dst = op;
+                       f->added_by_user = 0;
+                       return;
+               }
+       }
+
+       /* Maybe bridge device has same hw addr? */
+       if (p && ether_addr_equal(br->dev->dev_addr, addr) &&
+           (!vid || br_vlan_find(br, vid))) {
+               f->dst = NULL;
+               f->added_by_user = 0;
+               return;
+       }
+
+       fdb_delete(br, f);
+}
+
+void br_fdb_find_delete_local(struct net_bridge *br,
+                             const struct net_bridge_port *p,
+                             const unsigned char *addr, u16 vid)
+{
+       struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
+       struct net_bridge_fdb_entry *f;
+
+       spin_lock_bh(&br->hash_lock);
+       f = fdb_find(head, addr, vid);
+       if (f && f->is_local && !f->added_by_user && f->dst == p)
+               fdb_delete_local(br, p, f);
+       spin_unlock_bh(&br->hash_lock);
+}
+
 void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
 {
        struct net_bridge *br = p->br;
-       bool no_vlan = (nbp_get_vlan_info(p) == NULL) ? true : false;
+       struct net_port_vlans *pv = nbp_get_vlan_info(p);
+       bool no_vlan = !pv;
        int i;
+       u16 vid;
 
        spin_lock_bh(&br->hash_lock);
 
@@ -104,38 +153,34 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
                        struct net_bridge_fdb_entry *f;
 
                        f = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
-                       if (f->dst == p && f->is_local) {
-                               /* maybe another port has same hw addr? */
-                               struct net_bridge_port *op;
-                               u16 vid = f->vlan_id;
-                               list_for_each_entry(op, &br->port_list, list) {
-                                       if (op != p &&
-                                           ether_addr_equal(op->dev->dev_addr,
-                                                            f->addr.addr) &&
-                                           nbp_vlan_find(op, vid)) {
-                                               f->dst = op;
-                                               goto insert;
-                                       }
-                               }
-
+                       if (f->dst == p && f->is_local && !f->added_by_user) {
                                /* delete old one */
-                               fdb_delete(br, f);
-insert:
-                               /* insert new address,  may fail if invalid
-                                * address or dup.
-                                */
-                               fdb_insert(br, p, newaddr, vid);
+                               fdb_delete_local(br, p, f);
 
                                /* if this port has no vlan information
                                 * configured, we can safely be done at
                                 * this point.
                                 */
                                if (no_vlan)
-                                       goto done;
+                                       goto insert;
                        }
                }
        }
 
+insert:
+       /* insert new address,  may fail if invalid address or dup. */
+       fdb_insert(br, p, newaddr, 0);
+
+       if (no_vlan)
+               goto done;
+
+       /* Now add entries for every VLAN configured on the port.
+        * This function runs under RTNL so the bitmap will not change
+        * from under us.
+        */
+       for_each_set_bit(vid, pv->vlan_bitmap, VLAN_N_VID)
+               fdb_insert(br, p, newaddr, vid);
+
 done:
        spin_unlock_bh(&br->hash_lock);
 }
@@ -146,10 +191,12 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
        struct net_port_vlans *pv;
        u16 vid = 0;
 
+       spin_lock_bh(&br->hash_lock);
+
        /* If old entry was unassociated with any port, then delete it. */
        f = __br_fdb_get(br, br->dev->dev_addr, 0);
        if (f && f->is_local && !f->dst)
-               fdb_delete(br, f);
+               fdb_delete_local(br, NULL, f);
 
        fdb_insert(br, NULL, newaddr, 0);
 
@@ -159,14 +206,16 @@ void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr)
         */
        pv = br_get_vlan_info(br);
        if (!pv)
-               return;
+               goto out;
 
        for_each_set_bit_from(vid, pv->vlan_bitmap, VLAN_N_VID) {
                f = __br_fdb_get(br, br->dev->dev_addr, vid);
                if (f && f->is_local && !f->dst)
-                       fdb_delete(br, f);
+                       fdb_delete_local(br, NULL, f);
                fdb_insert(br, NULL, newaddr, vid);
        }
+out:
+       spin_unlock_bh(&br->hash_lock);
 }
 
 void br_fdb_cleanup(unsigned long _data)
@@ -235,25 +284,11 @@ void br_fdb_delete_by_port(struct net_bridge *br,
 
                        if (f->is_static && !do_all)
                                continue;
-                       /*
-                        * if multiple ports all have the same device address
-                        * then when one port is deleted, assign
-                        * the local entry to other port
-                        */
-                       if (f->is_local) {
-                               struct net_bridge_port *op;
-                               list_for_each_entry(op, &br->port_list, list) {
-                                       if (op != p &&
-                                           ether_addr_equal(op->dev->dev_addr,
-                                                            f->addr.addr)) {
-                                               f->dst = op;
-                                               goto skip_delete;
-                                       }
-                               }
-                       }
 
-                       fdb_delete(br, f);
-               skip_delete: ;
+                       if (f->is_local)
+                               fdb_delete_local(br, p, f);
+                       else
+                               fdb_delete(br, f);
                }
        }
        spin_unlock_bh(&br->hash_lock);
@@ -397,6 +432,7 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
                fdb->vlan_id = vid;
                fdb->is_local = 0;
                fdb->is_static = 0;
+               fdb->added_by_user = 0;
                fdb->updated = fdb->used = jiffies;
                hlist_add_head_rcu(&fdb->hlist, head);
        }
@@ -447,7 +483,7 @@ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
 }
 
 void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
-                  const unsigned char *addr, u16 vid)
+                  const unsigned char *addr, u16 vid, bool added_by_user)
 {
        struct hlist_head *head = &br->hash[br_mac_hash(addr, vid)];
        struct net_bridge_fdb_entry *fdb;
@@ -473,13 +509,18 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
                        /* fastpath: update of existing entry */
                        fdb->dst = source;
                        fdb->updated = jiffies;
+                       if (unlikely(added_by_user))
+                               fdb->added_by_user = 1;
                }
        } else {
                spin_lock(&br->hash_lock);
                if (likely(!fdb_find(head, addr, vid))) {
                        fdb = fdb_create(head, source, addr, vid);
-                       if (fdb)
+                       if (fdb) {
+                               if (unlikely(added_by_user))
+                                       fdb->added_by_user = 1;
                                fdb_notify(br, fdb, RTM_NEWNEIGH);
+                       }
                }
                /* else  we lose race and someone else inserts
                 * it first, don't bother updating
@@ -647,6 +688,7 @@ static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
 
                modified = true;
        }
+       fdb->added_by_user = 1;
 
        fdb->used = jiffies;
        if (modified) {
@@ -664,7 +706,7 @@ static int __br_fdb_add(struct ndmsg *ndm, struct net_bridge_port *p,
 
        if (ndm->ndm_flags & NTF_USE) {
                rcu_read_lock();
-               br_fdb_update(p->br, p, addr, vid);
+               br_fdb_update(p->br, p, addr, vid, true);
                rcu_read_unlock();
        } else {
                spin_lock_bh(&p->br->hash_lock);
@@ -749,8 +791,7 @@ out:
        return err;
 }
 
-int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr,
-                      u16 vlan)
+static int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, u16 vlan)
 {
        struct hlist_head *head = &br->hash[br_mac_hash(addr, vlan)];
        struct net_bridge_fdb_entry *fdb;
index cffe1d666ba11636cc7e3d374018edf7ac31535b..5262b8617eb9cc21b1070e48d1c1efda584aef6f 100644 (file)
@@ -366,7 +366,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (err)
                goto err2;
 
-       err = br_netpoll_enable(p, GFP_KERNEL);
+       err = br_netpoll_enable(p);
        if (err)
                goto err3;
 
@@ -389,6 +389,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (br->dev->needed_headroom < dev->needed_headroom)
                br->dev->needed_headroom = dev->needed_headroom;
 
+       if (br_fdb_insert(br, p, dev->dev_addr, 0))
+               netdev_err(dev, "failed insert local address bridge forwarding table\n");
+
        spin_lock_bh(&br->lock);
        changed_addr = br_stp_recalculate_bridge_id(br);
 
@@ -404,9 +407,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 
        dev_set_mtu(br->dev, br_min_mtu(br));
 
-       if (br_fdb_insert(br, p, dev->dev_addr, 0))
-               netdev_err(dev, "failed insert local address bridge forwarding table\n");
-
        kobject_uevent(&p->kobj, KOBJ_ADD);
 
        return 0;
index bf8dc7d308d6d0b0a092d080723118d327a19b10..d0cca3c65f0174ab8c6522b5f54ab2ad33b66dca 100644 (file)
@@ -29,6 +29,7 @@ static int br_pass_frame_up(struct sk_buff *skb)
        struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
        struct net_bridge *br = netdev_priv(brdev);
        struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
+       struct net_port_vlans *pv;
 
        u64_stats_update_begin(&brstats->syncp);
        brstats->rx_packets++;
@@ -39,18 +40,18 @@ static int br_pass_frame_up(struct sk_buff *skb)
         * packet is allowed except in promisc modue when someone
         * may be running packet capture.
         */
+       pv = br_get_vlan_info(br);
        if (!(brdev->flags & IFF_PROMISC) &&
-           !br_allowed_egress(br, br_get_vlan_info(br), skb)) {
+           !br_allowed_egress(br, pv, skb)) {
                kfree_skb(skb);
                return NET_RX_DROP;
        }
 
-       skb = br_handle_vlan(br, br_get_vlan_info(br), skb);
-       if (!skb)
-               return NET_RX_DROP;
-
        indev = skb->dev;
        skb->dev = brdev;
+       skb = br_handle_vlan(br, pv, skb);
+       if (!skb)
+               return NET_RX_DROP;
 
        return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
                       netif_receive_skb);
@@ -77,7 +78,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
        /* insert into forwarding database after filtering to avoid spoofing */
        br = p->br;
        if (p->flags & BR_LEARNING)
-               br_fdb_update(br, p, eth_hdr(skb)->h_source, vid);
+               br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
 
        if (!is_broadcast_ether_addr(dest) && is_multicast_ether_addr(dest) &&
            br_multicast_rcv(br, p, skb, vid))
@@ -148,7 +149,7 @@ static int br_handle_local_finish(struct sk_buff *skb)
 
        br_vlan_get_tag(skb, &vid);
        if (p->flags & BR_LEARNING)
-               br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid);
+               br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, false);
        return 0;        /* process further */
 }
 
index ef66365b7354da9f2fe2c4d87d2056d9a781f3c8..7b757b5dc773fc2dcaedfa8f7c97e7884a622d89 100644 (file)
@@ -363,7 +363,7 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge *br,
        skb_reset_mac_header(skb);
        eth = eth_hdr(skb);
 
-       memcpy(eth->h_source, br->dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(eth->h_source, br->dev->dev_addr);
        eth->h_dest[0] = 1;
        eth->h_dest[1] = 0;
        eth->h_dest[2] = 0x5e;
@@ -433,7 +433,7 @@ static struct sk_buff *br_ip6_multicast_alloc_query(struct net_bridge *br,
        skb_reset_mac_header(skb);
        eth = eth_hdr(skb);
 
-       memcpy(eth->h_source, br->dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(eth->h_source, br->dev->dev_addr);
        eth->h_proto = htons(ETH_P_IPV6);
        skb_put(skb, sizeof(*eth));
 
@@ -1127,9 +1127,10 @@ static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
                                        struct bridge_mcast_querier *querier,
                                        int saddr,
+                                       bool is_general_query,
                                        unsigned long max_delay)
 {
-       if (saddr)
+       if (saddr && is_general_query)
                br_multicast_update_querier_timer(br, querier, max_delay);
        else if (timer_pending(&querier->timer))
                return;
@@ -1181,8 +1182,16 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer
+        * all-systems destination addresses (224.0.0.1) for general queries
+        */
+       if (!group && iph->daddr != htonl(INADDR_ALLHOSTS_GROUP)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        br_multicast_query_received(br, port, &br->ip4_querier, !!iph->saddr,
-                                   max_delay);
+                                   !group, max_delay);
 
        if (!group)
                goto out;
@@ -1228,6 +1237,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        unsigned long max_delay;
        unsigned long now = jiffies;
        const struct in6_addr *group = NULL;
+       bool is_general_query;
        int err = 0;
 
        spin_lock(&br->multicast_lock);
@@ -1235,6 +1245,12 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */
+       if (!(ipv6_addr_type(&ip6h->saddr) & IPV6_ADDR_LINKLOCAL)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1256,8 +1272,19 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = max(msecs_to_jiffies(mldv2_mrc(mld2q)), 1UL);
        }
 
+       is_general_query = group && ipv6_addr_any(group);
+
+       /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer
+        * all-nodes destination address (ff02::1) for general queries
+        */
+       if (is_general_query && !ipv6_addr_is_ll_all_nodes(&ip6h->daddr)) {
+               err = -EINVAL;
+               goto out;
+       }
+
        br_multicast_query_received(br, port, &br->ip6_querier,
-                                   !ipv6_addr_any(&ip6h->saddr), max_delay);
+                                   !ipv6_addr_any(&ip6h->saddr),
+                                   is_general_query, max_delay);
 
        if (!group)
                goto out;
index b008c59a92c4be8dbc5812606ad76777e17d90ae..80e1b0f60a30214002684a42b1bab1a02e9d9962 100644 (file)
@@ -167,7 +167,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
        rt->dst.dev = br->dev;
        rt->dst.path = &rt->dst;
        dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
-       rt->dst.flags   = DST_NOXFRM | DST_NOPEER | DST_FAKE_RTABLE;
+       rt->dst.flags   = DST_NOXFRM | DST_FAKE_RTABLE;
        rt->dst.ops = &fake_dst_ops;
 }
 
@@ -506,7 +506,7 @@ bridged_dnat:
                                               1);
                                return 0;
                        }
-                       memcpy(eth_hdr(skb)->h_dest, dev->dev_addr, ETH_ALEN);
+                       ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
                        skb->pkt_type = PACKET_HOST;
                }
        } else {
index fcd12333c59b319de7c11c1ddc86214195725e46..06811d79f89f9e7712344d99fdc97194c62f0aef 100644 (file)
@@ -46,12 +46,12 @@ typedef __u16 port_id;
 struct bridge_id
 {
        unsigned char   prio[2];
-       unsigned char   addr[6];
+       unsigned char   addr[ETH_ALEN];
 };
 
 struct mac_addr
 {
-       unsigned char   addr[6];
+       unsigned char   addr[ETH_ALEN];
 };
 
 struct br_ip
@@ -104,6 +104,7 @@ struct net_bridge_fdb_entry
        mac_addr                        addr;
        unsigned char                   is_local;
        unsigned char                   is_static;
+       unsigned char                   added_by_user;
        __u16                           vlan_id;
 };
 
@@ -348,7 +349,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
                netpoll_send_skb(np, skb);
 }
 
-int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp);
+int br_netpoll_enable(struct net_bridge_port *p);
 void br_netpoll_disable(struct net_bridge_port *p);
 #else
 static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
@@ -356,7 +357,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
 {
 }
 
-static inline int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
+static inline int br_netpoll_enable(struct net_bridge_port *p)
 {
        return 0;
 }
@@ -370,6 +371,9 @@ static inline void br_netpoll_disable(struct net_bridge_port *p)
 int br_fdb_init(void);
 void br_fdb_fini(void);
 void br_fdb_flush(struct net_bridge *br);
+void br_fdb_find_delete_local(struct net_bridge *br,
+                             const struct net_bridge_port *p,
+                             const unsigned char *addr, u16 vid);
 void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr);
 void br_fdb_change_mac_address(struct net_bridge *br, const u8 *newaddr);
 void br_fdb_cleanup(unsigned long arg);
@@ -383,8 +387,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, unsigned long count,
 int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
                  const unsigned char *addr, u16 vid);
 void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
-                  const unsigned char *addr, u16 vid);
-int fdb_delete_by_addr(struct net_bridge *br, const u8 *addr, u16 vid);
+                  const unsigned char *addr, u16 vid, bool added_by_user);
 
 int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[],
                  struct net_device *dev, const unsigned char *addr);
@@ -584,6 +587,7 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
 int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags);
 int br_vlan_delete(struct net_bridge *br, u16 vid);
 void br_vlan_flush(struct net_bridge *br);
+bool br_vlan_find(struct net_bridge *br, u16 vid);
 int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
 int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
 int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
@@ -665,6 +669,11 @@ static inline void br_vlan_flush(struct net_bridge *br)
 {
 }
 
+static inline bool br_vlan_find(struct net_bridge *br, u16 vid)
+{
+       return false;
+}
+
 static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
 {
        return -EOPNOTSUPP;
index 656a6f3e40de1b13b9ea7a89373da5d5615e5bb2..189ba1e7d8515945db5593c053b7751d36a02d3b 100644 (file)
@@ -194,6 +194,8 @@ void br_stp_change_bridge_id(struct net_bridge *br, const unsigned char *addr)
 
        wasroot = br_is_root_bridge(br);
 
+       br_fdb_change_mac_address(br, addr);
+
        memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN);
        memcpy(br->bridge_id.addr, addr, ETH_ALEN);
        memcpy(br->dev->dev_addr, addr, ETH_ALEN);
index 4ca4d0a0151c49926dd7e47c6ac5bc8f6b5d28f0..91510712c7a729df3d57c3f118ece9eb3da3fe20 100644 (file)
@@ -99,9 +99,9 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid)
        v->num_vlans--;
        if (bitmap_empty(v->vlan_bitmap, VLAN_N_VID)) {
                if (v->port_idx)
-                       rcu_assign_pointer(v->parent.port->vlan_info, NULL);
+                       RCU_INIT_POINTER(v->parent.port->vlan_info, NULL);
                else
-                       rcu_assign_pointer(v->parent.br->vlan_info, NULL);
+                       RCU_INIT_POINTER(v->parent.br->vlan_info, NULL);
                kfree_rcu(v, rcu);
        }
        return 0;
@@ -113,28 +113,12 @@ static void __vlan_flush(struct net_port_vlans *v)
        v->pvid = 0;
        bitmap_zero(v->vlan_bitmap, VLAN_N_VID);
        if (v->port_idx)
-               rcu_assign_pointer(v->parent.port->vlan_info, NULL);
+               RCU_INIT_POINTER(v->parent.port->vlan_info, NULL);
        else
-               rcu_assign_pointer(v->parent.br->vlan_info, NULL);
+               RCU_INIT_POINTER(v->parent.br->vlan_info, NULL);
        kfree_rcu(v, rcu);
 }
 
-/* Strip the tag from the packet.  Will return skb with tci set 0.  */
-static struct sk_buff *br_vlan_untag(struct sk_buff *skb)
-{
-       if (skb->protocol != htons(ETH_P_8021Q)) {
-               skb->vlan_tci = 0;
-               return skb;
-       }
-
-       skb->vlan_tci = 0;
-       skb = vlan_untag(skb);
-       if (skb)
-               skb->vlan_tci = 0;
-
-       return skb;
-}
-
 struct sk_buff *br_handle_vlan(struct net_bridge *br,
                               const struct net_port_vlans *pv,
                               struct sk_buff *skb)
@@ -144,13 +128,27 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
        if (!br->vlan_enabled)
                goto out;
 
+       /* Vlan filter table must be configured at this point.  The
+        * only exception is the bridge is set in promisc mode and the
+        * packet is destined for the bridge device.  In this case
+        * pass the packet as is.
+        */
+       if (!pv) {
+               if ((br->dev->flags & IFF_PROMISC) && skb->dev == br->dev) {
+                       goto out;
+               } else {
+                       kfree_skb(skb);
+                       return NULL;
+               }
+       }
+
        /* At this point, we know that the frame was filtered and contains
         * a valid vlan id.  If the vlan id is set in the untagged bitmap,
         * send untagged; otherwise, send tagged.
         */
        br_vlan_get_tag(skb, &vid);
        if (test_bit(vid, pv->untagged_bitmap))
-               skb = br_vlan_untag(skb);
+               skb->vlan_tci = 0;
 
 out:
        return skb;
@@ -174,6 +172,18 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
        if (!v)
                return false;
 
+       /* If vlan tx offload is disabled on bridge device and frame was
+        * sent from vlan device on the bridge device, it does not have
+        * HW accelerated vlan tag.
+        */
+       if (unlikely(!vlan_tx_tag_present(skb) &&
+                    (skb->protocol == htons(ETH_P_8021Q) ||
+                     skb->protocol == htons(ETH_P_8021AD)))) {
+               skb = vlan_untag(skb);
+               if (unlikely(!skb))
+                       return false;
+       }
+
        err = br_vlan_get_tag(skb, vid);
        if (!*vid) {
                u16 pvid = br_get_pvid(v);
@@ -275,9 +285,7 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
        if (!pv)
                return -EINVAL;
 
-       spin_lock_bh(&br->hash_lock);
-       fdb_delete_by_addr(br, br->dev->dev_addr, vid);
-       spin_unlock_bh(&br->hash_lock);
+       br_fdb_find_delete_local(br, NULL, br->dev->dev_addr, vid);
 
        __vlan_del(pv, vid);
        return 0;
@@ -295,6 +303,25 @@ void br_vlan_flush(struct net_bridge *br)
        __vlan_flush(pv);
 }
 
+bool br_vlan_find(struct net_bridge *br, u16 vid)
+{
+       struct net_port_vlans *pv;
+       bool found = false;
+
+       rcu_read_lock();
+       pv = rcu_dereference(br->vlan_info);
+
+       if (!pv)
+               goto out;
+
+       if (test_bit(vid, pv->vlan_bitmap))
+               found = true;
+
+out:
+       rcu_read_unlock();
+       return found;
+}
+
 int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
 {
        if (!rtnl_trylock())
@@ -359,9 +386,7 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
        if (!pv)
                return -EINVAL;
 
-       spin_lock_bh(&port->br->hash_lock);
-       fdb_delete_by_addr(port->br, port->dev->dev_addr, vid);
-       spin_unlock_bh(&port->br->hash_lock);
+       br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid);
 
        return __vlan_del(pv, vid);
 }
index 3fb3c848affef74249a1fd9ed610aea7d1db5764..9024283d2bca8206d6976bb7bb72523b514bd68d 100644 (file)
@@ -28,7 +28,7 @@ static bool ebt_mac_wormhash_contains(const struct ebt_mac_wormhash *wh,
        uint32_t cmp[2] = { 0, 0 };
        int key = ((const unsigned char *)mac)[5];
 
-       memcpy(((char *) cmp) + 2, mac, ETH_ALEN);
+       ether_addr_copy(((char *) cmp) + 2, mac);
        start = wh->table[key];
        limit = wh->table[key + 1];
        if (ip) {
index c59f7bfae6e2c3dc8a2e4f3725f43498ae2542a2..4e0b0c3593250bd8a1be0cdafca49ce7e4684f94 100644 (file)
@@ -22,7 +22,7 @@ ebt_dnat_tg(struct sk_buff *skb, const struct xt_action_param *par)
        if (!skb_make_writable(skb, 0))
                return EBT_DROP;
 
-       memcpy(eth_hdr(skb)->h_dest, info->mac, ETH_ALEN);
+       ether_addr_copy(eth_hdr(skb)->h_dest, info->mac);
        return info->target;
 }
 
index 46624bb6d9be5f0ca26b2b845f44f1a857499291..203964997a515a6bc4d961e59b365a5354df6518 100644 (file)
@@ -25,10 +25,10 @@ ebt_redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
 
        if (par->hooknum != NF_BR_BROUTING)
                /* rcu_read_lock()ed by nf_hook_slow */
-               memcpy(eth_hdr(skb)->h_dest,
-                      br_port_get_rcu(par->in)->br->dev->dev_addr, ETH_ALEN);
+               ether_addr_copy(eth_hdr(skb)->h_dest,
+                               br_port_get_rcu(par->in)->br->dev->dev_addr);
        else
-               memcpy(eth_hdr(skb)->h_dest, par->in->dev_addr, ETH_ALEN);
+               ether_addr_copy(eth_hdr(skb)->h_dest, par->in->dev_addr);
        skb->pkt_type = PACKET_HOST;
        return info->target;
 }
index 0f6b118d6cb21cc19c891c37d974ddd4ad2bcd6a..e56ccd060d2680da042322cea43177a27744b7ca 100644 (file)
@@ -24,7 +24,7 @@ ebt_snat_tg(struct sk_buff *skb, const struct xt_action_param *par)
        if (!skb_make_writable(skb, 0))
                return EBT_DROP;
 
-       memcpy(eth_hdr(skb)->h_source, info->mac, ETH_ALEN);
+       ether_addr_copy(eth_hdr(skb)->h_source, info->mac);
        if (!(info->target & NAT_ARP_BIT) &&
            eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) {
                const struct arphdr *ap;
index 4dca159435cfe17dcc09fadccfebee7ca49b1075..edbca468fa73cc29b31703bd4fe4d70925f21bd5 100644 (file)
@@ -22,6 +22,7 @@
 #include <net/pkt_sched.h>
 #include <net/caif/caif_device.h>
 #include <net/caif/caif_layer.h>
+#include <net/caif/caif_dev.h>
 #include <net/caif/cfpkt.h>
 #include <net/caif/cfcnfg.h>
 #include <net/caif/cfserl.h>
index 353f793d1b3bb7285d466f0f67f3bc6023e10e49..a6e115463052ac72431fb8680bcedb3969dd1aff 100644 (file)
@@ -15,6 +15,7 @@
 #include <net/caif/caif_layer.h>
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
+#include <net/caif/caif_dev.h>
 
 #define SRVL_CTRL_PKT_SIZE 1
 #define SRVL_FLOW_OFF 0x81
index d249874a366d363edfc94adc47df54dde6bdba0e..a27f8aad9e991f95cc5366bce3e975bff4f16bdd 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/skbuff.h>
 #include <linux/can.h>
 #include <linux/can/core.h>
+#include <linux/can/skb.h>
 #include <linux/ratelimit.h>
 #include <net/net_namespace.h>
 #include <net/sock.h>
@@ -290,7 +291,7 @@ int can_send(struct sk_buff *skb, int loop)
                                return -ENOMEM;
                        }
 
-                       newskb->sk = skb->sk;
+                       can_skb_set_owner(newskb, skb->sk);
                        newskb->ip_summed = CHECKSUM_UNNECESSARY;
                        newskb->pkt_type = PACKET_BROADCAST;
                }
index 3fc737b214c78effe8b83a4fed649d8109274737..dcb75c0e66c1b69979a88c65efe43084046f8bc2 100644 (file)
@@ -268,7 +268,7 @@ static void bcm_can_tx(struct bcm_op *op)
 
        /* send with loopback */
        skb->dev = dev;
-       skb->sk = op->sk;
+       can_skb_set_owner(skb, op->sk);
        can_send(skb, 1);
 
        /* update statistics */
@@ -1223,7 +1223,7 @@ static int bcm_tx_send(struct msghdr *msg, int ifindex, struct sock *sk)
 
        can_skb_prv(skb)->ifindex = dev->ifindex;
        skb->dev = dev;
-       skb->sk  = sk;
+       can_skb_set_owner(skb, sk);
        err = can_send(skb, 1); /* send with loopback */
        dev_put(dev);
 
index 07d72d852324f23a8fffdc71798e89602b861977..081e81fd017fa53f7a6ed3afd341601b43377531 100644 (file)
@@ -121,13 +121,9 @@ static void raw_rcv(struct sk_buff *oskb, void *data)
        if (!ro->recv_own_msgs && oskb->sk == sk)
                return;
 
-       /* do not pass frames with DLC > 8 to a legacy socket */
-       if (!ro->fd_frames) {
-               struct canfd_frame *cfd = (struct canfd_frame *)oskb->data;
-
-               if (unlikely(cfd->len > CAN_MAX_DLEN))
-                       return;
-       }
+       /* do not pass non-CAN2.0 frames to a legacy socket */
+       if (!ro->fd_frames && oskb->len != CAN_MTU)
+               return;
 
        /* clone the given skb to be able to enqueue it into the rcv queue */
        skb = skb_clone(oskb, GFP_ATOMIC);
@@ -715,6 +711,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        skb->dev = dev;
        skb->sk  = sk;
+       skb->priority = sk->sk_priority;
 
        err = can_send(skb, ro->loopback);
 
@@ -737,9 +734,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
                       struct msghdr *msg, size_t size, int flags)
 {
        struct sock *sk = sock->sk;
-       struct raw_sock *ro = raw_sk(sk);
        struct sk_buff *skb;
-       int rxmtu;
        int err = 0;
        int noblock;
 
@@ -750,20 +745,10 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (!skb)
                return err;
 
-       /*
-        * when serving a legacy socket the DLC <= 8 is already checked inside
-        * raw_rcv(). Now check if we need to pass a canfd_frame to a legacy
-        * socket and cut the possible CANFD_MTU/CAN_MTU length to CAN_MTU
-        */
-       if (!ro->fd_frames)
-               rxmtu = CAN_MTU;
-       else
-               rxmtu = skb->len;
-
-       if (size < rxmtu)
+       if (size < skb->len)
                msg->msg_flags |= MSG_TRUNC;
        else
-               size = rxmtu;
+               size = skb->len;
 
        err = memcpy_toiovec(msg->msg_iov, skb->data, size);
        if (err < 0) {
index 0676f2b199d672eaf61157cdf78b75ee74afb434..82750f9158655225ad7dab9e903932d38f97b8a5 100644 (file)
@@ -2082,7 +2082,6 @@ bad:
        pr_err("osdc handle_map corrupt msg\n");
        ceph_msg_dump(msg);
        up_write(&osdc->map_sem);
-       return;
 }
 
 /*
@@ -2281,7 +2280,6 @@ done_err:
 
 bad:
        pr_err("osdc handle_watch_notify corrupt msg\n");
-       return;
 }
 
 /*
index 3721db71635051f82a4ace0d24e669156c1a8783..cf92139b229c965b0dd29c85ba0d60b941ee7b3f 100644 (file)
@@ -1245,7 +1245,7 @@ static int __dev_open(struct net_device *dev)
         * If we don't do this there is a chance ndo_poll_controller
         * or ndo_poll may be running while we open the device
         */
-       netpoll_rx_disable(dev);
+       netpoll_poll_disable(dev);
 
        ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev);
        ret = notifier_to_errno(ret);
@@ -1260,7 +1260,7 @@ static int __dev_open(struct net_device *dev)
        if (!ret && ops->ndo_open)
                ret = ops->ndo_open(dev);
 
-       netpoll_rx_enable(dev);
+       netpoll_poll_enable(dev);
 
        if (ret)
                clear_bit(__LINK_STATE_START, &dev->state);
@@ -1313,6 +1313,9 @@ static int __dev_close_many(struct list_head *head)
        might_sleep();
 
        list_for_each_entry(dev, head, close_list) {
+               /* Temporarily disable netpoll until the interface is down */
+               netpoll_poll_disable(dev);
+
                call_netdevice_notifiers(NETDEV_GOING_DOWN, dev);
 
                clear_bit(__LINK_STATE_START, &dev->state);
@@ -1343,6 +1346,7 @@ static int __dev_close_many(struct list_head *head)
 
                dev->flags &= ~IFF_UP;
                net_dmaengine_put();
+               netpoll_poll_enable(dev);
        }
 
        return 0;
@@ -1353,14 +1357,10 @@ static int __dev_close(struct net_device *dev)
        int retval;
        LIST_HEAD(single);
 
-       /* Temporarily disable netpoll until the interface is down */
-       netpoll_rx_disable(dev);
-
        list_add(&dev->close_list, &single);
        retval = __dev_close_many(&single);
        list_del(&single);
 
-       netpoll_rx_enable(dev);
        return retval;
 }
 
@@ -1398,14 +1398,9 @@ int dev_close(struct net_device *dev)
        if (dev->flags & IFF_UP) {
                LIST_HEAD(single);
 
-               /* Block netpoll rx while the interface is going down */
-               netpoll_rx_disable(dev);
-
                list_add(&dev->close_list, &single);
                dev_close_many(&single);
                list_del(&single);
-
-               netpoll_rx_enable(dev);
        }
        return 0;
 }
@@ -2286,7 +2281,7 @@ out:
 }
 EXPORT_SYMBOL(skb_checksum_help);
 
-__be16 skb_network_protocol(struct sk_buff *skb)
+__be16 skb_network_protocol(struct sk_buff *skb, int *depth)
 {
        __be16 type = skb->protocol;
        int vlan_depth = ETH_HLEN;
@@ -2313,6 +2308,8 @@ __be16 skb_network_protocol(struct sk_buff *skb)
                vlan_depth += VLAN_HLEN;
        }
 
+       *depth = vlan_depth;
+
        return type;
 }
 
@@ -2326,12 +2323,13 @@ struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb,
 {
        struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
        struct packet_offload *ptype;
-       __be16 type = skb_network_protocol(skb);
+       int vlan_depth = skb->mac_len;
+       __be16 type = skb_network_protocol(skb, &vlan_depth);
 
        if (unlikely(!type))
                return ERR_PTR(-EINVAL);
 
-       __skb_pull(skb, skb->mac_len);
+       __skb_pull(skb, vlan_depth);
 
        rcu_read_lock();
        list_for_each_entry_rcu(ptype, &offload_base, list) {
@@ -2420,7 +2418,7 @@ EXPORT_SYMBOL(netdev_rx_csum_fault);
  * 2. No high memory really exists on this machine.
  */
 
-static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
+static int illegal_highdma(const struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_HIGHMEM
        int i;
@@ -2495,34 +2493,38 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features)
 }
 
 static netdev_features_t harmonize_features(struct sk_buff *skb,
-       netdev_features_t features)
+                                           const struct net_device *dev,
+                                           netdev_features_t features)
 {
+       int tmp;
+
        if (skb->ip_summed != CHECKSUM_NONE &&
-           !can_checksum_protocol(features, skb_network_protocol(skb))) {
+           !can_checksum_protocol(features, skb_network_protocol(skb, &tmp))) {
                features &= ~NETIF_F_ALL_CSUM;
-       } else if (illegal_highdma(skb->dev, skb)) {
+       } else if (illegal_highdma(dev, skb)) {
                features &= ~NETIF_F_SG;
        }
 
        return features;
 }
 
-netdev_features_t netif_skb_features(struct sk_buff *skb)
+netdev_features_t netif_skb_dev_features(struct sk_buff *skb,
+                                        const struct net_device *dev)
 {
        __be16 protocol = skb->protocol;
-       netdev_features_t features = skb->dev->features;
+       netdev_features_t features = dev->features;
 
-       if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
+       if (skb_shinfo(skb)->gso_segs > dev->gso_max_segs)
                features &= ~NETIF_F_GSO_MASK;
 
        if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) {
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
                protocol = veh->h_vlan_encapsulated_proto;
        } else if (!vlan_tx_tag_present(skb)) {
-               return harmonize_features(skb, features);
+               return harmonize_features(skb, dev, features);
        }
 
-       features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
+       features &= (dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX |
                                               NETIF_F_HW_VLAN_STAG_TX);
 
        if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD))
@@ -2530,9 +2532,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
                                NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX |
                                NETIF_F_HW_VLAN_STAG_TX;
 
-       return harmonize_features(skb, features);
+       return harmonize_features(skb, dev, features);
 }
-EXPORT_SYMBOL(netif_skb_features);
+EXPORT_SYMBOL(netif_skb_dev_features);
 
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        struct netdev_queue *txq)
@@ -2803,7 +2805,7 @@ EXPORT_SYMBOL(dev_loopback_xmit);
  *      the BH enable code must have IRQs enabled so that it will not deadlock.
  *          --BLG
  */
-int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
+static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv)
 {
        struct net_device *dev = skb->dev;
        struct netdev_queue *txq;
@@ -2878,6 +2880,7 @@ recursion_alert:
        rc = -ENETDOWN;
        rcu_read_unlock_bh();
 
+       atomic_long_inc(&dev->tx_dropped);
        kfree_skb(skb);
        return rc;
 out:
@@ -2950,7 +2953,7 @@ set_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                flow_table = rcu_dereference(rxqueue->rps_flow_table);
                if (!flow_table)
                        goto out;
-               flow_id = skb->rxhash & flow_table->mask;
+               flow_id = skb_get_hash(skb) & flow_table->mask;
                rc = dev->netdev_ops->ndo_rx_flow_steer(dev, skb,
                                                        rxq_index, flow_id);
                if (rc < 0)
@@ -2984,6 +2987,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        struct rps_sock_flow_table *sock_flow_table;
        int cpu = -1;
        u16 tcpu;
+       u32 hash;
 
        if (skb_rx_queue_recorded(skb)) {
                u16 index = skb_get_rx_queue(skb);
@@ -3012,7 +3016,8 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        }
 
        skb_reset_network_header(skb);
-       if (!skb_get_hash(skb))
+       hash = skb_get_hash(skb);
+       if (!hash)
                goto done;
 
        flow_table = rcu_dereference(rxqueue->rps_flow_table);
@@ -3021,11 +3026,10 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                u16 next_cpu;
                struct rps_dev_flow *rflow;
 
-               rflow = &flow_table->flows[skb->rxhash & flow_table->mask];
+               rflow = &flow_table->flows[hash & flow_table->mask];
                tcpu = rflow->cpu;
 
-               next_cpu = sock_flow_table->ents[skb->rxhash &
-                   sock_flow_table->mask];
+               next_cpu = sock_flow_table->ents[hash & sock_flow_table->mask];
 
                /*
                 * If the desired CPU (where last recvmsg was done) is
@@ -3054,7 +3058,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
        }
 
        if (map) {
-               tcpu = map->cpus[((u64) skb->rxhash * map->len) >> 32];
+               tcpu = map->cpus[((u64) hash * map->len) >> 32];
 
                if (cpu_online(tcpu)) {
                        cpu = tcpu;
@@ -3229,10 +3233,6 @@ static int netif_rx_internal(struct sk_buff *skb)
 {
        int ret;
 
-       /* if netpoll wants it, pretend we never saw it */
-       if (netpoll_rx(skb))
-               return NET_RX_DROP;
-
        net_timestamp_check(netdev_tstamp_prequeue, skb);
 
        trace_netif_rx(skb);
@@ -3493,11 +3493,11 @@ EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
 static bool skb_pfmemalloc_protocol(struct sk_buff *skb)
 {
        switch (skb->protocol) {
-       case __constant_htons(ETH_P_ARP):
-       case __constant_htons(ETH_P_IP):
-       case __constant_htons(ETH_P_IPV6):
-       case __constant_htons(ETH_P_8021Q):
-       case __constant_htons(ETH_P_8021AD):
+       case htons(ETH_P_ARP):
+       case htons(ETH_P_IP):
+       case htons(ETH_P_IPV6):
+       case htons(ETH_P_8021Q):
+       case htons(ETH_P_8021AD):
                return true;
        default:
                return false;
@@ -3518,10 +3518,6 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
 
        trace_netif_receive_skb(skb);
 
-       /* if we've gotten here through NAPI, check netpoll */
-       if (netpoll_receive_skb(skb))
-               goto out;
-
        orig_dev = skb->dev;
 
        skb_reset_network_header(skb);
@@ -3648,7 +3644,6 @@ drop:
 
 unlock:
        rcu_read_unlock();
-out:
        return ret;
 }
 
@@ -3873,7 +3868,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
        int same_flow;
        enum gro_result ret;
 
-       if (!(skb->dev->features & NETIF_F_GRO) || netpoll_rx_on(skb))
+       if (!(skb->dev->features & NETIF_F_GRO))
                goto normal;
 
        if (skb_is_gso(skb) || skb_has_frag_list(skb))
@@ -4637,7 +4632,7 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev)
 }
 EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu);
 
-int netdev_adjacent_sysfs_add(struct net_device *dev,
+static int netdev_adjacent_sysfs_add(struct net_device *dev,
                              struct net_device *adj_dev,
                              struct list_head *dev_list)
 {
@@ -4647,7 +4642,7 @@ int netdev_adjacent_sysfs_add(struct net_device *dev,
        return sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj),
                                 linkname);
 }
-void netdev_adjacent_sysfs_del(struct net_device *dev,
+static void netdev_adjacent_sysfs_del(struct net_device *dev,
                               char *name,
                               struct list_head *dev_list)
 {
@@ -6244,6 +6239,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
                netdev_stats_to_stats64(storage, &dev->stats);
        }
        storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
+       storage->tx_dropped += atomic_long_read(&dev->tx_dropped);
        return storage;
 }
 EXPORT_SYMBOL(dev_get_stats);
index f409e0bd35c06456f4877d10d98c342f52362d84..185c341fafbd079714fe3a563b8209d5c5f7ead4 100644 (file)
@@ -745,6 +745,13 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
                        attach_rules(&ops->rules_list, dev);
                break;
 
+       case NETDEV_CHANGENAME:
+               list_for_each_entry(ops, &net->rules_ops, list) {
+                       detach_rules(&ops->rules_list, dev);
+                       attach_rules(&ops->rules_list, dev);
+               }
+               break;
+
        case NETDEV_UNREGISTER:
                list_for_each_entry(ops, &net->rules_ops, list)
                        detach_rules(&ops->rules_list, dev);
index ad30d626a5bd3f5cbd585d0641ab79aa29c3c446..3733381190ec23c5b0e0a5fd181cab27a8bdb312 100644 (file)
@@ -1,11 +1,16 @@
 /*
  * Linux Socket Filter - Kernel level socket filtering
  *
- * Author:
- *     Jay Schulist <jschlst@samba.org>
+ * Based on the design of the Berkeley Packet Filter. The new
+ * internal format has been designed by PLUMgrid:
  *
- * Based on the design of:
- *     - The Berkeley Packet Filter
+ *     Copyright (c) 2011 - 2014 PLUMgrid, http://plumgrid.com
+ *
+ * Authors:
+ *
+ *     Jay Schulist <jschlst@samba.org>
+ *     Alexei Starovoitov <ast@plumgrid.com>
+ *     Daniel Borkmann <dborkman@redhat.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -108,304 +113,1045 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(sk_filter);
 
+/* Base function for offset calculation. Needs to go into .text section,
+ * therefore keeping it non-static as well; will also be used by JITs
+ * anyway later on, so do not let the compiler omit it.
+ */
+noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
+{
+       return 0;
+}
+
 /**
- *     sk_run_filter - run a filter on a socket
- *     @skb: buffer to run the filter on
+ *     __sk_run_filter - run a filter on a given context
+ *     @ctx: buffer to run the filter on
  *     @fentry: filter to apply
  *
- * Decode and apply filter instructions to the skb->data.
- * Return length to keep, 0 for none. @skb is the data we are
- * filtering, @filter is the array of filter instructions.
- * Because all jumps are guaranteed to be before last instruction,
- * and last instruction guaranteed to be a RET, we dont need to check
- * flen. (We used to pass to this function the length of filter)
+ * Decode and apply filter instructions to the skb->data. Return length to
+ * keep, 0 for none. @ctx is the data we are operating on, @filter is the
+ * array of filter instructions.
  */
-unsigned int sk_run_filter(const struct sk_buff *skb,
-                          const struct sock_filter *fentry)
+unsigned int __sk_run_filter(void *ctx, const struct sock_filter_int *insn)
 {
+       u64 stack[MAX_BPF_STACK / sizeof(u64)];
+       u64 regs[MAX_BPF_REG], tmp;
        void *ptr;
-       u32 A = 0;                      /* Accumulator */
-       u32 X = 0;                      /* Index Register */
-       u32 mem[BPF_MEMWORDS];          /* Scratch Memory Store */
-       u32 tmp;
-       int k;
+       int off;
 
-       /*
-        * Process array of filter instructions.
-        */
-       for (;; fentry++) {
-#if defined(CONFIG_X86_32)
-#define        K (fentry->k)
-#else
-               const u32 K = fentry->k;
-#endif
-
-               switch (fentry->code) {
-               case BPF_S_ALU_ADD_X:
-                       A += X;
-                       continue;
-               case BPF_S_ALU_ADD_K:
-                       A += K;
-                       continue;
-               case BPF_S_ALU_SUB_X:
-                       A -= X;
-                       continue;
-               case BPF_S_ALU_SUB_K:
-                       A -= K;
-                       continue;
-               case BPF_S_ALU_MUL_X:
-                       A *= X;
-                       continue;
-               case BPF_S_ALU_MUL_K:
-                       A *= K;
-                       continue;
-               case BPF_S_ALU_DIV_X:
-                       if (X == 0)
-                               return 0;
-                       A /= X;
-                       continue;
-               case BPF_S_ALU_DIV_K:
-                       A /= K;
-                       continue;
-               case BPF_S_ALU_MOD_X:
-                       if (X == 0)
-                               return 0;
-                       A %= X;
-                       continue;
-               case BPF_S_ALU_MOD_K:
-                       A %= K;
-                       continue;
-               case BPF_S_ALU_AND_X:
-                       A &= X;
-                       continue;
-               case BPF_S_ALU_AND_K:
-                       A &= K;
-                       continue;
-               case BPF_S_ALU_OR_X:
-                       A |= X;
-                       continue;
-               case BPF_S_ALU_OR_K:
-                       A |= K;
-                       continue;
-               case BPF_S_ANC_ALU_XOR_X:
-               case BPF_S_ALU_XOR_X:
-                       A ^= X;
-                       continue;
-               case BPF_S_ALU_XOR_K:
-                       A ^= K;
-                       continue;
-               case BPF_S_ALU_LSH_X:
-                       A <<= X;
-                       continue;
-               case BPF_S_ALU_LSH_K:
-                       A <<= K;
-                       continue;
-               case BPF_S_ALU_RSH_X:
-                       A >>= X;
-                       continue;
-               case BPF_S_ALU_RSH_K:
-                       A >>= K;
-                       continue;
-               case BPF_S_ALU_NEG:
-                       A = -A;
-                       continue;
-               case BPF_S_JMP_JA:
-                       fentry += K;
-                       continue;
-               case BPF_S_JMP_JGT_K:
-                       fentry += (A > K) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JGE_K:
-                       fentry += (A >= K) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JEQ_K:
-                       fentry += (A == K) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JSET_K:
-                       fentry += (A & K) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JGT_X:
-                       fentry += (A > X) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JGE_X:
-                       fentry += (A >= X) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JEQ_X:
-                       fentry += (A == X) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_JMP_JSET_X:
-                       fentry += (A & X) ? fentry->jt : fentry->jf;
-                       continue;
-               case BPF_S_LD_W_ABS:
-                       k = K;
-load_w:
-                       ptr = load_pointer(skb, k, 4, &tmp);
-                       if (ptr != NULL) {
-                               A = get_unaligned_be32(ptr);
-                               continue;
-                       }
-                       return 0;
-               case BPF_S_LD_H_ABS:
-                       k = K;
-load_h:
-                       ptr = load_pointer(skb, k, 2, &tmp);
-                       if (ptr != NULL) {
-                               A = get_unaligned_be16(ptr);
-                               continue;
+#define K  insn->imm
+#define A  regs[insn->a_reg]
+#define X  regs[insn->x_reg]
+#define R0 regs[0]
+
+#define CONT    ({insn++; goto select_insn; })
+#define CONT_JMP ({insn++; goto select_insn; })
+
+       static const void *jumptable[256] = {
+               [0 ... 255] = &&default_label,
+               /* Now overwrite non-defaults ... */
+#define DL(A, B, C)    [A|B|C] = &&A##_##B##_##C
+               DL(BPF_ALU, BPF_ADD, BPF_X),
+               DL(BPF_ALU, BPF_ADD, BPF_K),
+               DL(BPF_ALU, BPF_SUB, BPF_X),
+               DL(BPF_ALU, BPF_SUB, BPF_K),
+               DL(BPF_ALU, BPF_AND, BPF_X),
+               DL(BPF_ALU, BPF_AND, BPF_K),
+               DL(BPF_ALU, BPF_OR, BPF_X),
+               DL(BPF_ALU, BPF_OR, BPF_K),
+               DL(BPF_ALU, BPF_LSH, BPF_X),
+               DL(BPF_ALU, BPF_LSH, BPF_K),
+               DL(BPF_ALU, BPF_RSH, BPF_X),
+               DL(BPF_ALU, BPF_RSH, BPF_K),
+               DL(BPF_ALU, BPF_XOR, BPF_X),
+               DL(BPF_ALU, BPF_XOR, BPF_K),
+               DL(BPF_ALU, BPF_MUL, BPF_X),
+               DL(BPF_ALU, BPF_MUL, BPF_K),
+               DL(BPF_ALU, BPF_MOV, BPF_X),
+               DL(BPF_ALU, BPF_MOV, BPF_K),
+               DL(BPF_ALU, BPF_DIV, BPF_X),
+               DL(BPF_ALU, BPF_DIV, BPF_K),
+               DL(BPF_ALU, BPF_MOD, BPF_X),
+               DL(BPF_ALU, BPF_MOD, BPF_K),
+               DL(BPF_ALU, BPF_NEG, 0),
+               DL(BPF_ALU, BPF_END, BPF_TO_BE),
+               DL(BPF_ALU, BPF_END, BPF_TO_LE),
+               DL(BPF_ALU64, BPF_ADD, BPF_X),
+               DL(BPF_ALU64, BPF_ADD, BPF_K),
+               DL(BPF_ALU64, BPF_SUB, BPF_X),
+               DL(BPF_ALU64, BPF_SUB, BPF_K),
+               DL(BPF_ALU64, BPF_AND, BPF_X),
+               DL(BPF_ALU64, BPF_AND, BPF_K),
+               DL(BPF_ALU64, BPF_OR, BPF_X),
+               DL(BPF_ALU64, BPF_OR, BPF_K),
+               DL(BPF_ALU64, BPF_LSH, BPF_X),
+               DL(BPF_ALU64, BPF_LSH, BPF_K),
+               DL(BPF_ALU64, BPF_RSH, BPF_X),
+               DL(BPF_ALU64, BPF_RSH, BPF_K),
+               DL(BPF_ALU64, BPF_XOR, BPF_X),
+               DL(BPF_ALU64, BPF_XOR, BPF_K),
+               DL(BPF_ALU64, BPF_MUL, BPF_X),
+               DL(BPF_ALU64, BPF_MUL, BPF_K),
+               DL(BPF_ALU64, BPF_MOV, BPF_X),
+               DL(BPF_ALU64, BPF_MOV, BPF_K),
+               DL(BPF_ALU64, BPF_ARSH, BPF_X),
+               DL(BPF_ALU64, BPF_ARSH, BPF_K),
+               DL(BPF_ALU64, BPF_DIV, BPF_X),
+               DL(BPF_ALU64, BPF_DIV, BPF_K),
+               DL(BPF_ALU64, BPF_MOD, BPF_X),
+               DL(BPF_ALU64, BPF_MOD, BPF_K),
+               DL(BPF_ALU64, BPF_NEG, 0),
+               DL(BPF_JMP, BPF_CALL, 0),
+               DL(BPF_JMP, BPF_JA, 0),
+               DL(BPF_JMP, BPF_JEQ, BPF_X),
+               DL(BPF_JMP, BPF_JEQ, BPF_K),
+               DL(BPF_JMP, BPF_JNE, BPF_X),
+               DL(BPF_JMP, BPF_JNE, BPF_K),
+               DL(BPF_JMP, BPF_JGT, BPF_X),
+               DL(BPF_JMP, BPF_JGT, BPF_K),
+               DL(BPF_JMP, BPF_JGE, BPF_X),
+               DL(BPF_JMP, BPF_JGE, BPF_K),
+               DL(BPF_JMP, BPF_JSGT, BPF_X),
+               DL(BPF_JMP, BPF_JSGT, BPF_K),
+               DL(BPF_JMP, BPF_JSGE, BPF_X),
+               DL(BPF_JMP, BPF_JSGE, BPF_K),
+               DL(BPF_JMP, BPF_JSET, BPF_X),
+               DL(BPF_JMP, BPF_JSET, BPF_K),
+               DL(BPF_JMP, BPF_EXIT, 0),
+               DL(BPF_STX, BPF_MEM, BPF_B),
+               DL(BPF_STX, BPF_MEM, BPF_H),
+               DL(BPF_STX, BPF_MEM, BPF_W),
+               DL(BPF_STX, BPF_MEM, BPF_DW),
+               DL(BPF_STX, BPF_XADD, BPF_W),
+               DL(BPF_STX, BPF_XADD, BPF_DW),
+               DL(BPF_ST, BPF_MEM, BPF_B),
+               DL(BPF_ST, BPF_MEM, BPF_H),
+               DL(BPF_ST, BPF_MEM, BPF_W),
+               DL(BPF_ST, BPF_MEM, BPF_DW),
+               DL(BPF_LDX, BPF_MEM, BPF_B),
+               DL(BPF_LDX, BPF_MEM, BPF_H),
+               DL(BPF_LDX, BPF_MEM, BPF_W),
+               DL(BPF_LDX, BPF_MEM, BPF_DW),
+               DL(BPF_LD, BPF_ABS, BPF_W),
+               DL(BPF_LD, BPF_ABS, BPF_H),
+               DL(BPF_LD, BPF_ABS, BPF_B),
+               DL(BPF_LD, BPF_IND, BPF_W),
+               DL(BPF_LD, BPF_IND, BPF_H),
+               DL(BPF_LD, BPF_IND, BPF_B),
+#undef DL
+       };
+
+       regs[FP_REG]  = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)];
+       regs[ARG1_REG] = (u64) (unsigned long) ctx;
+
+select_insn:
+       goto *jumptable[insn->code];
+
+       /* ALU */
+#define ALU(OPCODE, OP)                        \
+       BPF_ALU64_##OPCODE##_BPF_X:     \
+               A = A OP X;             \
+               CONT;                   \
+       BPF_ALU_##OPCODE##_BPF_X:       \
+               A = (u32) A OP (u32) X; \
+               CONT;                   \
+       BPF_ALU64_##OPCODE##_BPF_K:     \
+               A = A OP K;             \
+               CONT;                   \
+       BPF_ALU_##OPCODE##_BPF_K:       \
+               A = (u32) A OP (u32) K; \
+               CONT;
+
+       ALU(BPF_ADD,  +)
+       ALU(BPF_SUB,  -)
+       ALU(BPF_AND,  &)
+       ALU(BPF_OR,   |)
+       ALU(BPF_LSH, <<)
+       ALU(BPF_RSH, >>)
+       ALU(BPF_XOR,  ^)
+       ALU(BPF_MUL,  *)
+#undef ALU
+       BPF_ALU_BPF_NEG_0:
+               A = (u32) -A;
+               CONT;
+       BPF_ALU64_BPF_NEG_0:
+               A = -A;
+               CONT;
+       BPF_ALU_BPF_MOV_BPF_X:
+               A = (u32) X;
+               CONT;
+       BPF_ALU_BPF_MOV_BPF_K:
+               A = (u32) K;
+               CONT;
+       BPF_ALU64_BPF_MOV_BPF_X:
+               A = X;
+               CONT;
+       BPF_ALU64_BPF_MOV_BPF_K:
+               A = K;
+               CONT;
+       BPF_ALU64_BPF_ARSH_BPF_X:
+               (*(s64 *) &A) >>= X;
+               CONT;
+       BPF_ALU64_BPF_ARSH_BPF_K:
+               (*(s64 *) &A) >>= K;
+               CONT;
+       BPF_ALU64_BPF_MOD_BPF_X:
+               tmp = A;
+               if (X)
+                       A = do_div(tmp, X);
+               CONT;
+       BPF_ALU_BPF_MOD_BPF_X:
+               tmp = (u32) A;
+               if (X)
+                       A = do_div(tmp, (u32) X);
+               CONT;
+       BPF_ALU64_BPF_MOD_BPF_K:
+               tmp = A;
+               if (K)
+                       A = do_div(tmp, K);
+               CONT;
+       BPF_ALU_BPF_MOD_BPF_K:
+               tmp = (u32) A;
+               if (K)
+                       A = do_div(tmp, (u32) K);
+               CONT;
+       BPF_ALU64_BPF_DIV_BPF_X:
+               if (X)
+                       do_div(A, X);
+               CONT;
+       BPF_ALU_BPF_DIV_BPF_X:
+               tmp = (u32) A;
+               if (X)
+                       do_div(tmp, (u32) X);
+               A = (u32) tmp;
+               CONT;
+       BPF_ALU64_BPF_DIV_BPF_K:
+               if (K)
+                       do_div(A, K);
+               CONT;
+       BPF_ALU_BPF_DIV_BPF_K:
+               tmp = (u32) A;
+               if (K)
+                       do_div(tmp, (u32) K);
+               A = (u32) tmp;
+               CONT;
+       BPF_ALU_BPF_END_BPF_TO_BE:
+               switch (K) {
+               case 16:
+                       A = (__force u16) cpu_to_be16(A);
+                       break;
+               case 32:
+                       A = (__force u32) cpu_to_be32(A);
+                       break;
+               case 64:
+                       A = (__force u64) cpu_to_be64(A);
+                       break;
+               }
+               CONT;
+       BPF_ALU_BPF_END_BPF_TO_LE:
+               switch (K) {
+               case 16:
+                       A = (__force u16) cpu_to_le16(A);
+                       break;
+               case 32:
+                       A = (__force u32) cpu_to_le32(A);
+                       break;
+               case 64:
+                       A = (__force u64) cpu_to_le64(A);
+                       break;
+               }
+               CONT;
+
+       /* CALL */
+       BPF_JMP_BPF_CALL_0:
+               /* Function call scratches R1-R5 registers, preserves R6-R9,
+                * and stores return value into R0.
+                */
+               R0 = (__bpf_call_base + insn->imm)(regs[1], regs[2], regs[3],
+                                                  regs[4], regs[5]);
+               CONT;
+
+       /* JMP */
+       BPF_JMP_BPF_JA_0:
+               insn += insn->off;
+               CONT;
+       BPF_JMP_BPF_JEQ_BPF_X:
+               if (A == X) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JEQ_BPF_K:
+               if (A == K) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JNE_BPF_X:
+               if (A != X) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JNE_BPF_K:
+               if (A != K) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JGT_BPF_X:
+               if (A > X) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JGT_BPF_K:
+               if (A > K) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JGE_BPF_X:
+               if (A >= X) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JGE_BPF_K:
+               if (A >= K) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JSGT_BPF_X:
+               if (((s64)A) > ((s64)X)) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JSGT_BPF_K:
+               if (((s64)A) > ((s64)K)) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JSGE_BPF_X:
+               if (((s64)A) >= ((s64)X)) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JSGE_BPF_K:
+               if (((s64)A) >= ((s64)K)) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JSET_BPF_X:
+               if (A & X) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_JSET_BPF_K:
+               if (A & K) {
+                       insn += insn->off;
+                       CONT_JMP;
+               }
+               CONT;
+       BPF_JMP_BPF_EXIT_0:
+               return R0;
+
+       /* STX and ST and LDX*/
+#define LDST(SIZEOP, SIZE)                                     \
+       BPF_STX_BPF_MEM_##SIZEOP:                               \
+               *(SIZE *)(unsigned long) (A + insn->off) = X;   \
+               CONT;                                           \
+       BPF_ST_BPF_MEM_##SIZEOP:                                \
+               *(SIZE *)(unsigned long) (A + insn->off) = K;   \
+               CONT;                                           \
+       BPF_LDX_BPF_MEM_##SIZEOP:                               \
+               A = *(SIZE *)(unsigned long) (X + insn->off);   \
+               CONT;
+
+       LDST(BPF_B,   u8)
+       LDST(BPF_H,  u16)
+       LDST(BPF_W,  u32)
+       LDST(BPF_DW, u64)
+#undef LDST
+       BPF_STX_BPF_XADD_BPF_W: /* lock xadd *(u32 *)(A + insn->off) += X */
+               atomic_add((u32) X, (atomic_t *)(unsigned long)
+                          (A + insn->off));
+               CONT;
+       BPF_STX_BPF_XADD_BPF_DW: /* lock xadd *(u64 *)(A + insn->off) += X */
+               atomic64_add((u64) X, (atomic64_t *)(unsigned long)
+                            (A + insn->off));
+               CONT;
+       BPF_LD_BPF_ABS_BPF_W: /* R0 = ntohl(*(u32 *) (skb->data + K)) */
+               off = K;
+load_word:
+               /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are only
+                * appearing in the programs where ctx == skb. All programs
+                * keep 'ctx' in regs[CTX_REG] == R6, sk_convert_filter()
+                * saves it in R6, internal BPF verifier will check that
+                * R6 == ctx.
+                *
+                * BPF_ABS and BPF_IND are wrappers of function calls, so
+                * they scratch R1-R5 registers, preserve R6-R9, and store
+                * return value into R0.
+                *
+                * Implicit input:
+                *   ctx
+                *
+                * Explicit input:
+                *   X == any register
+                *   K == 32-bit immediate
+                *
+                * Output:
+                *   R0 - 8/16/32-bit skb data converted to cpu endianness
+                */
+               ptr = load_pointer((struct sk_buff *) ctx, off, 4, &tmp);
+               if (likely(ptr != NULL)) {
+                       R0 = get_unaligned_be32(ptr);
+                       CONT;
+               }
+               return 0;
+       BPF_LD_BPF_ABS_BPF_H: /* R0 = ntohs(*(u16 *) (skb->data + K)) */
+               off = K;
+load_half:
+               ptr = load_pointer((struct sk_buff *) ctx, off, 2, &tmp);
+               if (likely(ptr != NULL)) {
+                       R0 = get_unaligned_be16(ptr);
+                       CONT;
+               }
+               return 0;
+       BPF_LD_BPF_ABS_BPF_B: /* R0 = *(u8 *) (ctx + K) */
+               off = K;
+load_byte:
+               ptr = load_pointer((struct sk_buff *) ctx, off, 1, &tmp);
+               if (likely(ptr != NULL)) {
+                       R0 = *(u8 *)ptr;
+                       CONT;
+               }
+               return 0;
+       BPF_LD_BPF_IND_BPF_W: /* R0 = ntohl(*(u32 *) (skb->data + X + K)) */
+               off = K + X;
+               goto load_word;
+       BPF_LD_BPF_IND_BPF_H: /* R0 = ntohs(*(u16 *) (skb->data + X + K)) */
+               off = K + X;
+               goto load_half;
+       BPF_LD_BPF_IND_BPF_B: /* R0 = *(u8 *) (skb->data + X + K) */
+               off = K + X;
+               goto load_byte;
+
+       default_label:
+               /* If we ever reach this, we have a bug somewhere. */
+               WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code);
+               return 0;
+#undef CONT_JMP
+#undef CONT
+
+#undef R0
+#undef X
+#undef A
+#undef K
+}
+
+u32 sk_run_filter_int_seccomp(const struct seccomp_data *ctx,
+                             const struct sock_filter_int *insni)
+    __attribute__ ((alias ("__sk_run_filter")));
+
+u32 sk_run_filter_int_skb(const struct sk_buff *ctx,
+                         const struct sock_filter_int *insni)
+    __attribute__ ((alias ("__sk_run_filter")));
+EXPORT_SYMBOL_GPL(sk_run_filter_int_skb);
+
+/* Helper to find the offset of pkt_type in sk_buff structure. We want
+ * to make sure its still a 3bit field starting at a byte boundary;
+ * taken from arch/x86/net/bpf_jit_comp.c.
+ */
+#define PKT_TYPE_MAX   7
+static unsigned int pkt_type_offset(void)
+{
+       struct sk_buff skb_probe = { .pkt_type = ~0, };
+       u8 *ct = (u8 *) &skb_probe;
+       unsigned int off;
+
+       for (off = 0; off < sizeof(struct sk_buff); off++) {
+               if (ct[off] == PKT_TYPE_MAX)
+                       return off;
+       }
+
+       pr_err_once("Please fix %s, as pkt_type couldn't be found!\n", __func__);
+       return -1;
+}
+
+static u64 __skb_get_pay_offset(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+{
+       struct sk_buff *skb = (struct sk_buff *)(long) ctx;
+
+       return __skb_get_poff(skb);
+}
+
+static u64 __skb_get_nlattr(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+{
+       struct sk_buff *skb = (struct sk_buff *)(long) ctx;
+       struct nlattr *nla;
+
+       if (skb_is_nonlinear(skb))
+               return 0;
+
+       if (A > skb->len - sizeof(struct nlattr))
+               return 0;
+
+       nla = nla_find((struct nlattr *) &skb->data[A], skb->len - A, X);
+       if (nla)
+               return (void *) nla - (void *) skb->data;
+
+       return 0;
+}
+
+static u64 __skb_get_nlattr_nest(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+{
+       struct sk_buff *skb = (struct sk_buff *)(long) ctx;
+       struct nlattr *nla;
+
+       if (skb_is_nonlinear(skb))
+               return 0;
+
+       if (A > skb->len - sizeof(struct nlattr))
+               return 0;
+
+       nla = (struct nlattr *) &skb->data[A];
+       if (nla->nla_len > A - skb->len)
+               return 0;
+
+       nla = nla_find_nested(nla, X);
+       if (nla)
+               return (void *) nla - (void *) skb->data;
+
+       return 0;
+}
+
+static u64 __get_raw_cpu_id(u64 ctx, u64 A, u64 X, u64 r4, u64 r5)
+{
+       return raw_smp_processor_id();
+}
+
+/* Register mappings for user programs. */
+#define A_REG          0
+#define X_REG          7
+#define TMP_REG                8
+#define ARG2_REG       2
+#define ARG3_REG       3
+
+static bool convert_bpf_extensions(struct sock_filter *fp,
+                                  struct sock_filter_int **insnp)
+{
+       struct sock_filter_int *insn = *insnp;
+
+       switch (fp->k) {
+       case SKF_AD_OFF + SKF_AD_PROTOCOL:
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
+
+               insn->code = BPF_LDX | BPF_MEM | BPF_H;
+               insn->a_reg = A_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = offsetof(struct sk_buff, protocol);
+               insn++;
+
+               /* A = ntohs(A) [emitting a nop or swap16] */
+               insn->code = BPF_ALU | BPF_END | BPF_FROM_BE;
+               insn->a_reg = A_REG;
+               insn->imm = 16;
+               break;
+
+       case SKF_AD_OFF + SKF_AD_PKTTYPE:
+               insn->code = BPF_LDX | BPF_MEM | BPF_B;
+               insn->a_reg = A_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = pkt_type_offset();
+               if (insn->off < 0)
+                       return false;
+               insn++;
+
+               insn->code = BPF_ALU | BPF_AND | BPF_K;
+               insn->a_reg = A_REG;
+               insn->imm = PKT_TYPE_MAX;
+               break;
+
+       case SKF_AD_OFF + SKF_AD_IFINDEX:
+       case SKF_AD_OFF + SKF_AD_HATYPE:
+               if (FIELD_SIZEOF(struct sk_buff, dev) == 8)
+                       insn->code = BPF_LDX | BPF_MEM | BPF_DW;
+               else
+                       insn->code = BPF_LDX | BPF_MEM | BPF_W;
+               insn->a_reg = TMP_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = offsetof(struct sk_buff, dev);
+               insn++;
+
+               insn->code = BPF_JMP | BPF_JNE | BPF_K;
+               insn->a_reg = TMP_REG;
+               insn->imm = 0;
+               insn->off = 1;
+               insn++;
+
+               insn->code = BPF_JMP | BPF_EXIT;
+               insn++;
+
+               BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+               BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
+
+               insn->a_reg = A_REG;
+               insn->x_reg = TMP_REG;
+
+               if (fp->k == SKF_AD_OFF + SKF_AD_IFINDEX) {
+                       insn->code = BPF_LDX | BPF_MEM | BPF_W;
+                       insn->off = offsetof(struct net_device, ifindex);
+               } else {
+                       insn->code = BPF_LDX | BPF_MEM | BPF_H;
+                       insn->off = offsetof(struct net_device, type);
+               }
+               break;
+
+       case SKF_AD_OFF + SKF_AD_MARK:
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+
+               insn->code = BPF_LDX | BPF_MEM | BPF_W;
+               insn->a_reg = A_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = offsetof(struct sk_buff, mark);
+               break;
+
+       case SKF_AD_OFF + SKF_AD_RXHASH:
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4);
+
+               insn->code = BPF_LDX | BPF_MEM | BPF_W;
+               insn->a_reg = A_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = offsetof(struct sk_buff, hash);
+               break;
+
+       case SKF_AD_OFF + SKF_AD_QUEUE:
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
+
+               insn->code = BPF_LDX | BPF_MEM | BPF_H;
+               insn->a_reg = A_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = offsetof(struct sk_buff, queue_mapping);
+               break;
+
+       case SKF_AD_OFF + SKF_AD_VLAN_TAG:
+       case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT:
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2);
+
+               insn->code = BPF_LDX | BPF_MEM | BPF_H;
+               insn->a_reg = A_REG;
+               insn->x_reg = CTX_REG;
+               insn->off = offsetof(struct sk_buff, vlan_tci);
+               insn++;
+
+               BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000);
+
+               if (fp->k == SKF_AD_OFF + SKF_AD_VLAN_TAG) {
+                       insn->code = BPF_ALU | BPF_AND | BPF_K;
+                       insn->a_reg = A_REG;
+                       insn->imm = ~VLAN_TAG_PRESENT;
+               } else {
+                       insn->code = BPF_ALU | BPF_RSH | BPF_K;
+                       insn->a_reg = A_REG;
+                       insn->imm = 12;
+                       insn++;
+
+                       insn->code = BPF_ALU | BPF_AND | BPF_K;
+                       insn->a_reg = A_REG;
+                       insn->imm = 1;
+               }
+               break;
+
+       case SKF_AD_OFF + SKF_AD_PAY_OFFSET:
+       case SKF_AD_OFF + SKF_AD_NLATTR:
+       case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
+       case SKF_AD_OFF + SKF_AD_CPU:
+               /* arg1 = ctx */
+               insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+               insn->a_reg = ARG1_REG;
+               insn->x_reg = CTX_REG;
+               insn++;
+
+               /* arg2 = A */
+               insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+               insn->a_reg = ARG2_REG;
+               insn->x_reg = A_REG;
+               insn++;
+
+               /* arg3 = X */
+               insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+               insn->a_reg = ARG3_REG;
+               insn->x_reg = X_REG;
+               insn++;
+
+               /* Emit call(ctx, arg2=A, arg3=X) */
+               insn->code = BPF_JMP | BPF_CALL;
+               switch (fp->k) {
+               case SKF_AD_OFF + SKF_AD_PAY_OFFSET:
+                       insn->imm = __skb_get_pay_offset - __bpf_call_base;
+                       break;
+               case SKF_AD_OFF + SKF_AD_NLATTR:
+                       insn->imm = __skb_get_nlattr - __bpf_call_base;
+                       break;
+               case SKF_AD_OFF + SKF_AD_NLATTR_NEST:
+                       insn->imm = __skb_get_nlattr_nest - __bpf_call_base;
+                       break;
+               case SKF_AD_OFF + SKF_AD_CPU:
+                       insn->imm = __get_raw_cpu_id - __bpf_call_base;
+                       break;
+               }
+               break;
+
+       case SKF_AD_OFF + SKF_AD_ALU_XOR_X:
+               insn->code = BPF_ALU | BPF_XOR | BPF_X;
+               insn->a_reg = A_REG;
+               insn->x_reg = X_REG;
+               break;
+
+       default:
+               /* This is just a dummy call to avoid letting the compiler
+                * evict __bpf_call_base() as an optimization. Placed here
+                * where no-one bothers.
+                */
+               BUG_ON(__bpf_call_base(0, 0, 0, 0, 0) != 0);
+               return false;
+       }
+
+       *insnp = insn;
+       return true;
+}
+
+/**
+ *     sk_convert_filter - convert filter program
+ *     @prog: the user passed filter program
+ *     @len: the length of the user passed filter program
+ *     @new_prog: buffer where converted program will be stored
+ *     @new_len: pointer to store length of converted program
+ *
+ * Remap 'sock_filter' style BPF instruction set to 'sock_filter_ext' style.
+ * Conversion workflow:
+ *
+ * 1) First pass for calculating the new program length:
+ *   sk_convert_filter(old_prog, old_len, NULL, &new_len)
+ *
+ * 2) 2nd pass to remap in two passes: 1st pass finds new
+ *    jump offsets, 2nd pass remapping:
+ *   new_prog = kmalloc(sizeof(struct sock_filter_int) * new_len);
+ *   sk_convert_filter(old_prog, old_len, new_prog, &new_len);
+ *
+ * User BPF's register A is mapped to our BPF register 6, user BPF
+ * register X is mapped to BPF register 7; frame pointer is always
+ * register 10; Context 'void *ctx' is stored in register 1, that is,
+ * for socket filters: ctx == 'struct sk_buff *', for seccomp:
+ * ctx == 'struct seccomp_data *'.
+ */
+int sk_convert_filter(struct sock_filter *prog, int len,
+                     struct sock_filter_int *new_prog, int *new_len)
+{
+       int new_flen = 0, pass = 0, target, i;
+       struct sock_filter_int *new_insn;
+       struct sock_filter *fp;
+       int *addrs = NULL;
+       u8 bpf_src;
+
+       BUILD_BUG_ON(BPF_MEMWORDS * sizeof(u32) > MAX_BPF_STACK);
+       BUILD_BUG_ON(FP_REG + 1 != MAX_BPF_REG);
+
+       if (len <= 0 || len >= BPF_MAXINSNS)
+               return -EINVAL;
+
+       if (new_prog) {
+               addrs = kzalloc(len * sizeof(*addrs), GFP_KERNEL);
+               if (!addrs)
+                       return -ENOMEM;
+       }
+
+do_pass:
+       new_insn = new_prog;
+       fp = prog;
+
+       if (new_insn) {
+               new_insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+               new_insn->a_reg = CTX_REG;
+               new_insn->x_reg = ARG1_REG;
+       }
+       new_insn++;
+
+       for (i = 0; i < len; fp++, i++) {
+               struct sock_filter_int tmp_insns[6] = { };
+               struct sock_filter_int *insn = tmp_insns;
+
+               if (addrs)
+                       addrs[i] = new_insn - new_prog;
+
+               switch (fp->code) {
+               /* All arithmetic insns and skb loads map as-is. */
+               case BPF_ALU | BPF_ADD | BPF_X:
+               case BPF_ALU | BPF_ADD | BPF_K:
+               case BPF_ALU | BPF_SUB | BPF_X:
+               case BPF_ALU | BPF_SUB | BPF_K:
+               case BPF_ALU | BPF_AND | BPF_X:
+               case BPF_ALU | BPF_AND | BPF_K:
+               case BPF_ALU | BPF_OR | BPF_X:
+               case BPF_ALU | BPF_OR | BPF_K:
+               case BPF_ALU | BPF_LSH | BPF_X:
+               case BPF_ALU | BPF_LSH | BPF_K:
+               case BPF_ALU | BPF_RSH | BPF_X:
+               case BPF_ALU | BPF_RSH | BPF_K:
+               case BPF_ALU | BPF_XOR | BPF_X:
+               case BPF_ALU | BPF_XOR | BPF_K:
+               case BPF_ALU | BPF_MUL | BPF_X:
+               case BPF_ALU | BPF_MUL | BPF_K:
+               case BPF_ALU | BPF_DIV | BPF_X:
+               case BPF_ALU | BPF_DIV | BPF_K:
+               case BPF_ALU | BPF_MOD | BPF_X:
+               case BPF_ALU | BPF_MOD | BPF_K:
+               case BPF_ALU | BPF_NEG:
+               case BPF_LD | BPF_ABS | BPF_W:
+               case BPF_LD | BPF_ABS | BPF_H:
+               case BPF_LD | BPF_ABS | BPF_B:
+               case BPF_LD | BPF_IND | BPF_W:
+               case BPF_LD | BPF_IND | BPF_H:
+               case BPF_LD | BPF_IND | BPF_B:
+                       /* Check for overloaded BPF extension and
+                        * directly convert it if found, otherwise
+                        * just move on with mapping.
+                        */
+                       if (BPF_CLASS(fp->code) == BPF_LD &&
+                           BPF_MODE(fp->code) == BPF_ABS &&
+                           convert_bpf_extensions(fp, &insn))
+                               break;
+
+                       insn->code = fp->code;
+                       insn->a_reg = A_REG;
+                       insn->x_reg = X_REG;
+                       insn->imm = fp->k;
+                       break;
+
+               /* Jump opcodes map as-is, but offsets need adjustment. */
+               case BPF_JMP | BPF_JA:
+                       target = i + fp->k + 1;
+                       insn->code = fp->code;
+#define EMIT_JMP                                                       \
+       do {                                                            \
+               if (target >= len || target < 0)                        \
+                       goto err;                                       \
+               insn->off = addrs ? addrs[target] - addrs[i] - 1 : 0;   \
+               /* Adjust pc relative offset for 2nd or 3rd insn. */    \
+               insn->off -= insn - tmp_insns;                          \
+       } while (0)
+
+                       EMIT_JMP;
+                       break;
+
+               case BPF_JMP | BPF_JEQ | BPF_K:
+               case BPF_JMP | BPF_JEQ | BPF_X:
+               case BPF_JMP | BPF_JSET | BPF_K:
+               case BPF_JMP | BPF_JSET | BPF_X:
+               case BPF_JMP | BPF_JGT | BPF_K:
+               case BPF_JMP | BPF_JGT | BPF_X:
+               case BPF_JMP | BPF_JGE | BPF_K:
+               case BPF_JMP | BPF_JGE | BPF_X:
+                       if (BPF_SRC(fp->code) == BPF_K && (int) fp->k < 0) {
+                               /* BPF immediates are signed, zero extend
+                                * immediate into tmp register and use it
+                                * in compare insn.
+                                */
+                               insn->code = BPF_ALU | BPF_MOV | BPF_K;
+                               insn->a_reg = TMP_REG;
+                               insn->imm = fp->k;
+                               insn++;
+
+                               insn->a_reg = A_REG;
+                               insn->x_reg = TMP_REG;
+                               bpf_src = BPF_X;
+                       } else {
+                               insn->a_reg = A_REG;
+                               insn->x_reg = X_REG;
+                               insn->imm = fp->k;
+                               bpf_src = BPF_SRC(fp->code);
                        }
-                       return 0;
-               case BPF_S_LD_B_ABS:
-                       k = K;
-load_b:
-                       ptr = load_pointer(skb, k, 1, &tmp);
-                       if (ptr != NULL) {
-                               A = *(u8 *)ptr;
-                               continue;
+
+                       /* Common case where 'jump_false' is next insn. */
+                       if (fp->jf == 0) {
+                               insn->code = BPF_JMP | BPF_OP(fp->code) | bpf_src;
+                               target = i + fp->jt + 1;
+                               EMIT_JMP;
+                               break;
                        }
-                       return 0;
-               case BPF_S_LD_W_LEN:
-                       A = skb->len;
-                       continue;
-               case BPF_S_LDX_W_LEN:
-                       X = skb->len;
-                       continue;
-               case BPF_S_LD_W_IND:
-                       k = X + K;
-                       goto load_w;
-               case BPF_S_LD_H_IND:
-                       k = X + K;
-                       goto load_h;
-               case BPF_S_LD_B_IND:
-                       k = X + K;
-                       goto load_b;
-               case BPF_S_LDX_B_MSH:
-                       ptr = load_pointer(skb, K, 1, &tmp);
-                       if (ptr != NULL) {
-                               X = (*(u8 *)ptr & 0xf) << 2;
-                               continue;
+
+                       /* Convert JEQ into JNE when 'jump_true' is next insn. */
+                       if (fp->jt == 0 && BPF_OP(fp->code) == BPF_JEQ) {
+                               insn->code = BPF_JMP | BPF_JNE | bpf_src;
+                               target = i + fp->jf + 1;
+                               EMIT_JMP;
+                               break;
                        }
-                       return 0;
-               case BPF_S_LD_IMM:
-                       A = K;
-                       continue;
-               case BPF_S_LDX_IMM:
-                       X = K;
-                       continue;
-               case BPF_S_LD_MEM:
-                       A = mem[K];
-                       continue;
-               case BPF_S_LDX_MEM:
-                       X = mem[K];
-                       continue;
-               case BPF_S_MISC_TAX:
-                       X = A;
-                       continue;
-               case BPF_S_MISC_TXA:
-                       A = X;
-                       continue;
-               case BPF_S_RET_K:
-                       return K;
-               case BPF_S_RET_A:
-                       return A;
-               case BPF_S_ST:
-                       mem[K] = A;
-                       continue;
-               case BPF_S_STX:
-                       mem[K] = X;
-                       continue;
-               case BPF_S_ANC_PROTOCOL:
-                       A = ntohs(skb->protocol);
-                       continue;
-               case BPF_S_ANC_PKTTYPE:
-                       A = skb->pkt_type;
-                       continue;
-               case BPF_S_ANC_IFINDEX:
-                       if (!skb->dev)
-                               return 0;
-                       A = skb->dev->ifindex;
-                       continue;
-               case BPF_S_ANC_MARK:
-                       A = skb->mark;
-                       continue;
-               case BPF_S_ANC_QUEUE:
-                       A = skb->queue_mapping;
-                       continue;
-               case BPF_S_ANC_HATYPE:
-                       if (!skb->dev)
-                               return 0;
-                       A = skb->dev->type;
-                       continue;
-               case BPF_S_ANC_RXHASH:
-                       A = skb->rxhash;
-                       continue;
-               case BPF_S_ANC_CPU:
-                       A = raw_smp_processor_id();
-                       continue;
-               case BPF_S_ANC_VLAN_TAG:
-                       A = vlan_tx_tag_get(skb);
-                       continue;
-               case BPF_S_ANC_VLAN_TAG_PRESENT:
-                       A = !!vlan_tx_tag_present(skb);
-                       continue;
-               case BPF_S_ANC_PAY_OFFSET:
-                       A = __skb_get_poff(skb);
-                       continue;
-               case BPF_S_ANC_NLATTR: {
-                       struct nlattr *nla;
-
-                       if (skb_is_nonlinear(skb))
-                               return 0;
-                       if (A > skb->len - sizeof(struct nlattr))
-                               return 0;
-
-                       nla = nla_find((struct nlattr *)&skb->data[A],
-                                      skb->len - A, X);
-                       if (nla)
-                               A = (void *)nla - (void *)skb->data;
-                       else
-                               A = 0;
-                       continue;
-               }
-               case BPF_S_ANC_NLATTR_NEST: {
-                       struct nlattr *nla;
-
-                       if (skb_is_nonlinear(skb))
-                               return 0;
-                       if (A > skb->len - sizeof(struct nlattr))
-                               return 0;
-
-                       nla = (struct nlattr *)&skb->data[A];
-                       if (nla->nla_len > A - skb->len)
-                               return 0;
-
-                       nla = nla_find_nested(nla, X);
-                       if (nla)
-                               A = (void *)nla - (void *)skb->data;
-                       else
-                               A = 0;
-                       continue;
-               }
-#ifdef CONFIG_SECCOMP_FILTER
-               case BPF_S_ANC_SECCOMP_LD_W:
-                       A = seccomp_bpf_load(fentry->k);
-                       continue;
-#endif
+
+                       /* Other jumps are mapped into two insns: Jxx and JA. */
+                       target = i + fp->jt + 1;
+                       insn->code = BPF_JMP | BPF_OP(fp->code) | bpf_src;
+                       EMIT_JMP;
+                       insn++;
+
+                       insn->code = BPF_JMP | BPF_JA;
+                       target = i + fp->jf + 1;
+                       EMIT_JMP;
+                       break;
+
+               /* ldxb 4 * ([14] & 0xf) is remaped into 6 insns. */
+               case BPF_LDX | BPF_MSH | BPF_B:
+                       insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+                       insn->a_reg = TMP_REG;
+                       insn->x_reg = A_REG;
+                       insn++;
+
+                       insn->code = BPF_LD | BPF_ABS | BPF_B;
+                       insn->a_reg = A_REG;
+                       insn->imm = fp->k;
+                       insn++;
+
+                       insn->code = BPF_ALU | BPF_AND | BPF_K;
+                       insn->a_reg = A_REG;
+                       insn->imm = 0xf;
+                       insn++;
+
+                       insn->code = BPF_ALU | BPF_LSH | BPF_K;
+                       insn->a_reg = A_REG;
+                       insn->imm = 2;
+                       insn++;
+
+                       insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+                       insn->a_reg = X_REG;
+                       insn->x_reg = A_REG;
+                       insn++;
+
+                       insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+                       insn->a_reg = A_REG;
+                       insn->x_reg = TMP_REG;
+                       break;
+
+               /* RET_K, RET_A are remaped into 2 insns. */
+               case BPF_RET | BPF_A:
+               case BPF_RET | BPF_K:
+                       insn->code = BPF_ALU | BPF_MOV |
+                                    (BPF_RVAL(fp->code) == BPF_K ?
+                                     BPF_K : BPF_X);
+                       insn->a_reg = 0;
+                       insn->x_reg = A_REG;
+                       insn->imm = fp->k;
+                       insn++;
+
+                       insn->code = BPF_JMP | BPF_EXIT;
+                       break;
+
+               /* Store to stack. */
+               case BPF_ST:
+               case BPF_STX:
+                       insn->code = BPF_STX | BPF_MEM | BPF_W;
+                       insn->a_reg = FP_REG;
+                       insn->x_reg = fp->code == BPF_ST ? A_REG : X_REG;
+                       insn->off = -(BPF_MEMWORDS - fp->k) * 4;
+                       break;
+
+               /* Load from stack. */
+               case BPF_LD | BPF_MEM:
+               case BPF_LDX | BPF_MEM:
+                       insn->code = BPF_LDX | BPF_MEM | BPF_W;
+                       insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ?
+                                     A_REG : X_REG;
+                       insn->x_reg = FP_REG;
+                       insn->off = -(BPF_MEMWORDS - fp->k) * 4;
+                       break;
+
+               /* A = K or X = K */
+               case BPF_LD | BPF_IMM:
+               case BPF_LDX | BPF_IMM:
+                       insn->code = BPF_ALU | BPF_MOV | BPF_K;
+                       insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ?
+                                     A_REG : X_REG;
+                       insn->imm = fp->k;
+                       break;
+
+               /* X = A */
+               case BPF_MISC | BPF_TAX:
+                       insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+                       insn->a_reg = X_REG;
+                       insn->x_reg = A_REG;
+                       break;
+
+               /* A = X */
+               case BPF_MISC | BPF_TXA:
+                       insn->code = BPF_ALU64 | BPF_MOV | BPF_X;
+                       insn->a_reg = A_REG;
+                       insn->x_reg = X_REG;
+                       break;
+
+               /* A = skb->len or X = skb->len */
+               case BPF_LD | BPF_W | BPF_LEN:
+               case BPF_LDX | BPF_W | BPF_LEN:
+                       insn->code = BPF_LDX | BPF_MEM | BPF_W;
+                       insn->a_reg = BPF_CLASS(fp->code) == BPF_LD ?
+                                     A_REG : X_REG;
+                       insn->x_reg = CTX_REG;
+                       insn->off = offsetof(struct sk_buff, len);
+                       break;
+
+               /* access seccomp_data fields */
+               case BPF_LDX | BPF_ABS | BPF_W:
+                       insn->code = BPF_LDX | BPF_MEM | BPF_W;
+                       insn->a_reg = A_REG;
+                       insn->x_reg = CTX_REG;
+                       insn->off = fp->k;
+                       break;
+
                default:
-                       WARN_RATELIMIT(1, "Unknown code:%u jt:%u tf:%u k:%u\n",
-                                      fentry->code, fentry->jt,
-                                      fentry->jf, fentry->k);
-                       return 0;
+                       goto err;
                }
+
+               insn++;
+               if (new_prog)
+                       memcpy(new_insn, tmp_insns,
+                              sizeof(*insn) * (insn - tmp_insns));
+
+               new_insn += insn - tmp_insns;
+       }
+
+       if (!new_prog) {
+               /* Only calculating new length. */
+               *new_len = new_insn - new_prog;
+               return 0;
        }
 
+       pass++;
+       if (new_flen != new_insn - new_prog) {
+               new_flen = new_insn - new_prog;
+               if (pass > 2)
+                       goto err;
+
+               goto do_pass;
+       }
+
+       kfree(addrs);
+       BUG_ON(*new_len != new_flen);
        return 0;
+err:
+       kfree(addrs);
+       return -EINVAL;
 }
-EXPORT_SYMBOL(sk_run_filter);
 
-/*
- * Security :
+/* Security:
+ *
  * A BPF program is able to use 16 cells of memory to store intermediate
- * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter())
+ * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter()).
+ *
  * As we dont want to clear mem[] array for each packet going through
  * sk_run_filter(), we check that filter loaded by user never try to read
  * a cell if not previously written, and we check all branches to be sure
@@ -629,30 +1375,197 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
 }
 EXPORT_SYMBOL(sk_chk_filter);
 
+static int sk_store_orig_filter(struct sk_filter *fp,
+                               const struct sock_fprog *fprog)
+{
+       unsigned int fsize = sk_filter_proglen(fprog);
+       struct sock_fprog_kern *fkprog;
+
+       fp->orig_prog = kmalloc(sizeof(*fkprog), GFP_KERNEL);
+       if (!fp->orig_prog)
+               return -ENOMEM;
+
+       fkprog = fp->orig_prog;
+       fkprog->len = fprog->len;
+       fkprog->filter = kmemdup(fp->insns, fsize, GFP_KERNEL);
+       if (!fkprog->filter) {
+               kfree(fp->orig_prog);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void sk_release_orig_filter(struct sk_filter *fp)
+{
+       struct sock_fprog_kern *fprog = fp->orig_prog;
+
+       if (fprog) {
+               kfree(fprog->filter);
+               kfree(fprog);
+       }
+}
+
 /**
  *     sk_filter_release_rcu - Release a socket filter by rcu_head
  *     @rcu: rcu_head that contains the sk_filter to free
  */
-void sk_filter_release_rcu(struct rcu_head *rcu)
+static void sk_filter_release_rcu(struct rcu_head *rcu)
 {
        struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
 
+       sk_release_orig_filter(fp);
        bpf_jit_free(fp);
 }
-EXPORT_SYMBOL(sk_filter_release_rcu);
 
-static int __sk_prepare_filter(struct sk_filter *fp)
+/**
+ *     sk_filter_release - release a socket filter
+ *     @fp: filter to remove
+ *
+ *     Remove a filter from a socket and release its resources.
+ */
+static void sk_filter_release(struct sk_filter *fp)
+{
+       if (atomic_dec_and_test(&fp->refcnt))
+               call_rcu(&fp->rcu, sk_filter_release_rcu);
+}
+
+void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
+{
+       atomic_sub(sk_filter_size(fp->len), &sk->sk_omem_alloc);
+       sk_filter_release(fp);
+}
+
+void sk_filter_charge(struct sock *sk, struct sk_filter *fp)
+{
+       atomic_inc(&fp->refcnt);
+       atomic_add(sk_filter_size(fp->len), &sk->sk_omem_alloc);
+}
+
+static struct sk_filter *__sk_migrate_realloc(struct sk_filter *fp,
+                                             struct sock *sk,
+                                             unsigned int len)
+{
+       struct sk_filter *fp_new;
+
+       if (sk == NULL)
+               return krealloc(fp, len, GFP_KERNEL);
+
+       fp_new = sock_kmalloc(sk, len, GFP_KERNEL);
+       if (fp_new) {
+               memcpy(fp_new, fp, sizeof(struct sk_filter));
+               /* As we're kepping orig_prog in fp_new along,
+                * we need to make sure we're not evicting it
+                * from the old fp.
+                */
+               fp->orig_prog = NULL;
+               sk_filter_uncharge(sk, fp);
+       }
+
+       return fp_new;
+}
+
+static struct sk_filter *__sk_migrate_filter(struct sk_filter *fp,
+                                            struct sock *sk)
+{
+       struct sock_filter *old_prog;
+       struct sk_filter *old_fp;
+       int i, err, new_len, old_len = fp->len;
+
+       /* We are free to overwrite insns et al right here as it
+        * won't be used at this point in time anymore internally
+        * after the migration to the internal BPF instruction
+        * representation.
+        */
+       BUILD_BUG_ON(sizeof(struct sock_filter) !=
+                    sizeof(struct sock_filter_int));
+
+       /* For now, we need to unfiddle BPF_S_* identifiers in place.
+        * This can sooner or later on be subject to removal, e.g. when
+        * JITs have been converted.
+        */
+       for (i = 0; i < fp->len; i++)
+               sk_decode_filter(&fp->insns[i], &fp->insns[i]);
+
+       /* Conversion cannot happen on overlapping memory areas,
+        * so we need to keep the user BPF around until the 2nd
+        * pass. At this time, the user BPF is stored in fp->insns.
+        */
+       old_prog = kmemdup(fp->insns, old_len * sizeof(struct sock_filter),
+                          GFP_KERNEL);
+       if (!old_prog) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+
+       /* 1st pass: calculate the new program length. */
+       err = sk_convert_filter(old_prog, old_len, NULL, &new_len);
+       if (err)
+               goto out_err_free;
+
+       /* Expand fp for appending the new filter representation. */
+       old_fp = fp;
+       fp = __sk_migrate_realloc(old_fp, sk, sk_filter_size(new_len));
+       if (!fp) {
+               /* The old_fp is still around in case we couldn't
+                * allocate new memory, so uncharge on that one.
+                */
+               fp = old_fp;
+               err = -ENOMEM;
+               goto out_err_free;
+       }
+
+       fp->bpf_func = sk_run_filter_int_skb;
+       fp->len = new_len;
+
+       /* 2nd pass: remap sock_filter insns into sock_filter_int insns. */
+       err = sk_convert_filter(old_prog, old_len, fp->insnsi, &new_len);
+       if (err)
+               /* 2nd sk_convert_filter() can fail only if it fails
+                * to allocate memory, remapping must succeed. Note,
+                * that at this time old_fp has already been released
+                * by __sk_migrate_realloc().
+                */
+               goto out_err_free;
+
+       kfree(old_prog);
+       return fp;
+
+out_err_free:
+       kfree(old_prog);
+out_err:
+       /* Rollback filter setup. */
+       if (sk != NULL)
+               sk_filter_uncharge(sk, fp);
+       else
+               kfree(fp);
+       return ERR_PTR(err);
+}
+
+static struct sk_filter *__sk_prepare_filter(struct sk_filter *fp,
+                                            struct sock *sk)
 {
        int err;
 
-       fp->bpf_func = sk_run_filter;
+       fp->bpf_func = NULL;
+       fp->jited = 0;
 
        err = sk_chk_filter(fp->insns, fp->len);
        if (err)
-               return err;
+               return ERR_PTR(err);
 
+       /* Probe if we can JIT compile the filter and if so, do
+        * the compilation of the filter.
+        */
        bpf_jit_compile(fp);
-       return 0;
+
+       /* JIT compiler couldn't process this filter, so do the
+        * internal BPF translation for the optimized interpreter.
+        */
+       if (!fp->jited)
+               fp = __sk_migrate_filter(fp, sk);
+
+       return fp;
 }
 
 /**
@@ -668,9 +1581,8 @@ static int __sk_prepare_filter(struct sk_filter *fp)
 int sk_unattached_filter_create(struct sk_filter **pfp,
                                struct sock_fprog *fprog)
 {
+       unsigned int fsize = sk_filter_proglen(fprog);
        struct sk_filter *fp;
-       unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
-       int err;
 
        /* Make sure new filter is there and in the right amounts. */
        if (fprog->filter == NULL)
@@ -679,20 +1591,26 @@ int sk_unattached_filter_create(struct sk_filter **pfp,
        fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
+
        memcpy(fp->insns, fprog->filter, fsize);
 
        atomic_set(&fp->refcnt, 1);
        fp->len = fprog->len;
+       /* Since unattached filters are not copied back to user
+        * space through sk_get_filter(), we do not need to hold
+        * a copy here, and can spare us the work.
+        */
+       fp->orig_prog = NULL;
 
-       err = __sk_prepare_filter(fp);
-       if (err)
-               goto free_mem;
+       /* __sk_prepare_filter() already takes care of uncharging
+        * memory in case something goes wrong.
+        */
+       fp = __sk_prepare_filter(fp, NULL);
+       if (IS_ERR(fp))
+               return PTR_ERR(fp);
 
        *pfp = fp;
        return 0;
-free_mem:
-       kfree(fp);
-       return err;
 }
 EXPORT_SYMBOL_GPL(sk_unattached_filter_create);
 
@@ -715,7 +1633,7 @@ EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy);
 int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
 {
        struct sk_filter *fp, *old_fp;
-       unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
+       unsigned int fsize = sk_filter_proglen(fprog);
        unsigned int sk_fsize = sk_filter_size(fprog->len);
        int err;
 
@@ -729,6 +1647,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL);
        if (!fp)
                return -ENOMEM;
+
        if (copy_from_user(fp->insns, fprog->filter, fsize)) {
                sock_kfree_s(sk, fp, sk_fsize);
                return -EFAULT;
@@ -737,18 +1656,26 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        atomic_set(&fp->refcnt, 1);
        fp->len = fprog->len;
 
-       err = __sk_prepare_filter(fp);
+       err = sk_store_orig_filter(fp, fprog);
        if (err) {
                sk_filter_uncharge(sk, fp);
-               return err;
+               return -ENOMEM;
        }
 
+       /* __sk_prepare_filter() already takes care of uncharging
+        * memory in case something goes wrong.
+        */
+       fp = __sk_prepare_filter(fp, sk);
+       if (IS_ERR(fp))
+               return PTR_ERR(fp);
+
        old_fp = rcu_dereference_protected(sk->sk_filter,
                                           sock_owned_by_user(sk));
        rcu_assign_pointer(sk->sk_filter, fp);
 
        if (old_fp)
                sk_filter_uncharge(sk, old_fp);
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(sk_attach_filter);
@@ -768,6 +1695,7 @@ int sk_detach_filter(struct sock *sk)
                sk_filter_uncharge(sk, filter);
                ret = 0;
        }
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(sk_detach_filter);
@@ -850,34 +1778,41 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
        to->k = filt->k;
 }
 
-int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, unsigned int len)
+int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf,
+                 unsigned int len)
 {
+       struct sock_fprog_kern *fprog;
        struct sk_filter *filter;
-       int i, ret;
+       int ret = 0;
 
        lock_sock(sk);
        filter = rcu_dereference_protected(sk->sk_filter,
-                       sock_owned_by_user(sk));
-       ret = 0;
+                                          sock_owned_by_user(sk));
        if (!filter)
                goto out;
-       ret = filter->len;
+
+       /* We're copying the filter that has been originally attached,
+        * so no conversion/decode needed anymore.
+        */
+       fprog = filter->orig_prog;
+
+       ret = fprog->len;
        if (!len)
+               /* User space only enquires number of filter blocks. */
                goto out;
+
        ret = -EINVAL;
-       if (len < filter->len)
+       if (len < fprog->len)
                goto out;
 
        ret = -EFAULT;
-       for (i = 0; i < filter->len; i++) {
-               struct sock_filter fb;
-
-               sk_decode_filter(&filter->insns[i], &fb);
-               if (copy_to_user(&ubuf[i], &fb, sizeof(fb)))
-                       goto out;
-       }
+       if (copy_to_user(ubuf, fprog->filter, sk_filter_proglen(fprog)))
+               goto out;
 
-       ret = filter->len;
+       /* Instead of bytes, the API requests to return the number
+        * of filter blocks.
+        */
+       ret = fprog->len;
 out:
        release_sock(sk);
        return ret;
index dfa602ceb8cd846a2fdbbd24ac5367356ebb3906..31cfb365e0c689ffa528bf2f96072c6bcbc82799 100644 (file)
@@ -24,6 +24,7 @@
 #include <net/flow.h>
 #include <linux/atomic.h>
 #include <linux/security.h>
+#include <net/net_namespace.h>
 
 struct flow_cache_entry {
        union {
@@ -38,37 +39,14 @@ struct flow_cache_entry {
        struct flow_cache_object        *object;
 };
 
-struct flow_cache_percpu {
-       struct hlist_head               *hash_table;
-       int                             hash_count;
-       u32                             hash_rnd;
-       int                             hash_rnd_recalc;
-       struct tasklet_struct           flush_tasklet;
-};
-
 struct flow_flush_info {
        struct flow_cache               *cache;
        atomic_t                        cpuleft;
        struct completion               completion;
 };
 
-struct flow_cache {
-       u32                             hash_shift;
-       struct flow_cache_percpu __percpu *percpu;
-       struct notifier_block           hotcpu_notifier;
-       int                             low_watermark;
-       int                             high_watermark;
-       struct timer_list               rnd_timer;
-};
-
-atomic_t flow_cache_genid = ATOMIC_INIT(0);
-EXPORT_SYMBOL(flow_cache_genid);
-static struct flow_cache flow_cache_global;
 static struct kmem_cache *flow_cachep __read_mostly;
 
-static DEFINE_SPINLOCK(flow_cache_gc_lock);
-static LIST_HEAD(flow_cache_gc_list);
-
 #define flow_cache_hash_size(cache)    (1 << (cache)->hash_shift)
 #define FLOW_HASH_RND_PERIOD           (10 * 60 * HZ)
 
@@ -84,16 +62,18 @@ static void flow_cache_new_hashrnd(unsigned long arg)
        add_timer(&fc->rnd_timer);
 }
 
-static int flow_entry_valid(struct flow_cache_entry *fle)
+static int flow_entry_valid(struct flow_cache_entry *fle,
+                               struct netns_xfrm *xfrm)
 {
-       if (atomic_read(&flow_cache_genid) != fle->genid)
+       if (atomic_read(&xfrm->flow_cache_genid) != fle->genid)
                return 0;
        if (fle->object && !fle->object->ops->check(fle->object))
                return 0;
        return 1;
 }
 
-static void flow_entry_kill(struct flow_cache_entry *fle)
+static void flow_entry_kill(struct flow_cache_entry *fle,
+                               struct netns_xfrm *xfrm)
 {
        if (fle->object)
                fle->object->ops->delete(fle->object);
@@ -104,26 +84,28 @@ static void flow_cache_gc_task(struct work_struct *work)
 {
        struct list_head gc_list;
        struct flow_cache_entry *fce, *n;
+       struct netns_xfrm *xfrm = container_of(work, struct netns_xfrm,
+                                               flow_cache_gc_work);
 
        INIT_LIST_HEAD(&gc_list);
-       spin_lock_bh(&flow_cache_gc_lock);
-       list_splice_tail_init(&flow_cache_gc_list, &gc_list);
-       spin_unlock_bh(&flow_cache_gc_lock);
+       spin_lock_bh(&xfrm->flow_cache_gc_lock);
+       list_splice_tail_init(&xfrm->flow_cache_gc_list, &gc_list);
+       spin_unlock_bh(&xfrm->flow_cache_gc_lock);
 
        list_for_each_entry_safe(fce, n, &gc_list, u.gc_list)
-               flow_entry_kill(fce);
+               flow_entry_kill(fce, xfrm);
 }
-static DECLARE_WORK(flow_cache_gc_work, flow_cache_gc_task);
 
 static void flow_cache_queue_garbage(struct flow_cache_percpu *fcp,
-                                    int deleted, struct list_head *gc_list)
+                                    int deleted, struct list_head *gc_list,
+                                    struct netns_xfrm *xfrm)
 {
        if (deleted) {
                fcp->hash_count -= deleted;
-               spin_lock_bh(&flow_cache_gc_lock);
-               list_splice_tail(gc_list, &flow_cache_gc_list);
-               spin_unlock_bh(&flow_cache_gc_lock);
-               schedule_work(&flow_cache_gc_work);
+               spin_lock_bh(&xfrm->flow_cache_gc_lock);
+               list_splice_tail(gc_list, &xfrm->flow_cache_gc_list);
+               spin_unlock_bh(&xfrm->flow_cache_gc_lock);
+               schedule_work(&xfrm->flow_cache_gc_work);
        }
 }
 
@@ -135,6 +117,8 @@ static void __flow_cache_shrink(struct flow_cache *fc,
        struct hlist_node *tmp;
        LIST_HEAD(gc_list);
        int i, deleted = 0;
+       struct netns_xfrm *xfrm = container_of(fc, struct netns_xfrm,
+                                               flow_cache_global);
 
        for (i = 0; i < flow_cache_hash_size(fc); i++) {
                int saved = 0;
@@ -142,7 +126,7 @@ static void __flow_cache_shrink(struct flow_cache *fc,
                hlist_for_each_entry_safe(fle, tmp,
                                          &fcp->hash_table[i], u.hlist) {
                        if (saved < shrink_to &&
-                           flow_entry_valid(fle)) {
+                           flow_entry_valid(fle, xfrm)) {
                                saved++;
                        } else {
                                deleted++;
@@ -152,7 +136,7 @@ static void __flow_cache_shrink(struct flow_cache *fc,
                }
        }
 
-       flow_cache_queue_garbage(fcp, deleted, &gc_list);
+       flow_cache_queue_garbage(fcp, deleted, &gc_list, xfrm);
 }
 
 static void flow_cache_shrink(struct flow_cache *fc,
@@ -208,7 +192,7 @@ struct flow_cache_object *
 flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
                  flow_resolve_t resolver, void *ctx)
 {
-       struct flow_cache *fc = &flow_cache_global;
+       struct flow_cache *fc = &net->xfrm.flow_cache_global;
        struct flow_cache_percpu *fcp;
        struct flow_cache_entry *fle, *tfle;
        struct flow_cache_object *flo;
@@ -258,7 +242,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
                        hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]);
                        fcp->hash_count++;
                }
-       } else if (likely(fle->genid == atomic_read(&flow_cache_genid))) {
+       } else if (likely(fle->genid == atomic_read(&net->xfrm.flow_cache_genid))) {
                flo = fle->object;
                if (!flo)
                        goto ret_object;
@@ -279,7 +263,7 @@ nocache:
        }
        flo = resolver(net, key, family, dir, flo, ctx);
        if (fle) {
-               fle->genid = atomic_read(&flow_cache_genid);
+               fle->genid = atomic_read(&net->xfrm.flow_cache_genid);
                if (!IS_ERR(flo))
                        fle->object = flo;
                else
@@ -303,12 +287,14 @@ static void flow_cache_flush_tasklet(unsigned long data)
        struct hlist_node *tmp;
        LIST_HEAD(gc_list);
        int i, deleted = 0;
+       struct netns_xfrm *xfrm = container_of(fc, struct netns_xfrm,
+                                               flow_cache_global);
 
        fcp = this_cpu_ptr(fc->percpu);
        for (i = 0; i < flow_cache_hash_size(fc); i++) {
                hlist_for_each_entry_safe(fle, tmp,
                                          &fcp->hash_table[i], u.hlist) {
-                       if (flow_entry_valid(fle))
+                       if (flow_entry_valid(fle, xfrm))
                                continue;
 
                        deleted++;
@@ -317,7 +303,7 @@ static void flow_cache_flush_tasklet(unsigned long data)
                }
        }
 
-       flow_cache_queue_garbage(fcp, deleted, &gc_list);
+       flow_cache_queue_garbage(fcp, deleted, &gc_list, xfrm);
 
        if (atomic_dec_and_test(&info->cpuleft))
                complete(&info->completion);
@@ -351,10 +337,9 @@ static void flow_cache_flush_per_cpu(void *data)
        tasklet_schedule(tasklet);
 }
 
-void flow_cache_flush(void)
+void flow_cache_flush(struct net *net)
 {
        struct flow_flush_info info;
-       static DEFINE_MUTEX(flow_flush_sem);
        cpumask_var_t mask;
        int i, self;
 
@@ -365,8 +350,8 @@ void flow_cache_flush(void)
 
        /* Don't want cpus going down or up during this. */
        get_online_cpus();
-       mutex_lock(&flow_flush_sem);
-       info.cache = &flow_cache_global;
+       mutex_lock(&net->xfrm.flow_flush_sem);
+       info.cache = &net->xfrm.flow_cache_global;
        for_each_online_cpu(i)
                if (!flow_cache_percpu_empty(info.cache, i))
                        cpumask_set_cpu(i, mask);
@@ -386,21 +371,23 @@ void flow_cache_flush(void)
        wait_for_completion(&info.completion);
 
 done:
-       mutex_unlock(&flow_flush_sem);
+       mutex_unlock(&net->xfrm.flow_flush_sem);
        put_online_cpus();
        free_cpumask_var(mask);
 }
 
 static void flow_cache_flush_task(struct work_struct *work)
 {
-       flow_cache_flush();
-}
+       struct netns_xfrm *xfrm = container_of(work, struct netns_xfrm,
+                                               flow_cache_gc_work);
+       struct net *net = container_of(xfrm, struct net, xfrm);
 
-static DECLARE_WORK(flow_cache_flush_work, flow_cache_flush_task);
+       flow_cache_flush(net);
+}
 
-void flow_cache_flush_deferred(void)
+void flow_cache_flush_deferred(struct net *net)
 {
-       schedule_work(&flow_cache_flush_work);
+       schedule_work(&net->xfrm.flow_cache_flush_work);
 }
 
 static int flow_cache_cpu_prepare(struct flow_cache *fc, int cpu)
@@ -425,7 +412,8 @@ static int flow_cache_cpu(struct notifier_block *nfb,
                          unsigned long action,
                          void *hcpu)
 {
-       struct flow_cache *fc = container_of(nfb, struct flow_cache, hotcpu_notifier);
+       struct flow_cache *fc = container_of(nfb, struct flow_cache,
+                                               hotcpu_notifier);
        int res, cpu = (unsigned long) hcpu;
        struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
 
@@ -444,9 +432,20 @@ static int flow_cache_cpu(struct notifier_block *nfb,
        return NOTIFY_OK;
 }
 
-static int __init flow_cache_init(struct flow_cache *fc)
+int flow_cache_init(struct net *net)
 {
        int i;
+       struct flow_cache *fc = &net->xfrm.flow_cache_global;
+
+       if (!flow_cachep)
+               flow_cachep = kmem_cache_create("flow_cache",
+                                               sizeof(struct flow_cache_entry),
+                                               0, SLAB_PANIC, NULL);
+       spin_lock_init(&net->xfrm.flow_cache_gc_lock);
+       INIT_LIST_HEAD(&net->xfrm.flow_cache_gc_list);
+       INIT_WORK(&net->xfrm.flow_cache_gc_work, flow_cache_gc_task);
+       INIT_WORK(&net->xfrm.flow_cache_flush_work, flow_cache_flush_task);
+       mutex_init(&net->xfrm.flow_flush_sem);
 
        fc->hash_shift = 10;
        fc->low_watermark = 2 * flow_cache_hash_size(fc);
@@ -484,14 +483,23 @@ err:
 
        return -ENOMEM;
 }
+EXPORT_SYMBOL(flow_cache_init);
 
-static int __init flow_cache_init_global(void)
+void flow_cache_fini(struct net *net)
 {
-       flow_cachep = kmem_cache_create("flow_cache",
-                                       sizeof(struct flow_cache_entry),
-                                       0, SLAB_PANIC, NULL);
+       int i;
+       struct flow_cache *fc = &net->xfrm.flow_cache_global;
 
-       return flow_cache_init(&flow_cache_global);
-}
+       del_timer_sync(&fc->rnd_timer);
+       unregister_hotcpu_notifier(&fc->hotcpu_notifier);
 
-module_init(flow_cache_init_global);
+       for_each_possible_cpu(i) {
+               struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i);
+               kfree(fcp->hash_table);
+               fcp->hash_table = NULL;
+       }
+
+       free_percpu(fc->percpu);
+       fc->percpu = NULL;
+}
+EXPORT_SYMBOL(flow_cache_fini);
index 87577d447554336b33067ab6e2373c6bdd25b93d..107ed12a5323ab20e796042ae671e7b60ac0b488 100644 (file)
@@ -61,7 +61,7 @@ bool skb_flow_dissect(const struct sk_buff *skb, struct flow_keys *flow)
 
 again:
        switch (proto) {
-       case __constant_htons(ETH_P_IP): {
+       case htons(ETH_P_IP): {
                const struct iphdr *iph;
                struct iphdr _iph;
 ip:
@@ -77,7 +77,7 @@ ip:
                iph_to_flow_copy_addrs(flow, iph);
                break;
        }
-       case __constant_htons(ETH_P_IPV6): {
+       case htons(ETH_P_IPV6): {
                const struct ipv6hdr *iph;
                struct ipv6hdr _iph;
 ipv6:
@@ -91,8 +91,8 @@ ipv6:
                nhoff += sizeof(struct ipv6hdr);
                break;
        }
-       case __constant_htons(ETH_P_8021AD):
-       case __constant_htons(ETH_P_8021Q): {
+       case htons(ETH_P_8021AD):
+       case htons(ETH_P_8021Q): {
                const struct vlan_hdr *vlan;
                struct vlan_hdr _vlan;
 
@@ -104,7 +104,7 @@ ipv6:
                nhoff += sizeof(*vlan);
                goto again;
        }
-       case __constant_htons(ETH_P_PPP_SES): {
+       case htons(ETH_P_PPP_SES): {
                struct {
                        struct pppoe_hdr hdr;
                        __be16 proto;
@@ -115,9 +115,9 @@ ipv6:
                proto = hdr->proto;
                nhoff += PPPOE_SES_HLEN;
                switch (proto) {
-               case __constant_htons(PPP_IP):
+               case htons(PPP_IP):
                        goto ip;
-               case __constant_htons(PPP_IPV6):
+               case htons(PPP_IPV6):
                        goto ipv6;
                default:
                        return false;
@@ -203,8 +203,8 @@ static __always_inline u32 __flow_hash_1word(u32 a)
 
 /*
  * __skb_get_hash: calculate a flow hash based on src/dst addresses
- * and src/dst port numbers.  Sets rxhash in skb to non-zero hash value
- * on success, zero indicates no valid hash.  Also, sets l4_rxhash in skb
+ * and src/dst port numbers.  Sets hash in skb to non-zero hash value
+ * on success, zero indicates no valid hash.  Also, sets l4_hash in skb
  * if hash is a canonical 4-tuple hash over transport ports.
  */
 void __skb_get_hash(struct sk_buff *skb)
@@ -216,7 +216,7 @@ void __skb_get_hash(struct sk_buff *skb)
                return;
 
        if (keys.ports)
-               skb->l4_rxhash = 1;
+               skb->l4_hash = 1;
 
        /* get a consistent hash (same value on both flow directions) */
        if (((__force u32)keys.dst < (__force u32)keys.src) ||
@@ -232,7 +232,7 @@ void __skb_get_hash(struct sk_buff *skb)
        if (!hash)
                hash = 1;
 
-       skb->rxhash = hash;
+       skb->hash = hash;
 }
 EXPORT_SYMBOL(__skb_get_hash);
 
@@ -323,17 +323,6 @@ u32 __skb_get_poff(const struct sk_buff *skb)
        return poff;
 }
 
-static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
-{
-       if (unlikely(queue_index >= dev->real_num_tx_queues)) {
-               net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n",
-                                    dev->name, queue_index,
-                                    dev->real_num_tx_queues);
-               return 0;
-       }
-       return queue_index;
-}
-
 static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
 {
 #ifdef CONFIG_XPS
@@ -355,7 +344,7 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
                                        hash = skb->sk->sk_hash;
                                else
                                        hash = (__force u16) skb->protocol ^
-                                           skb->rxhash;
+                                           skb->hash;
                                hash = __flow_hash_1word(hash);
                                queue_index = map->queues[
                                    ((u64)hash * map->len) >> 32];
@@ -372,7 +361,7 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb)
 #endif
 }
 
-u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
+static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
        int queue_index = sk_tx_queue_get(sk);
@@ -392,7 +381,6 @@ u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
 
        return queue_index;
 }
-EXPORT_SYMBOL(__netdev_pick_tx);
 
 struct netdev_queue *netdev_pick_tx(struct net_device *dev,
                                    struct sk_buff *skb,
@@ -403,13 +391,13 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev,
        if (dev->real_num_tx_queues != 1) {
                const struct net_device_ops *ops = dev->netdev_ops;
                if (ops->ndo_select_queue)
-                       queue_index = ops->ndo_select_queue(dev, skb,
-                                                           accel_priv);
+                       queue_index = ops->ndo_select_queue(dev, skb, accel_priv,
+                                                           __netdev_pick_tx);
                else
                        queue_index = __netdev_pick_tx(dev, skb);
 
                if (!accel_priv)
-                       queue_index = dev_cap_txqueue(dev, queue_index);
+                       queue_index = netdev_cap_txqueue(dev, queue_index);
        }
 
        skb_set_queue_mapping(skb, queue_index);
index b9e9e0d38672a8ca9a17f8d6ec8daf88b8a09a65..8f8a96ef9f3f64ba519fe4c872d46c7b7c680ec9 100644 (file)
@@ -766,9 +766,6 @@ static void neigh_periodic_work(struct work_struct *work)
        nht = rcu_dereference_protected(tbl->nht,
                                        lockdep_is_held(&tbl->lock));
 
-       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
-               goto out;
-
        /*
         *      periodically recompute ReachableTime from random function
         */
@@ -781,6 +778,9 @@ static void neigh_periodic_work(struct work_struct *work)
                                neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
        }
 
+       if (atomic_read(&tbl->entries) < tbl->gc_thresh1)
+               goto out;
+
        for (i = 0 ; i < (1 << nht->hash_shift); i++) {
                np = &nht->hash_buckets[i];
 
@@ -836,10 +836,10 @@ out:
 static __inline__ int neigh_max_probes(struct neighbour *n)
 {
        struct neigh_parms *p = n->parms;
-       return (n->nud_state & NUD_PROBE) ?
-               NEIGH_VAR(p, UCAST_PROBES) :
-               NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) +
-               NEIGH_VAR(p, MCAST_PROBES);
+       int max_probes = NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES);
+       if (!(n->nud_state & NUD_PROBE))
+               max_probes += NEIGH_VAR(p, MCAST_PROBES);
+       return max_probes;
 }
 
 static void neigh_invalidate(struct neighbour *neigh)
@@ -945,6 +945,7 @@ static void neigh_timer_handler(unsigned long arg)
                neigh->nud_state = NUD_FAILED;
                notify = 1;
                neigh_invalidate(neigh);
+               goto out;
        }
 
        if (neigh->nud_state & NUD_IN_TIMER) {
@@ -3046,7 +3047,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
        if (!t)
                goto err;
 
-       for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
+       for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) {
                t->neigh_vars[i].data += (long) p;
                t->neigh_vars[i].extra1 = dev;
                t->neigh_vars[i].extra2 = p;
index 93886246a0b42a4f02e8387e758216582dd6d54f..daed9a64c6f6b350ef4518fc91b8b6718d58624d 100644 (file)
@@ -104,6 +104,7 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
 }
 
 NETDEVICE_SHOW_RO(dev_id, fmt_hex);
+NETDEVICE_SHOW_RO(dev_port, fmt_dec);
 NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec);
 NETDEVICE_SHOW_RO(addr_len, fmt_dec);
 NETDEVICE_SHOW_RO(iflink, fmt_dec);
@@ -373,6 +374,7 @@ static struct attribute *net_class_attrs[] = {
        &dev_attr_netdev_group.attr,
        &dev_attr_type.attr,
        &dev_attr_dev_id.attr,
+       &dev_attr_dev_port.attr,
        &dev_attr_iflink.attr,
        &dev_attr_ifindex.attr,
        &dev_attr_addr_assign_type.attr,
@@ -996,15 +998,12 @@ static struct attribute_group dql_group = {
 #endif /* CONFIG_BQL */
 
 #ifdef CONFIG_XPS
-static inline unsigned int get_netdev_queue_index(struct netdev_queue *queue)
+static unsigned int get_netdev_queue_index(struct netdev_queue *queue)
 {
        struct net_device *dev = queue->dev;
-       int i;
-
-       for (i = 0; i < dev->num_tx_queues; i++)
-               if (queue == &dev->_tx[i])
-                       break;
+       unsigned int i;
 
+       i = queue - dev->_tx;
        BUG_ON(i >= dev->num_tx_queues);
 
        return i;
index c03f3dec4763fc507edc56167cd8e88a209fb197..ed7740f7a94d538d617ced2c0f8174f1eb1dd3ed 100644 (file)
 
 static struct sk_buff_head skb_pool;
 
-static atomic_t trapped;
-
 DEFINE_STATIC_SRCU(netpoll_srcu);
 
 #define USEC_PER_POLL  50
-#define NETPOLL_RX_ENABLED  1
-#define NETPOLL_RX_DROP     2
 
 #define MAX_SKB_SIZE                                                   \
        (sizeof(struct ethhdr) +                                        \
@@ -61,7 +57,6 @@ DEFINE_STATIC_SRCU(netpoll_srcu);
         MAX_UDP_CHUNK)
 
 static void zap_completion_queue(void);
-static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
 static void netpoll_async_cleanup(struct work_struct *work);
 
 static unsigned int carrier_timeout = 4;
@@ -74,6 +69,37 @@ module_param(carrier_timeout, uint, 0644);
 #define np_notice(np, fmt, ...)                                \
        pr_notice("%s: " fmt, np->name, ##__VA_ARGS__)
 
+static int netpoll_start_xmit(struct sk_buff *skb, struct net_device *dev,
+                             struct netdev_queue *txq)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+       int status = NETDEV_TX_OK;
+       netdev_features_t features;
+
+       features = netif_skb_features(skb);
+
+       if (vlan_tx_tag_present(skb) &&
+           !vlan_hw_offload_capable(features, skb->vlan_proto)) {
+               skb = __vlan_put_tag(skb, skb->vlan_proto,
+                                    vlan_tx_tag_get(skb));
+               if (unlikely(!skb)) {
+                       /* This is actually a packet drop, but we
+                        * don't want the code that calls this
+                        * function to try and operate on a NULL skb.
+                        */
+                       goto out;
+               }
+               skb->vlan_tci = 0;
+       }
+
+       status = ops->ndo_start_xmit(skb, dev);
+       if (status == NETDEV_TX_OK)
+               txq_trans_update(txq);
+
+out:
+       return status;
+}
+
 static void queue_process(struct work_struct *work)
 {
        struct netpoll_info *npinfo =
@@ -83,51 +109,31 @@ static void queue_process(struct work_struct *work)
 
        while ((skb = skb_dequeue(&npinfo->txq))) {
                struct net_device *dev = skb->dev;
-               const struct net_device_ops *ops = dev->netdev_ops;
                struct netdev_queue *txq;
 
                if (!netif_device_present(dev) || !netif_running(dev)) {
-                       __kfree_skb(skb);
+                       kfree_skb(skb);
                        continue;
                }
 
                txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
 
                local_irq_save(flags);
-               __netif_tx_lock(txq, smp_processor_id());
+               HARD_TX_LOCK(dev, txq, smp_processor_id());
                if (netif_xmit_frozen_or_stopped(txq) ||
-                   ops->ndo_start_xmit(skb, dev) != NETDEV_TX_OK) {
+                   netpoll_start_xmit(skb, dev, txq) != NETDEV_TX_OK) {
                        skb_queue_head(&npinfo->txq, skb);
-                       __netif_tx_unlock(txq);
+                       HARD_TX_UNLOCK(dev, txq);
                        local_irq_restore(flags);
 
                        schedule_delayed_work(&npinfo->tx_work, HZ/10);
                        return;
                }
-               __netif_tx_unlock(txq);
+               HARD_TX_UNLOCK(dev, txq);
                local_irq_restore(flags);
        }
 }
 
-static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh,
-                           unsigned short ulen, __be32 saddr, __be32 daddr)
-{
-       __wsum psum;
-
-       if (uh->check == 0 || skb_csum_unnecessary(skb))
-               return 0;
-
-       psum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0);
-
-       if (skb->ip_summed == CHECKSUM_COMPLETE &&
-           !csum_fold(csum_add(psum, skb->csum)))
-               return 0;
-
-       skb->csum = psum;
-
-       return __skb_checksum_complete(skb);
-}
-
 /*
  * Check whether delayed processing was scheduled for our NIC. If so,
  * we attempt to grab the poll lock and use ->poll() to pump the card.
@@ -138,14 +144,8 @@ static __sum16 checksum_udp(struct sk_buff *skb, struct udphdr *uh,
  * trylock here and interrupts are already disabled in the softirq
  * case. Further, we test the poll_owner to avoid recursion on UP
  * systems where the lock doesn't exist.
- *
- * In cases where there is bi-directional communications, reading only
- * one message at a time can lead to packets being dropped by the
- * network adapter, forcing superfluous retries and possibly timeouts.
- * Thus, we set our budget to greater than 1.
  */
-static int poll_one_napi(struct netpoll_info *npinfo,
-                        struct napi_struct *napi, int budget)
+static int poll_one_napi(struct napi_struct *napi, int budget)
 {
        int work;
 
@@ -156,52 +156,35 @@ static int poll_one_napi(struct netpoll_info *npinfo,
        if (!test_bit(NAPI_STATE_SCHED, &napi->state))
                return budget;
 
-       npinfo->rx_flags |= NETPOLL_RX_DROP;
-       atomic_inc(&trapped);
        set_bit(NAPI_STATE_NPSVC, &napi->state);
 
        work = napi->poll(napi, budget);
+       WARN_ONCE(work > budget, "%pF exceeded budget in poll\n", napi->poll);
        trace_napi_poll(napi);
 
        clear_bit(NAPI_STATE_NPSVC, &napi->state);
-       atomic_dec(&trapped);
-       npinfo->rx_flags &= ~NETPOLL_RX_DROP;
 
        return budget - work;
 }
 
-static void poll_napi(struct net_device *dev)
+static void poll_napi(struct net_device *dev, int budget)
 {
        struct napi_struct *napi;
-       int budget = 16;
 
        list_for_each_entry(napi, &dev->napi_list, dev_list) {
                if (napi->poll_owner != smp_processor_id() &&
                    spin_trylock(&napi->poll_lock)) {
-                       budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
-                                              napi, budget);
+                       budget = poll_one_napi(napi, budget);
                        spin_unlock(&napi->poll_lock);
-
-                       if (!budget)
-                               break;
                }
        }
 }
 
-static void service_neigh_queue(struct netpoll_info *npi)
-{
-       if (npi) {
-               struct sk_buff *skb;
-
-               while ((skb = skb_dequeue(&npi->neigh_tx)))
-                       netpoll_neigh_reply(skb, npi);
-       }
-}
-
 static void netpoll_poll_dev(struct net_device *dev)
 {
        const struct net_device_ops *ops;
        struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
+       int budget = 0;
 
        /* Don't do any rx activity if the dev_lock mutex is held
         * the dev_open/close paths use this to block netpoll activity
@@ -224,31 +207,14 @@ static void netpoll_poll_dev(struct net_device *dev)
        /* Process pending work on NIC */
        ops->ndo_poll_controller(dev);
 
-       poll_napi(dev);
+       poll_napi(dev, budget);
 
        up(&ni->dev_lock);
 
-       if (dev->flags & IFF_SLAVE) {
-               if (ni) {
-                       struct net_device *bond_dev;
-                       struct sk_buff *skb;
-                       struct netpoll_info *bond_ni;
-
-                       bond_dev = netdev_master_upper_dev_get_rcu(dev);
-                       bond_ni = rcu_dereference_bh(bond_dev->npinfo);
-                       while ((skb = skb_dequeue(&ni->neigh_tx))) {
-                               skb->dev = bond_dev;
-                               skb_queue_tail(&bond_ni->neigh_tx, skb);
-                       }
-               }
-       }
-
-       service_neigh_queue(ni);
-
        zap_completion_queue();
 }
 
-void netpoll_rx_disable(struct net_device *dev)
+void netpoll_poll_disable(struct net_device *dev)
 {
        struct netpoll_info *ni;
        int idx;
@@ -259,9 +225,9 @@ void netpoll_rx_disable(struct net_device *dev)
                down(&ni->dev_lock);
        srcu_read_unlock(&netpoll_srcu, idx);
 }
-EXPORT_SYMBOL(netpoll_rx_disable);
+EXPORT_SYMBOL(netpoll_poll_disable);
 
-void netpoll_rx_enable(struct net_device *dev)
+void netpoll_poll_enable(struct net_device *dev)
 {
        struct netpoll_info *ni;
        rcu_read_lock();
@@ -270,7 +236,7 @@ void netpoll_rx_enable(struct net_device *dev)
                up(&ni->dev_lock);
        rcu_read_unlock();
 }
-EXPORT_SYMBOL(netpoll_rx_enable);
+EXPORT_SYMBOL(netpoll_poll_enable);
 
 static void refill_skbs(void)
 {
@@ -359,7 +325,6 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
 {
        int status = NETDEV_TX_BUSY;
        unsigned long tries;
-       const struct net_device_ops *ops = dev->netdev_ops;
        /* It is up to the caller to keep npinfo alive. */
        struct netpoll_info *npinfo;
 
@@ -367,7 +332,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
 
        npinfo = rcu_dereference_bh(np->dev->npinfo);
        if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
-               __kfree_skb(skb);
+               dev_kfree_skb_irq(skb);
                return;
        }
 
@@ -380,29 +345,11 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                /* try until next clock tick */
                for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
                     tries > 0; --tries) {
-                       if (__netif_tx_trylock(txq)) {
-                               if (!netif_xmit_stopped(txq)) {
-                                       if (vlan_tx_tag_present(skb) &&
-                                           !vlan_hw_offload_capable(netif_skb_features(skb),
-                                                                    skb->vlan_proto)) {
-                                               skb = __vlan_put_tag(skb, skb->vlan_proto, vlan_tx_tag_get(skb));
-                                               if (unlikely(!skb)) {
-                                                       /* This is actually a packet drop, but we
-                                                        * don't want the code at the end of this
-                                                        * function to try and re-queue a NULL skb.
-                                                        */
-                                                       status = NETDEV_TX_OK;
-                                                       goto unlock_txq;
-                                               }
-                                               skb->vlan_tci = 0;
-                                       }
-
-                                       status = ops->ndo_start_xmit(skb, dev);
-                                       if (status == NETDEV_TX_OK)
-                                               txq_trans_update(txq);
-                               }
-                       unlock_txq:
-                               __netif_tx_unlock(txq);
+                       if (HARD_TX_TRYLOCK(dev, txq)) {
+                               if (!netif_xmit_stopped(txq))
+                                       status = netpoll_start_xmit(skb, dev, txq);
+
+                               HARD_TX_UNLOCK(dev, txq);
 
                                if (status == NETDEV_TX_OK)
                                        break;
@@ -417,7 +364,7 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
 
                WARN_ONCE(!irqs_disabled(),
                        "netpoll_send_skb_on_dev(): %s enabled interrupts in poll (%pF)\n",
-                       dev->name, ops->ndo_start_xmit);
+                       dev->name, dev->netdev_ops->ndo_start_xmit);
 
        }
 
@@ -529,384 +476,6 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 }
 EXPORT_SYMBOL(netpoll_send_udp);
 
-static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
-{
-       int size, type = ARPOP_REPLY;
-       __be32 sip, tip;
-       unsigned char *sha;
-       struct sk_buff *send_skb;
-       struct netpoll *np, *tmp;
-       unsigned long flags;
-       int hlen, tlen;
-       int hits = 0, proto;
-
-       if (list_empty(&npinfo->rx_np))
-               return;
-
-       /* Before checking the packet, we do some early
-          inspection whether this is interesting at all */
-       spin_lock_irqsave(&npinfo->rx_lock, flags);
-       list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-               if (np->dev == skb->dev)
-                       hits++;
-       }
-       spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-
-       /* No netpoll struct is using this dev */
-       if (!hits)
-               return;
-
-       proto = ntohs(eth_hdr(skb)->h_proto);
-       if (proto == ETH_P_ARP) {
-               struct arphdr *arp;
-               unsigned char *arp_ptr;
-               /* No arp on this interface */
-               if (skb->dev->flags & IFF_NOARP)
-                       return;
-
-               if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
-                       return;
-
-               skb_reset_network_header(skb);
-               skb_reset_transport_header(skb);
-               arp = arp_hdr(skb);
-
-               if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
-                    arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
-                   arp->ar_pro != htons(ETH_P_IP) ||
-                   arp->ar_op != htons(ARPOP_REQUEST))
-                       return;
-
-               arp_ptr = (unsigned char *)(arp+1);
-               /* save the location of the src hw addr */
-               sha = arp_ptr;
-               arp_ptr += skb->dev->addr_len;
-               memcpy(&sip, arp_ptr, 4);
-               arp_ptr += 4;
-               /* If we actually cared about dst hw addr,
-                  it would get copied here */
-               arp_ptr += skb->dev->addr_len;
-               memcpy(&tip, arp_ptr, 4);
-
-               /* Should we ignore arp? */
-               if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
-                       return;
-
-               size = arp_hdr_len(skb->dev);
-
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (tip != np->local_ip.ip)
-                               continue;
-
-                       hlen = LL_RESERVED_SPACE(np->dev);
-                       tlen = np->dev->needed_tailroom;
-                       send_skb = find_skb(np, size + hlen + tlen, hlen);
-                       if (!send_skb)
-                               continue;
-
-                       skb_reset_network_header(send_skb);
-                       arp = (struct arphdr *) skb_put(send_skb, size);
-                       send_skb->dev = skb->dev;
-                       send_skb->protocol = htons(ETH_P_ARP);
-
-                       /* Fill the device header for the ARP frame */
-                       if (dev_hard_header(send_skb, skb->dev, ETH_P_ARP,
-                                           sha, np->dev->dev_addr,
-                                           send_skb->len) < 0) {
-                               kfree_skb(send_skb);
-                               continue;
-                       }
-
-                       /*
-                        * Fill out the arp protocol part.
-                        *
-                        * we only support ethernet device type,
-                        * which (according to RFC 1390) should
-                        * always equal 1 (Ethernet).
-                        */
-
-                       arp->ar_hrd = htons(np->dev->type);
-                       arp->ar_pro = htons(ETH_P_IP);
-                       arp->ar_hln = np->dev->addr_len;
-                       arp->ar_pln = 4;
-                       arp->ar_op = htons(type);
-
-                       arp_ptr = (unsigned char *)(arp + 1);
-                       memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
-                       arp_ptr += np->dev->addr_len;
-                       memcpy(arp_ptr, &tip, 4);
-                       arp_ptr += 4;
-                       memcpy(arp_ptr, sha, np->dev->addr_len);
-                       arp_ptr += np->dev->addr_len;
-                       memcpy(arp_ptr, &sip, 4);
-
-                       netpoll_send_skb(np, send_skb);
-
-                       /* If there are several rx_skb_hooks for the same
-                        * address we're fine by sending a single reply
-                        */
-                       break;
-               }
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-       } else if( proto == ETH_P_IPV6) {
-#if IS_ENABLED(CONFIG_IPV6)
-               struct nd_msg *msg;
-               u8 *lladdr = NULL;
-               struct ipv6hdr *hdr;
-               struct icmp6hdr *icmp6h;
-               const struct in6_addr *saddr;
-               const struct in6_addr *daddr;
-               struct inet6_dev *in6_dev = NULL;
-               struct in6_addr *target;
-
-               in6_dev = in6_dev_get(skb->dev);
-               if (!in6_dev || !in6_dev->cnf.accept_ra)
-                       return;
-
-               if (!pskb_may_pull(skb, skb->len))
-                       return;
-
-               msg = (struct nd_msg *)skb_transport_header(skb);
-
-               __skb_push(skb, skb->data - skb_transport_header(skb));
-
-               if (ipv6_hdr(skb)->hop_limit != 255)
-                       return;
-               if (msg->icmph.icmp6_code != 0)
-                       return;
-               if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
-                       return;
-
-               saddr = &ipv6_hdr(skb)->saddr;
-               daddr = &ipv6_hdr(skb)->daddr;
-
-               size = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
-
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (!ipv6_addr_equal(daddr, &np->local_ip.in6))
-                               continue;
-
-                       hlen = LL_RESERVED_SPACE(np->dev);
-                       tlen = np->dev->needed_tailroom;
-                       send_skb = find_skb(np, size + hlen + tlen, hlen);
-                       if (!send_skb)
-                               continue;
-
-                       send_skb->protocol = htons(ETH_P_IPV6);
-                       send_skb->dev = skb->dev;
-
-                       skb_reset_network_header(send_skb);
-                       hdr = (struct ipv6hdr *) skb_put(send_skb, sizeof(struct ipv6hdr));
-                       *(__be32*)hdr = htonl(0x60000000);
-                       hdr->payload_len = htons(size);
-                       hdr->nexthdr = IPPROTO_ICMPV6;
-                       hdr->hop_limit = 255;
-                       hdr->saddr = *saddr;
-                       hdr->daddr = *daddr;
-
-                       icmp6h = (struct icmp6hdr *) skb_put(send_skb, sizeof(struct icmp6hdr));
-                       icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
-                       icmp6h->icmp6_router = 0;
-                       icmp6h->icmp6_solicited = 1;
-
-                       target = (struct in6_addr *) skb_put(send_skb, sizeof(struct in6_addr));
-                       *target = msg->target;
-                       icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, size,
-                                                             IPPROTO_ICMPV6,
-                                                             csum_partial(icmp6h,
-                                                                          size, 0));
-
-                       if (dev_hard_header(send_skb, skb->dev, ETH_P_IPV6,
-                                           lladdr, np->dev->dev_addr,
-                                           send_skb->len) < 0) {
-                               kfree_skb(send_skb);
-                               continue;
-                       }
-
-                       netpoll_send_skb(np, send_skb);
-
-                       /* If there are several rx_skb_hooks for the same
-                        * address, we're fine by sending a single reply
-                        */
-                       break;
-               }
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-#endif
-       }
-}
-
-static bool pkt_is_ns(struct sk_buff *skb)
-{
-       struct nd_msg *msg;
-       struct ipv6hdr *hdr;
-
-       if (skb->protocol != htons(ETH_P_ARP))
-               return false;
-       if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
-               return false;
-
-       msg = (struct nd_msg *)skb_transport_header(skb);
-       __skb_push(skb, skb->data - skb_transport_header(skb));
-       hdr = ipv6_hdr(skb);
-
-       if (hdr->nexthdr != IPPROTO_ICMPV6)
-               return false;
-       if (hdr->hop_limit != 255)
-               return false;
-       if (msg->icmph.icmp6_code != 0)
-               return false;
-       if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
-               return false;
-
-       return true;
-}
-
-int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
-{
-       int proto, len, ulen, data_len;
-       int hits = 0, offset;
-       const struct iphdr *iph;
-       struct udphdr *uh;
-       struct netpoll *np, *tmp;
-       uint16_t source;
-
-       if (list_empty(&npinfo->rx_np))
-               goto out;
-
-       if (skb->dev->type != ARPHRD_ETHER)
-               goto out;
-
-       /* check if netpoll clients need ARP */
-       if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) {
-               skb_queue_tail(&npinfo->neigh_tx, skb);
-               return 1;
-       } else if (pkt_is_ns(skb) && atomic_read(&trapped)) {
-               skb_queue_tail(&npinfo->neigh_tx, skb);
-               return 1;
-       }
-
-       if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
-               skb = vlan_untag(skb);
-               if (unlikely(!skb))
-                       goto out;
-       }
-
-       proto = ntohs(eth_hdr(skb)->h_proto);
-       if (proto != ETH_P_IP && proto != ETH_P_IPV6)
-               goto out;
-       if (skb->pkt_type == PACKET_OTHERHOST)
-               goto out;
-       if (skb_shared(skb))
-               goto out;
-
-       if (proto == ETH_P_IP) {
-               if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-                       goto out;
-               iph = (struct iphdr *)skb->data;
-               if (iph->ihl < 5 || iph->version != 4)
-                       goto out;
-               if (!pskb_may_pull(skb, iph->ihl*4))
-                       goto out;
-               iph = (struct iphdr *)skb->data;
-               if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-                       goto out;
-
-               len = ntohs(iph->tot_len);
-               if (skb->len < len || len < iph->ihl*4)
-                       goto out;
-
-               /*
-                * Our transport medium may have padded the buffer out.
-                * Now We trim to the true length of the frame.
-                */
-               if (pskb_trim_rcsum(skb, len))
-                       goto out;
-
-               iph = (struct iphdr *)skb->data;
-               if (iph->protocol != IPPROTO_UDP)
-                       goto out;
-
-               len -= iph->ihl*4;
-               uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
-               offset = (unsigned char *)(uh + 1) - skb->data;
-               ulen = ntohs(uh->len);
-               data_len = skb->len - offset;
-               source = ntohs(uh->source);
-
-               if (ulen != len)
-                       goto out;
-               if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
-                       goto out;
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
-                               continue;
-                       if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
-                               continue;
-                       if (np->local_port && np->local_port != ntohs(uh->dest))
-                               continue;
-
-                       np->rx_skb_hook(np, source, skb, offset, data_len);
-                       hits++;
-               }
-       } else {
-#if IS_ENABLED(CONFIG_IPV6)
-               const struct ipv6hdr *ip6h;
-
-               if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
-                       goto out;
-               ip6h = (struct ipv6hdr *)skb->data;
-               if (ip6h->version != 6)
-                       goto out;
-               len = ntohs(ip6h->payload_len);
-               if (!len)
-                       goto out;
-               if (len + sizeof(struct ipv6hdr) > skb->len)
-                       goto out;
-               if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
-                       goto out;
-               ip6h = ipv6_hdr(skb);
-               if (!pskb_may_pull(skb, sizeof(struct udphdr)))
-                       goto out;
-               uh = udp_hdr(skb);
-               offset = (unsigned char *)(uh + 1) - skb->data;
-               ulen = ntohs(uh->len);
-               data_len = skb->len - offset;
-               source = ntohs(uh->source);
-               if (ulen != skb->len)
-                       goto out;
-               if (udp6_csum_init(skb, uh, IPPROTO_UDP))
-                       goto out;
-               list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
-                       if (!ipv6_addr_equal(&np->local_ip.in6, &ip6h->daddr))
-                               continue;
-                       if (!ipv6_addr_equal(&np->remote_ip.in6, &ip6h->saddr))
-                               continue;
-                       if (np->local_port && np->local_port != ntohs(uh->dest))
-                               continue;
-
-                       np->rx_skb_hook(np, source, skb, offset, data_len);
-                       hits++;
-               }
-#endif
-       }
-
-       if (!hits)
-               goto out;
-
-       kfree_skb(skb);
-       return 1;
-
-out:
-       if (atomic_read(&trapped)) {
-               kfree_skb(skb);
-               return 1;
-       }
-
-       return 0;
-}
-
 void netpoll_print_options(struct netpoll *np)
 {
        np_info(np, "local port %d\n", np->local_port);
@@ -948,6 +517,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
 {
        char *cur=opt, *delim;
        int ipv6;
+       bool ipversion_set = false;
 
        if (*cur != '@') {
                if ((delim = strchr(cur, '@')) == NULL)
@@ -960,6 +530,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
        cur++;
 
        if (*cur != '/') {
+               ipversion_set = true;
                if ((delim = strchr(cur, '/')) == NULL)
                        goto parse_failed;
                *delim = 0;
@@ -1002,7 +573,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
        ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
        if (ipv6 < 0)
                goto parse_failed;
-       else if (np->ipv6 != (bool)ipv6)
+       else if (ipversion_set && np->ipv6 != (bool)ipv6)
                goto parse_failed;
        else
                np->ipv6 = (bool)ipv6;
@@ -1024,11 +595,10 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
 }
 EXPORT_SYMBOL(netpoll_parse_options);
 
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
 {
        struct netpoll_info *npinfo;
        const struct net_device_ops *ops;
-       unsigned long flags;
        int err;
 
        np->dev = ndev;
@@ -1044,18 +614,13 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
        }
 
        if (!ndev->npinfo) {
-               npinfo = kmalloc(sizeof(*npinfo), gfp);
+               npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
                if (!npinfo) {
                        err = -ENOMEM;
                        goto out;
                }
 
-               npinfo->rx_flags = 0;
-               INIT_LIST_HEAD(&npinfo->rx_np);
-
-               spin_lock_init(&npinfo->rx_lock);
                sema_init(&npinfo->dev_lock, 1);
-               skb_queue_head_init(&npinfo->neigh_tx);
                skb_queue_head_init(&npinfo->txq);
                INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
 
@@ -1063,7 +628,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 
                ops = np->dev->netdev_ops;
                if (ops->ndo_netpoll_setup) {
-                       err = ops->ndo_netpoll_setup(ndev, npinfo, gfp);
+                       err = ops->ndo_netpoll_setup(ndev, npinfo);
                        if (err)
                                goto free_npinfo;
                }
@@ -1074,13 +639,6 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 
        npinfo->netpoll = np;
 
-       if (np->rx_skb_hook) {
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               npinfo->rx_flags |= NETPOLL_RX_ENABLED;
-               list_add_tail(&np->rx, &npinfo->rx_np);
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-       }
-
        /* last thing to do is link it to the net device structure */
        rcu_assign_pointer(ndev->npinfo, npinfo);
 
@@ -1202,7 +760,7 @@ int netpoll_setup(struct netpoll *np)
        /* fill up the skb queue */
        refill_skbs();
 
-       err = __netpoll_setup(np, ndev, GFP_KERNEL);
+       err = __netpoll_setup(np, ndev);
        if (err)
                goto put;
 
@@ -1229,7 +787,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
        struct netpoll_info *npinfo =
                        container_of(rcu_head, struct netpoll_info, rcu);
 
-       skb_queue_purge(&npinfo->neigh_tx);
        skb_queue_purge(&npinfo->txq);
 
        /* we can't call cancel_delayed_work_sync here, as we are in softirq */
@@ -1245,7 +802,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
 void __netpoll_cleanup(struct netpoll *np)
 {
        struct netpoll_info *npinfo;
-       unsigned long flags;
 
        /* rtnl_dereference would be preferable here but
         * rcu_cleanup_netpoll path can put us in here safely without
@@ -1255,14 +811,6 @@ void __netpoll_cleanup(struct netpoll *np)
        if (!npinfo)
                return;
 
-       if (!list_empty(&npinfo->rx_np)) {
-               spin_lock_irqsave(&npinfo->rx_lock, flags);
-               list_del(&np->rx);
-               if (list_empty(&npinfo->rx_np))
-                       npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
-               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
-       }
-
        synchronize_srcu(&netpoll_srcu);
 
        if (atomic_dec_and_test(&npinfo->refcnt)) {
@@ -1272,7 +820,7 @@ void __netpoll_cleanup(struct netpoll *np)
                if (ops->ndo_netpoll_cleanup)
                        ops->ndo_netpoll_cleanup(np->dev);
 
-               rcu_assign_pointer(np->dev->npinfo, NULL);
+               RCU_INIT_POINTER(np->dev->npinfo, NULL);
                call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info);
        }
 }
@@ -1306,18 +854,3 @@ out:
        rtnl_unlock();
 }
 EXPORT_SYMBOL(netpoll_cleanup);
-
-int netpoll_trap(void)
-{
-       return atomic_read(&trapped);
-}
-EXPORT_SYMBOL(netpoll_trap);
-
-void netpoll_set_trap(int trap)
-{
-       if (trap)
-               atomic_inc(&trapped);
-       else
-               atomic_dec(&trapped);
-}
-EXPORT_SYMBOL(netpoll_set_trap);
index fdac61cac1bd11b15a69f78584029731e9310e4e..d0dac57291afab943db9719aa5818ebb6611cf65 100644 (file)
@@ -476,23 +476,22 @@ static int pgctrl_show(struct seq_file *seq, void *v)
 static ssize_t pgctrl_write(struct file *file, const char __user *buf,
                            size_t count, loff_t *ppos)
 {
-       int err = 0;
        char data[128];
        struct pktgen_net *pn = net_generic(current->nsproxy->net_ns, pg_net_id);
 
-       if (!capable(CAP_NET_ADMIN)) {
-               err = -EPERM;
-               goto out;
-       }
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (count == 0)
+               return -EINVAL;
 
        if (count > sizeof(data))
                count = sizeof(data);
 
-       if (copy_from_user(data, buf, count)) {
-               err = -EFAULT;
-               goto out;
-       }
-       data[count - 1] = 0;    /* Make string */
+       if (copy_from_user(data, buf, count))
+               return -EFAULT;
+
+       data[count - 1] = 0;    /* Strip trailing '\n' and terminate string */
 
        if (!strcmp(data, "stop"))
                pktgen_stop_all_threads_ifs(pn);
@@ -506,10 +505,7 @@ static ssize_t pgctrl_write(struct file *file, const char __user *buf,
        else
                pr_warning("Unknown command: %s\n", data);
 
-       err = count;
-
-out:
-       return err;
+       return count;
 }
 
 static int pgctrl_open(struct inode *inode, struct file *file)
@@ -1251,7 +1247,13 @@ static ssize_t pktgen_if_write(struct file *file,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
                                f,
                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
-                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC, NODE_ALLOC\n");
+                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, "
+                               "MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, "
+                               "QUEUE_MAP_RND, QUEUE_MAP_CPU, UDPCSUM, "
+#ifdef CONFIG_XFRM
+                               "IPSEC, "
+#endif
+                               "NODE_ALLOC\n");
                        return count;
                }
                sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
index 4425148d2b51592626b92a1451d9bc1208213fb8..467f326126e0eb913416c9bd2f847816d6d98948 100644 (file)
@@ -221,5 +221,4 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req,
 out:
        spin_unlock_bh(&fastopenq->lock);
        sock_put(lsk);
-       return;
 }
index 393b1bc9a618e5dee70105614772ad692e09bb7e..e7c6006bc3eaf72e4a22d729d6d8643bff6bef58 100644 (file)
@@ -374,7 +374,7 @@ static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev)
        if (!master_dev)
                return 0;
        ops = master_dev->rtnl_link_ops;
-       if (!ops->get_slave_size)
+       if (!ops || !ops->get_slave_size)
                return 0;
        /* IFLA_INFO_SLAVE_DATA + nested data */
        return nla_total_size(sizeof(struct nlattr)) +
@@ -1121,56 +1121,7 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
-static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       struct net *net = sock_net(skb->sk);
-       int h, s_h;
-       int idx = 0, s_idx;
-       struct net_device *dev;
-       struct hlist_head *head;
-       struct nlattr *tb[IFLA_MAX+1];
-       u32 ext_filter_mask = 0;
-
-       s_h = cb->args[0];
-       s_idx = cb->args[1];
-
-       rcu_read_lock();
-       cb->seq = net->dev_base_seq;
-
-       if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
-                       ifla_policy) >= 0) {
-
-               if (tb[IFLA_EXT_MASK])
-                       ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
-       }
-
-       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
-               idx = 0;
-               head = &net->dev_index_head[h];
-               hlist_for_each_entry_rcu(dev, head, index_hlist) {
-                       if (idx < s_idx)
-                               goto cont;
-                       if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
-                                            NETLINK_CB(cb->skb).portid,
-                                            cb->nlh->nlmsg_seq, 0,
-                                            NLM_F_MULTI,
-                                            ext_filter_mask) <= 0)
-                               goto out;
-
-                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
-cont:
-                       idx++;
-               }
-       }
-out:
-       rcu_read_unlock();
-       cb->args[1] = idx;
-       cb->args[0] = h;
-
-       return skb->len;
-}
-
-const struct nla_policy ifla_policy[IFLA_MAX+1] = {
+static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_IFNAME]           = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
        [IFLA_ADDRESS]          = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
        [IFLA_BROADCAST]        = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
@@ -1197,7 +1148,6 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
        [IFLA_NUM_RX_QUEUES]    = { .type = NLA_U32 },
        [IFLA_PHYS_PORT_ID]     = { .type = NLA_BINARY, .len = MAX_PHYS_PORT_ID_LEN },
 };
-EXPORT_SYMBOL(ifla_policy);
 
 static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
        [IFLA_INFO_KIND]        = { .type = NLA_STRING },
@@ -1235,6 +1185,61 @@ static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
        [IFLA_PORT_RESPONSE]    = { .type = NLA_U16, },
 };
 
+static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       struct net *net = sock_net(skb->sk);
+       int h, s_h;
+       int idx = 0, s_idx;
+       struct net_device *dev;
+       struct hlist_head *head;
+       struct nlattr *tb[IFLA_MAX+1];
+       u32 ext_filter_mask = 0;
+
+       s_h = cb->args[0];
+       s_idx = cb->args[1];
+
+       rcu_read_lock();
+       cb->seq = net->dev_base_seq;
+
+       if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX,
+                       ifla_policy) >= 0) {
+
+               if (tb[IFLA_EXT_MASK])
+                       ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
+       }
+
+       for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+               idx = 0;
+               head = &net->dev_index_head[h];
+               hlist_for_each_entry_rcu(dev, head, index_hlist) {
+                       if (idx < s_idx)
+                               goto cont;
+                       if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
+                                            NETLINK_CB(cb->skb).portid,
+                                            cb->nlh->nlmsg_seq, 0,
+                                            NLM_F_MULTI,
+                                            ext_filter_mask) <= 0)
+                               goto out;
+
+                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
+cont:
+                       idx++;
+               }
+       }
+out:
+       rcu_read_unlock();
+       cb->args[1] = idx;
+       cb->args[0] = h;
+
+       return skb->len;
+}
+
+int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len)
+{
+       return nla_parse(tb, IFLA_MAX, head, len, ifla_policy);
+}
+EXPORT_SYMBOL(rtnl_nla_parse_ifla);
+
 struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
 {
        struct net *net;
@@ -1963,16 +1968,21 @@ replay:
 
                dev->ifindex = ifm->ifi_index;
 
-               if (ops->newlink)
+               if (ops->newlink) {
                        err = ops->newlink(net, dev, tb, data);
-               else
+                       /* Drivers should call free_netdev() in ->destructor
+                        * and unregister it on failure so that device could be
+                        * finally freed in rtnl_unlock.
+                        */
+                       if (err < 0)
+                               goto out;
+               } else {
                        err = register_netdevice(dev);
-
-               if (err < 0) {
-                       free_netdev(dev);
-                       goto out;
+                       if (err < 0) {
+                               free_netdev(dev);
+                               goto out;
+                       }
                }
-
                err = rtnl_configure_link(dev, ifm);
                if (err < 0)
                        unregister_netdevice(dev);
@@ -2116,12 +2126,13 @@ EXPORT_SYMBOL(rtmsg_ifinfo);
 static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
                                   struct net_device *dev,
                                   u8 *addr, u32 pid, u32 seq,
-                                  int type, unsigned int flags)
+                                  int type, unsigned int flags,
+                                  int nlflags)
 {
        struct nlmsghdr *nlh;
        struct ndmsg *ndm;
 
-       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), nlflags);
        if (!nlh)
                return -EMSGSIZE;
 
@@ -2159,7 +2170,7 @@ static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, int type)
        if (!skb)
                goto errout;
 
-       err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF);
+       err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF, 0);
        if (err < 0) {
                kfree_skb(skb);
                goto errout;
@@ -2384,7 +2395,8 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
 
                err = nlmsg_populate_fdb_fill(skb, dev, ha->addr,
                                              portid, seq,
-                                             RTM_NEWNEIGH, NTF_SELF);
+                                             RTM_NEWNEIGH, NTF_SELF,
+                                             NLM_F_MULTI);
                if (err < 0)
                        return err;
 skip:
index 5976ef0846bdda08db6289bb91f05a63b85e6e3a..30c7d35dd862a090c691732af63af1e8fdbad41a 100644 (file)
@@ -707,9 +707,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
        new->mark               = old->mark;
        new->skb_iif            = old->skb_iif;
        __nf_copy(new, old);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       new->nf_trace           = old->nf_trace;
-#endif
 #ifdef CONFIG_NET_SCHED
        new->tc_index           = old->tc_index;
 #ifdef CONFIG_NET_CLS_ACT
@@ -2130,25 +2127,31 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
  *
  *     The `hlen` as calculated by skb_zerocopy_headlen() specifies the
  *     headroom in the `to` buffer.
+ *
+ *     Return value:
+ *     0: everything is OK
+ *     -ENOMEM: couldn't orphan frags of @from due to lack of memory
+ *     -EFAULT: skb_copy_bits() found some problem with skb geometry
  */
-void
-skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
+int
+skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
 {
        int i, j = 0;
        int plen = 0; /* length of skb->head fragment */
+       int ret;
        struct page *page;
        unsigned int offset;
 
        BUG_ON(!from->head_frag && !hlen);
 
        /* dont bother with small payloads */
-       if (len <= skb_tailroom(to)) {
-               skb_copy_bits(from, 0, skb_put(to, len), len);
-               return;
-       }
+       if (len <= skb_tailroom(to))
+               return skb_copy_bits(from, 0, skb_put(to, len), len);
 
        if (hlen) {
-               skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+               ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen);
+               if (unlikely(ret))
+                       return ret;
                len -= hlen;
        } else {
                plen = min_t(int, skb_headlen(from), len);
@@ -2166,6 +2169,11 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
        to->len += len + plen;
        to->data_len += len + plen;
 
+       if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) {
+               skb_tx_error(from);
+               return -ENOMEM;
+       }
+
        for (i = 0; i < skb_shinfo(from)->nr_frags; i++) {
                if (!len)
                        break;
@@ -2176,6 +2184,8 @@ skb_zerocopy(struct sk_buff *to, const struct sk_buff *from, int len, int hlen)
                j++;
        }
        skb_shinfo(to)->nr_frags = j;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(skb_zerocopy);
 
@@ -2841,81 +2851,85 @@ EXPORT_SYMBOL_GPL(skb_pull_rcsum);
 
 /**
  *     skb_segment - Perform protocol segmentation on skb.
- *     @skb: buffer to segment
+ *     @head_skb: buffer to segment
  *     @features: features for the output path (see dev->features)
  *
  *     This function performs segmentation on the given skb.  It returns
  *     a pointer to the first in a list of new skbs for the segments.
  *     In case of error it returns ERR_PTR(err).
  */
-struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
+struct sk_buff *skb_segment(struct sk_buff *head_skb,
+                           netdev_features_t features)
 {
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
-       struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
-       skb_frag_t *skb_frag = skb_shinfo(skb)->frags;
-       unsigned int mss = skb_shinfo(skb)->gso_size;
-       unsigned int doffset = skb->data - skb_mac_header(skb);
+       struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
+       skb_frag_t *frag = skb_shinfo(head_skb)->frags;
+       unsigned int mss = skb_shinfo(head_skb)->gso_size;
+       unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
+       struct sk_buff *frag_skb = head_skb;
        unsigned int offset = doffset;
-       unsigned int tnl_hlen = skb_tnl_header_len(skb);
+       unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
        unsigned int headroom;
        unsigned int len;
        __be16 proto;
        bool csum;
        int sg = !!(features & NETIF_F_SG);
-       int nfrags = skb_shinfo(skb)->nr_frags;
+       int nfrags = skb_shinfo(head_skb)->nr_frags;
        int err = -ENOMEM;
        int i = 0;
        int pos;
+       int dummy;
 
-       proto = skb_network_protocol(skb);
+       proto = skb_network_protocol(head_skb, &dummy);
        if (unlikely(!proto))
                return ERR_PTR(-EINVAL);
 
        csum = !!can_checksum_protocol(features, proto);
-       __skb_push(skb, doffset);
-       headroom = skb_headroom(skb);
-       pos = skb_headlen(skb);
+       __skb_push(head_skb, doffset);
+       headroom = skb_headroom(head_skb);
+       pos = skb_headlen(head_skb);
 
        do {
                struct sk_buff *nskb;
-               skb_frag_t *frag;
+               skb_frag_t *nskb_frag;
                int hsize;
                int size;
 
-               len = skb->len - offset;
+               len = head_skb->len - offset;
                if (len > mss)
                        len = mss;
 
-               hsize = skb_headlen(skb) - offset;
+               hsize = skb_headlen(head_skb) - offset;
                if (hsize < 0)
                        hsize = 0;
                if (hsize > len || !sg)
                        hsize = len;
 
-               if (!hsize && i >= nfrags && skb_headlen(fskb) &&
-                   (skb_headlen(fskb) == len || sg)) {
-                       BUG_ON(skb_headlen(fskb) > len);
+               if (!hsize && i >= nfrags && skb_headlen(list_skb) &&
+                   (skb_headlen(list_skb) == len || sg)) {
+                       BUG_ON(skb_headlen(list_skb) > len);
 
                        i = 0;
-                       nfrags = skb_shinfo(fskb)->nr_frags;
-                       skb_frag = skb_shinfo(fskb)->frags;
-                       pos += skb_headlen(fskb);
+                       nfrags = skb_shinfo(list_skb)->nr_frags;
+                       frag = skb_shinfo(list_skb)->frags;
+                       frag_skb = list_skb;
+                       pos += skb_headlen(list_skb);
 
                        while (pos < offset + len) {
                                BUG_ON(i >= nfrags);
 
-                               size = skb_frag_size(skb_frag);
+                               size = skb_frag_size(frag);
                                if (pos + size > offset + len)
                                        break;
 
                                i++;
                                pos += size;
-                               skb_frag++;
+                               frag++;
                        }
 
-                       nskb = skb_clone(fskb, GFP_ATOMIC);
-                       fskb = fskb->next;
+                       nskb = skb_clone(list_skb, GFP_ATOMIC);
+                       list_skb = list_skb->next;
 
                        if (unlikely(!nskb))
                                goto err;
@@ -2936,7 +2950,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                        __skb_push(nskb, doffset);
                } else {
                        nskb = __alloc_skb(hsize + doffset + headroom,
-                                          GFP_ATOMIC, skb_alloc_rx_flag(skb),
+                                          GFP_ATOMIC, skb_alloc_rx_flag(head_skb),
                                           NUMA_NO_NODE);
 
                        if (unlikely(!nskb))
@@ -2952,12 +2966,12 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                        segs = nskb;
                tail = nskb;
 
-               __copy_skb_header(nskb, skb);
-               nskb->mac_len = skb->mac_len;
+               __copy_skb_header(nskb, head_skb);
+               nskb->mac_len = head_skb->mac_len;
 
                skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom);
 
-               skb_copy_from_linear_data_offset(skb, -tnl_hlen,
+               skb_copy_from_linear_data_offset(head_skb, -tnl_hlen,
                                                 nskb->data - tnl_hlen,
                                                 doffset + tnl_hlen);
 
@@ -2966,30 +2980,32 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
 
                if (!sg) {
                        nskb->ip_summed = CHECKSUM_NONE;
-                       nskb->csum = skb_copy_and_csum_bits(skb, offset,
+                       nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
                                                            skb_put(nskb, len),
                                                            len, 0);
                        continue;
                }
 
-               frag = skb_shinfo(nskb)->frags;
+               nskb_frag = skb_shinfo(nskb)->frags;
 
-               skb_copy_from_linear_data_offset(skb, offset,
+               skb_copy_from_linear_data_offset(head_skb, offset,
                                                 skb_put(nskb, hsize), hsize);
 
-               skb_shinfo(nskb)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+               skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
+                       SKBTX_SHARED_FRAG;
 
                while (pos < offset + len) {
                        if (i >= nfrags) {
-                               BUG_ON(skb_headlen(fskb));
+                               BUG_ON(skb_headlen(list_skb));
 
                                i = 0;
-                               nfrags = skb_shinfo(fskb)->nr_frags;
-                               skb_frag = skb_shinfo(fskb)->frags;
+                               nfrags = skb_shinfo(list_skb)->nr_frags;
+                               frag = skb_shinfo(list_skb)->frags;
+                               frag_skb = list_skb;
 
                                BUG_ON(!nfrags);
 
-                               fskb = fskb->next;
+                               list_skb = list_skb->next;
                        }
 
                        if (unlikely(skb_shinfo(nskb)->nr_frags >=
@@ -3000,27 +3016,30 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features)
                                goto err;
                        }
 
-                       *frag = *skb_frag;
-                       __skb_frag_ref(frag);
-                       size = skb_frag_size(frag);
+                       if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC)))
+                               goto err;
+
+                       *nskb_frag = *frag;
+                       __skb_frag_ref(nskb_frag);
+                       size = skb_frag_size(nskb_frag);
 
                        if (pos < offset) {
-                               frag->page_offset += offset - pos;
-                               skb_frag_size_sub(frag, offset - pos);
+                               nskb_frag->page_offset += offset - pos;
+                               skb_frag_size_sub(nskb_frag, offset - pos);
                        }
 
                        skb_shinfo(nskb)->nr_frags++;
 
                        if (pos + size <= offset + len) {
                                i++;
-                               skb_frag++;
+                               frag++;
                                pos += size;
                        } else {
-                               skb_frag_size_sub(frag, pos + size - (offset + len));
+                               skb_frag_size_sub(nskb_frag, pos + size - (offset + len));
                                goto skip_fraglist;
                        }
 
-                       frag++;
+                       nskb_frag++;
                }
 
 skip_fraglist:
@@ -3034,7 +3053,7 @@ perform_csum_check:
                                                  nskb->len - doffset, 0);
                        nskb->ip_summed = CHECKSUM_NONE;
                }
-       } while ((offset += len) < skb->len);
+       } while ((offset += len) < head_skb->len);
 
        return segs;
 
@@ -3281,6 +3300,32 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
        return elt;
 }
 
+/* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given
+ * sglist without mark the sg which contain last skb data as the end.
+ * So the caller can mannipulate sg list as will when padding new data after
+ * the first call without calling sg_unmark_end to expend sg list.
+ *
+ * Scenario to use skb_to_sgvec_nomark:
+ * 1. sg_init_table
+ * 2. skb_to_sgvec_nomark(payload1)
+ * 3. skb_to_sgvec_nomark(payload2)
+ *
+ * This is equivalent to:
+ * 1. sg_init_table
+ * 2. skb_to_sgvec(payload1)
+ * 3. sg_unmark_end
+ * 4. skb_to_sgvec(payload2)
+ *
+ * When mapping mutilple payload conditionally, skb_to_sgvec_nomark
+ * is more preferable.
+ */
+int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
+                       int offset, int len)
+{
+       return __skb_to_sgvec(skb, sg, offset, len);
+}
+EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark);
+
 int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
 {
        int nsg = __skb_to_sgvec(skb, sg, offset, len);
@@ -3543,15 +3588,47 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len,
        return 0;
 }
 
+#define MAX_TCP_HDR_LEN (15 * 4)
+
+static __sum16 *skb_checksum_setup_ip(struct sk_buff *skb,
+                                     typeof(IPPROTO_IP) proto,
+                                     unsigned int off)
+{
+       switch (proto) {
+               int err;
+
+       case IPPROTO_TCP:
+               err = skb_maybe_pull_tail(skb, off + sizeof(struct tcphdr),
+                                         off + MAX_TCP_HDR_LEN);
+               if (!err && !skb_partial_csum_set(skb, off,
+                                                 offsetof(struct tcphdr,
+                                                          check)))
+                       err = -EPROTO;
+               return err ? ERR_PTR(err) : &tcp_hdr(skb)->check;
+
+       case IPPROTO_UDP:
+               err = skb_maybe_pull_tail(skb, off + sizeof(struct udphdr),
+                                         off + sizeof(struct udphdr));
+               if (!err && !skb_partial_csum_set(skb, off,
+                                                 offsetof(struct udphdr,
+                                                          check)))
+                       err = -EPROTO;
+               return err ? ERR_PTR(err) : &udp_hdr(skb)->check;
+       }
+
+       return ERR_PTR(-EPROTO);
+}
+
 /* This value should be large enough to cover a tagged ethernet header plus
  * maximally sized IP and TCP or UDP headers.
  */
 #define MAX_IP_HDR_LEN 128
 
-static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate)
+static int skb_checksum_setup_ipv4(struct sk_buff *skb, bool recalculate)
 {
        unsigned int off;
        bool fragment;
+       __sum16 *csum;
        int err;
 
        fragment = false;
@@ -3572,51 +3649,15 @@ static int skb_checksum_setup_ip(struct sk_buff *skb, bool recalculate)
        if (fragment)
                goto out;
 
-       switch (ip_hdr(skb)->protocol) {
-       case IPPROTO_TCP:
-               err = skb_maybe_pull_tail(skb,
-                                         off + sizeof(struct tcphdr),
-                                         MAX_IP_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct tcphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate)
-                       tcp_hdr(skb)->check =
-                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                  ip_hdr(skb)->daddr,
-                                                  skb->len - off,
-                                                  IPPROTO_TCP, 0);
-               break;
-       case IPPROTO_UDP:
-               err = skb_maybe_pull_tail(skb,
-                                         off + sizeof(struct udphdr),
-                                         MAX_IP_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct udphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate)
-                       udp_hdr(skb)->check =
-                               ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
-                                                  ip_hdr(skb)->daddr,
-                                                  skb->len - off,
-                                                  IPPROTO_UDP, 0);
-               break;
-       default:
-               goto out;
-       }
+       csum = skb_checksum_setup_ip(skb, ip_hdr(skb)->protocol, off);
+       if (IS_ERR(csum))
+               return PTR_ERR(csum);
 
+       if (recalculate)
+               *csum = ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
+                                          ip_hdr(skb)->daddr,
+                                          skb->len - off,
+                                          ip_hdr(skb)->protocol, 0);
        err = 0;
 
 out:
@@ -3639,6 +3680,7 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
        unsigned int len;
        bool fragment;
        bool done;
+       __sum16 *csum;
 
        fragment = false;
        done = false;
@@ -3716,51 +3758,14 @@ static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate)
        if (!done || fragment)
                goto out;
 
-       switch (nexthdr) {
-       case IPPROTO_TCP:
-               err = skb_maybe_pull_tail(skb,
-                                         off + sizeof(struct tcphdr),
-                                         MAX_IPV6_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct tcphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate)
-                       tcp_hdr(skb)->check =
-                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                &ipv6_hdr(skb)->daddr,
-                                                skb->len - off,
-                                                IPPROTO_TCP, 0);
-               break;
-       case IPPROTO_UDP:
-               err = skb_maybe_pull_tail(skb,
-                                         off + sizeof(struct udphdr),
-                                         MAX_IPV6_HDR_LEN);
-               if (err < 0)
-                       goto out;
-
-               if (!skb_partial_csum_set(skb, off,
-                                         offsetof(struct udphdr, check))) {
-                       err = -EPROTO;
-                       goto out;
-               }
-
-               if (recalculate)
-                       udp_hdr(skb)->check =
-                               ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-                                                &ipv6_hdr(skb)->daddr,
-                                                skb->len - off,
-                                                IPPROTO_UDP, 0);
-               break;
-       default:
-               goto out;
-       }
+       csum = skb_checksum_setup_ip(skb, nexthdr, off);
+       if (IS_ERR(csum))
+               return PTR_ERR(csum);
 
+       if (recalculate)
+               *csum = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+                                        &ipv6_hdr(skb)->daddr,
+                                        skb->len - off, nexthdr, 0);
        err = 0;
 
 out:
@@ -3778,7 +3783,7 @@ int skb_checksum_setup(struct sk_buff *skb, bool recalculate)
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
-               err = skb_checksum_setup_ip(skb, recalculate);
+               err = skb_checksum_setup_ipv4(skb, recalculate);
                break;
 
        case htons(ETH_P_IPV6):
index 0c127dcdf6a8ba9d25d544b02bf798d25fd67f6e..c0fc6bdad1e3629f123244d6d7c77805c9b5f0bd 100644 (file)
@@ -1775,7 +1775,9 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
                        while (order) {
                                if (npages >= 1 << order) {
                                        page = alloc_pages(sk->sk_allocation |
-                                                          __GFP_COMP | __GFP_NOWARN,
+                                                          __GFP_COMP |
+                                                          __GFP_NOWARN |
+                                                          __GFP_NORETRY,
                                                           order);
                                        if (page)
                                                goto fill_page;
@@ -1845,7 +1847,7 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio)
                gfp_t gfp = prio;
 
                if (order)
-                       gfp |= __GFP_COMP | __GFP_NOWARN;
+                       gfp |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY;
                pfrag->page = alloc_pages(gfp, order);
                if (likely(pfrag->page)) {
                        pfrag->offset = 0;
@@ -2355,10 +2357,13 @@ void release_sock(struct sock *sk)
        if (sk->sk_backlog.tail)
                __release_sock(sk);
 
+       /* Warning : release_cb() might need to release sk ownership,
+        * ie call sock_release_ownership(sk) before us.
+        */
        if (sk->sk_prot->release_cb)
                sk->sk_prot->release_cb(sk);
 
-       sk->sk_lock.owned = 0;
+       sock_release_ownership(sk);
        if (waitqueue_active(&sk->sk_lock.wq))
                wake_up(&sk->sk_lock.wq);
        spin_unlock_bh(&sk->sk_lock.slock);
index a0e9cf6379de3eac8ac1182c3be73e8d140b4a1b..d7af1885932269eb9f4196fe1211a6d09e298b97 100644 (file)
@@ -52,9 +52,10 @@ EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
 int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
                             struct sk_buff *skb, int attrtype)
 {
-       struct nlattr *attr;
+       struct sock_fprog_kern *fprog;
        struct sk_filter *filter;
-       unsigned int len;
+       struct nlattr *attr;
+       unsigned int flen;
        int err = 0;
 
        if (!ns_capable(user_ns, CAP_NET_ADMIN)) {
@@ -63,24 +64,20 @@ int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
        }
 
        rcu_read_lock();
-
        filter = rcu_dereference(sk->sk_filter);
-       len = filter ? filter->len * sizeof(struct sock_filter) : 0;
+       if (!filter)
+               goto out;
 
-       attr = nla_reserve(skb, attrtype, len);
+       fprog = filter->orig_prog;
+       flen = sk_filter_proglen(fprog);
+
+       attr = nla_reserve(skb, attrtype, flen);
        if (attr == NULL) {
                err = -EMSGSIZE;
                goto out;
        }
 
-       if (filter) {
-               struct sock_filter *fb = (struct sock_filter *)nla_data(attr);
-               int i;
-
-               for (i = 0; i < filter->len; i++, fb++)
-                       sk_decode_filter(&filter->insns[i], fb);
-       }
-
+       memcpy(nla_data(attr), fprog->filter, flen);
 out:
        rcu_read_unlock();
        return err;
index 661b5a40ec1029016a4a2e70579c690c40110512..9ff26b3cc021b1c3e80d80f5dfff7d726a0c46e9 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/export.h>
 
-static struct sock_filter ptp_filter[] = {
-       PTP_FILTER
-};
+static struct sk_filter *ptp_insns __read_mostly;
+
+unsigned int ptp_classify_raw(const struct sk_buff *skb)
+{
+       return SK_RUN_FILTER(ptp_insns, skb);
+}
+EXPORT_SYMBOL_GPL(ptp_classify_raw);
 
 static unsigned int classify(const struct sk_buff *skb)
 {
-       if (likely(skb->dev &&
-                  skb->dev->phydev &&
+       if (likely(skb->dev && skb->dev->phydev &&
                   skb->dev->phydev->drv))
-               return sk_run_filter(skb, ptp_filter);
+               return ptp_classify_raw(skb);
        else
                return PTP_CLASS_NONE;
 }
@@ -60,11 +63,13 @@ void skb_clone_tx_timestamp(struct sk_buff *skb)
                if (likely(phydev->drv->txtstamp)) {
                        if (!atomic_inc_not_zero(&sk->sk_refcnt))
                                return;
+
                        clone = skb_clone(skb, GFP_ATOMIC);
                        if (!clone) {
                                sock_put(sk);
                                return;
                        }
+
                        clone->sk = sk;
                        phydev->drv->txtstamp(phydev, clone, type);
                }
@@ -89,12 +94,15 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
        }
 
        *skb_hwtstamps(skb) = *hwtstamps;
+
        serr = SKB_EXT_ERR(skb);
        memset(serr, 0, sizeof(*serr));
        serr->ee.ee_errno = ENOMSG;
        serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
        skb->sk = NULL;
+
        err = sock_queue_err_skb(sk, skb);
+
        sock_put(sk);
        if (err)
                kfree_skb(skb);
@@ -135,5 +143,10 @@ EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp);
 
 void __init skb_timestamping_init(void)
 {
-       BUG_ON(sk_chk_filter(ptp_filter, ARRAY_SIZE(ptp_filter)));
+       static struct sock_filter ptp_filter[] = { PTP_FILTER };
+       struct sock_fprog ptp_prog = {
+               .len = ARRAY_SIZE(ptp_filter), .filter = ptp_filter,
+       };
+
+       BUG_ON(sk_unattached_filter_create(&ptp_insns, &ptp_prog));
 }
index c073b81a1f3e74887783dbd6096b77629d12fbe0..62b5828acde0906b71fc39955c9f2b36582d395a 100644 (file)
@@ -8,7 +8,7 @@
 #include "tfrc.h"
 
 #ifdef CONFIG_IP_DCCP_TFRC_DEBUG
-static bool tfrc_debug;
+bool tfrc_debug;
 module_param(tfrc_debug, bool, 0644);
 MODULE_PARM_DESC(tfrc_debug, "Enable TFRC debug messages");
 #endif
index a3d8f7c76ae091ba92704a3e6a70186c53b3b0f5..40ee7d62b6520d7daf2a1a8f3b54bda9cfbedfc2 100644 (file)
@@ -21,6 +21,7 @@
 #include "packet_history.h"
 
 #ifdef CONFIG_IP_DCCP_TFRC_DEBUG
+extern bool tfrc_debug;
 #define tfrc_pr_debug(format, a...)    DCCP_PR_DEBUG(tfrc_debug, format, ##a)
 #else
 #define tfrc_pr_debug(format, a...)
index 2954dcbca8325d81cab149613554d380bc607469..4c04848953bdb4caddeae9debd195ea3d004ee0d 100644 (file)
@@ -2104,8 +2104,6 @@ static struct notifier_block dn_dev_notifier = {
        .notifier_call = dn_device_event,
 };
 
-extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
-
 static struct packet_type dn_dix_packet_type __read_mostly = {
        .type =         cpu_to_be16(ETH_P_DNA_RT),
        .func =         dn_route_rcv,
@@ -2353,9 +2351,6 @@ static const struct proto_ops dn_proto_ops = {
        .sendpage =     sock_no_sendpage,
 };
 
-void dn_register_sysctl(void);
-void dn_unregister_sysctl(void);
-
 MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
 MODULE_AUTHOR("Linux DECnet Project Team");
 MODULE_LICENSE("GPL");
index cac505f166d51133a32dac0e08c12358871fe6f6..e5302b7f7ca9f0f6f67954689572d6a5b09a3c74 100644 (file)
@@ -209,7 +209,7 @@ static int slave_xmit(struct sk_buff *skb, struct hsr_priv *hsr_priv,
        /* Address substitution (IEC62439-3 pp 26, 50): replace mac
         * address of outgoing frame with that of the outgoing slave's.
         */
-       memcpy(hsr_ethhdr->ethhdr.h_source, skb->dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(hsr_ethhdr->ethhdr.h_source, skb->dev->dev_addr);
 
        return dev_queue_xmit(skb);
 }
@@ -346,7 +346,7 @@ static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type)
 
        /* Payload: MacAddressA */
        hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp));
-       memcpy(hsr_sp->MacAddressA, hsr_dev->dev_addr, ETH_ALEN);
+       ether_addr_copy(hsr_sp->MacAddressA, hsr_dev->dev_addr);
 
        dev_queue_xmit(skb);
        return;
@@ -493,7 +493,7 @@ static int check_slave_ok(struct net_device *dev)
 
 
 /* Default multicast address for HSR Supervision frames */
-static const unsigned char def_multicast_addr[ETH_ALEN] = {
+static const unsigned char def_multicast_addr[ETH_ALEN] __aligned(2) = {
        0x01, 0x15, 0x4e, 0x00, 0x01, 0x00
 };
 
@@ -519,7 +519,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
        hsr_priv->announce_timer.function = hsr_announce;
        hsr_priv->announce_timer.data = (unsigned long) hsr_priv;
 
-       memcpy(hsr_priv->sup_multicast_addr, def_multicast_addr, ETH_ALEN);
+       ether_addr_copy(hsr_priv->sup_multicast_addr, def_multicast_addr);
        hsr_priv->sup_multicast_addr[ETH_ALEN - 1] = multicast_spec;
 
 /* FIXME: should I modify the value of these?
@@ -547,7 +547,7 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
        hsr_dev->features |= NETIF_F_VLAN_CHALLENGED;
 
        /* Set hsr_dev's MAC address to that of mac_slave1 */
-       memcpy(hsr_dev->dev_addr, hsr_priv->slave[0]->dev_addr, ETH_ALEN);
+       ether_addr_copy(hsr_dev->dev_addr, hsr_priv->slave[0]->dev_addr);
 
        /* Set required header length */
        for (i = 0; i < HSR_MAX_SLAVE; i++) {
index 327060c6c874b337cf6edf9bd37c5b8181c0beee..83e58449366a92bcc4e349241337914bca8dcd10 100644 (file)
@@ -108,8 +108,8 @@ int hsr_create_self_node(struct list_head *self_node_db,
        if (!node)
                return -ENOMEM;
 
-       memcpy(node->MacAddressA, addr_a, ETH_ALEN);
-       memcpy(node->MacAddressB, addr_b, ETH_ALEN);
+       ether_addr_copy(node->MacAddressA, addr_a);
+       ether_addr_copy(node->MacAddressB, addr_b);
 
        rcu_read_lock();
        oldnode = list_first_or_null_rcu(self_node_db,
@@ -199,7 +199,7 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv,
                /* Node is known, but frame was received from an unknown
                 * address. Node is PICS_SUBS capable; merge its AddrB.
                 */
-               memcpy(node->MacAddressB, hsr_ethsup->ethhdr.h_source, ETH_ALEN);
+               ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source);
                node->AddrB_if = dev_idx;
                return node;
        }
@@ -208,8 +208,8 @@ struct node_entry *hsr_merge_node(struct hsr_priv *hsr_priv,
        if (!node)
                return NULL;
 
-       memcpy(node->MacAddressA, hsr_sp->MacAddressA, ETH_ALEN);
-       memcpy(node->MacAddressB, hsr_ethsup->ethhdr.h_source, ETH_ALEN);
+       ether_addr_copy(node->MacAddressA, hsr_sp->MacAddressA);
+       ether_addr_copy(node->MacAddressB, hsr_ethsup->ethhdr.h_source);
        if (!ether_addr_equal(hsr_sp->MacAddressA, hsr_ethsup->ethhdr.h_source))
                node->AddrB_if = dev_idx;
        else
@@ -250,7 +250,7 @@ void hsr_addr_subst_source(struct hsr_priv *hsr_priv, struct sk_buff *skb)
        rcu_read_lock();
        node = find_node_by_AddrB(&hsr_priv->node_db, ethhdr->h_source);
        if (node)
-               memcpy(ethhdr->h_source, node->MacAddressA, ETH_ALEN);
+               ether_addr_copy(ethhdr->h_source, node->MacAddressA);
        rcu_read_unlock();
 }
 
@@ -272,7 +272,7 @@ void hsr_addr_subst_dest(struct hsr_priv *hsr_priv, struct ethhdr *ethhdr,
        rcu_read_lock();
        node = find_node_by_AddrA(&hsr_priv->node_db, ethhdr->h_dest);
        if (node && (node->AddrB_if == dev_idx))
-               memcpy(ethhdr->h_dest, node->MacAddressB, ETH_ALEN);
+               ether_addr_copy(ethhdr->h_dest, node->MacAddressB);
        rcu_read_unlock();
 }
 
@@ -297,7 +297,7 @@ static bool seq_nr_after(u16 a, u16 b)
 
 void hsr_register_frame_in(struct node_entry *node, enum hsr_dev_idx dev_idx)
 {
-       if ((dev_idx < 0) || (dev_idx >= HSR_MAX_DEV)) {
+       if ((dev_idx < 0) || (dev_idx >= HSR_MAX_SLAVE)) {
                WARN_ONCE(1, "%s: Invalid dev_idx (%d)\n", __func__, dev_idx);
                return;
        }
@@ -428,13 +428,13 @@ void *hsr_get_next_node(struct hsr_priv *hsr_priv, void *_pos,
                node = list_first_or_null_rcu(&hsr_priv->node_db,
                                                struct node_entry, mac_list);
                if (node)
-                       memcpy(addr, node->MacAddressA, ETH_ALEN);
+                       ether_addr_copy(addr, node->MacAddressA);
                return node;
        }
 
        node = _pos;
        list_for_each_entry_continue_rcu(node, &hsr_priv->node_db, mac_list) {
-               memcpy(addr, node->MacAddressA, ETH_ALEN);
+               ether_addr_copy(addr, node->MacAddressA);
                return node;
        }
 
@@ -462,7 +462,7 @@ int hsr_get_node_data(struct hsr_priv *hsr_priv,
                return -ENOENT; /* No such entry */
        }
 
-       memcpy(addr_b, node->MacAddressB, ETH_ALEN);
+       ether_addr_copy(addr_b, node->MacAddressB);
 
        tdiff = jiffies - node->time_in[HSR_DEV_SLAVE_A];
        if (node->time_in_stale[HSR_DEV_SLAVE_A])
index af68dd83a4e3df0ed12b18d5361d436fa3edd9f6..3fee5218a691f20c8b028e7ed2738febc7dfd0b7 100644 (file)
@@ -138,8 +138,8 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
                        break;
 
                if (dev == hsr_priv->slave[0])
-                       memcpy(hsr_priv->dev->dev_addr,
-                              hsr_priv->slave[0]->dev_addr, ETH_ALEN);
+                       ether_addr_copy(hsr_priv->dev->dev_addr,
+                                       hsr_priv->slave[0]->dev_addr);
 
                /* Make sure we recognize frames from ourselves in hsr_rcv() */
                res = hsr_create_self_node(&hsr_priv->self_node_db,
@@ -459,7 +459,7 @@ static int __init hsr_init(void)
 static void __exit hsr_exit(void)
 {
        unregister_netdevice_notifier(&hsr_nb);
-       del_timer(&prune_timer);
+       del_timer_sync(&prune_timer);
        hsr_netlink_exit();
        dev_remove_pack(&hsr_pt);
 }
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
deleted file mode 100644 (file)
index 48b25c0..0000000
+++ /dev/null
@@ -1,797 +0,0 @@
-/*
- * Copyright 2011, Siemens AG
- * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-/*
- * Based on patches from Jon Smirl <jonsmirl@gmail.com>
- * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/* Jon's code is based on 6lowpan implementation for Contiki which is:
- * Copyright (c) 2008, Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the Institute nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/bitops.h>
-#include <linux/if_arp.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/netdevice.h>
-#include <net/af_ieee802154.h>
-#include <net/ieee802154.h>
-#include <net/ieee802154_netdev.h>
-#include <net/ipv6.h>
-
-#include "6lowpan.h"
-
-static LIST_HEAD(lowpan_devices);
-
-/* private device info */
-struct lowpan_dev_info {
-       struct net_device       *real_dev; /* real WPAN device ptr */
-       struct mutex            dev_list_mtx; /* mutex for list ops */
-       unsigned short          fragment_tag;
-};
-
-struct lowpan_dev_record {
-       struct net_device *ldev;
-       struct list_head list;
-};
-
-struct lowpan_fragment {
-       struct sk_buff          *skb;           /* skb to be assembled */
-       u16                     length;         /* length to be assemled */
-       u32                     bytes_rcv;      /* bytes received */
-       u16                     tag;            /* current fragment tag */
-       struct timer_list       timer;          /* assembling timer */
-       struct list_head        list;           /* fragments list */
-};
-
-static LIST_HEAD(lowpan_fragments);
-static DEFINE_SPINLOCK(flist_lock);
-
-static inline struct
-lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
-{
-       return netdev_priv(dev);
-}
-
-static inline void lowpan_address_flip(u8 *src, u8 *dest)
-{
-       int i;
-       for (i = 0; i < IEEE802154_ADDR_LEN; i++)
-               (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
-}
-
-static int lowpan_header_create(struct sk_buff *skb,
-                          struct net_device *dev,
-                          unsigned short type, const void *_daddr,
-                          const void *_saddr, unsigned int len)
-{
-       struct ipv6hdr *hdr;
-       const u8 *saddr = _saddr;
-       const u8 *daddr = _daddr;
-       struct ieee802154_addr sa, da;
-
-       /* TODO:
-        * if this package isn't ipv6 one, where should it be routed?
-        */
-       if (type != ETH_P_IPV6)
-               return 0;
-
-       hdr = ipv6_hdr(skb);
-
-       if (!saddr)
-               saddr = dev->dev_addr;
-
-       raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
-       raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
-
-       lowpan_header_compress(skb, dev, type, daddr, saddr, len);
-
-       /*
-        * NOTE1: I'm still unsure about the fact that compression and WPAN
-        * header are created here and not later in the xmit. So wait for
-        * an opinion of net maintainers.
-        */
-       /*
-        * NOTE2: to be absolutely correct, we must derive PANid information
-        * from MAC subif of the 'dev' and 'real_dev' network devices, but
-        * this isn't implemented in mainline yet, so currently we assign 0xff
-        */
-       mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
-       mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
-
-       /* prepare wpan address data */
-       sa.addr_type = IEEE802154_ADDR_LONG;
-       sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
-
-       memcpy(&(sa.hwaddr), saddr, 8);
-       /* intra-PAN communications */
-       da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
-
-       /*
-        * if the destination address is the broadcast address, use the
-        * corresponding short address
-        */
-       if (lowpan_is_addr_broadcast(daddr)) {
-               da.addr_type = IEEE802154_ADDR_SHORT;
-               da.short_addr = IEEE802154_ADDR_BROADCAST;
-       } else {
-               da.addr_type = IEEE802154_ADDR_LONG;
-               memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
-
-               /* request acknowledgment */
-               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
-       }
-
-       return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
-                       type, (void *)&da, (void *)&sa, skb->len);
-}
-
-static int lowpan_give_skb_to_devices(struct sk_buff *skb,
-                                       struct net_device *dev)
-{
-       struct lowpan_dev_record *entry;
-       struct sk_buff *skb_cp;
-       int stat = NET_RX_SUCCESS;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(entry, &lowpan_devices, list)
-               if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
-                       skb_cp = skb_copy(skb, GFP_ATOMIC);
-                       if (!skb_cp) {
-                               stat = -ENOMEM;
-                               break;
-                       }
-
-                       skb_cp->dev = entry->ldev;
-                       stat = netif_rx(skb_cp);
-               }
-       rcu_read_unlock();
-
-       return stat;
-}
-
-static void lowpan_fragment_timer_expired(unsigned long entry_addr)
-{
-       struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
-
-       pr_debug("timer expired for frame with tag %d\n", entry->tag);
-
-       list_del(&entry->list);
-       dev_kfree_skb(entry->skb);
-       kfree(entry);
-}
-
-static struct lowpan_fragment *
-lowpan_alloc_new_frame(struct sk_buff *skb, u16 len, u16 tag)
-{
-       struct lowpan_fragment *frame;
-
-       frame = kzalloc(sizeof(struct lowpan_fragment),
-                       GFP_ATOMIC);
-       if (!frame)
-               goto frame_err;
-
-       INIT_LIST_HEAD(&frame->list);
-
-       frame->length = len;
-       frame->tag = tag;
-
-       /* allocate buffer for frame assembling */
-       frame->skb = netdev_alloc_skb_ip_align(skb->dev, frame->length +
-                                              sizeof(struct ipv6hdr));
-
-       if (!frame->skb)
-               goto skb_err;
-
-       frame->skb->priority = skb->priority;
-
-       /* reserve headroom for uncompressed ipv6 header */
-       skb_reserve(frame->skb, sizeof(struct ipv6hdr));
-       skb_put(frame->skb, frame->length);
-
-       /* copy the first control block to keep a
-        * trace of the link-layer addresses in case
-        * of a link-local compressed address
-        */
-       memcpy(frame->skb->cb, skb->cb, sizeof(skb->cb));
-
-       init_timer(&frame->timer);
-       /* time out is the same as for ipv6 - 60 sec */
-       frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
-       frame->timer.data = (unsigned long)frame;
-       frame->timer.function = lowpan_fragment_timer_expired;
-
-       add_timer(&frame->timer);
-
-       list_add_tail(&frame->list, &lowpan_fragments);
-
-       return frame;
-
-skb_err:
-       kfree(frame);
-frame_err:
-       return NULL;
-}
-
-static int process_data(struct sk_buff *skb)
-{
-       u8 iphc0, iphc1;
-       const struct ieee802154_addr *_saddr, *_daddr;
-
-       raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
-       /* at least two bytes will be used for the encoding */
-       if (skb->len < 2)
-               goto drop;
-
-       if (lowpan_fetch_skb_u8(skb, &iphc0))
-               goto drop;
-
-       /* fragments assembling */
-       switch (iphc0 & LOWPAN_DISPATCH_MASK) {
-       case LOWPAN_DISPATCH_FRAG1:
-       case LOWPAN_DISPATCH_FRAGN:
-       {
-               struct lowpan_fragment *frame;
-               /* slen stores the rightmost 8 bits of the 11 bits length */
-               u8 slen, offset = 0;
-               u16 len, tag;
-               bool found = false;
-
-               if (lowpan_fetch_skb_u8(skb, &slen) || /* frame length */
-                   lowpan_fetch_skb_u16(skb, &tag))  /* fragment tag */
-                       goto drop;
-
-               /* adds the 3 MSB to the 8 LSB to retrieve the 11 bits length */
-               len = ((iphc0 & 7) << 8) | slen;
-
-               if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) {
-                       pr_debug("%s received a FRAG1 packet (tag: %d, "
-                                "size of the entire IP packet: %d)",
-                                __func__, tag, len);
-               } else { /* FRAGN */
-                       if (lowpan_fetch_skb_u8(skb, &offset))
-                               goto unlock_and_drop;
-                       pr_debug("%s received a FRAGN packet (tag: %d, "
-                                "size of the entire IP packet: %d, "
-                                "offset: %d)", __func__, tag, len, offset * 8);
-               }
-
-               /*
-                * check if frame assembling with the same tag is
-                * already in progress
-                */
-               spin_lock_bh(&flist_lock);
-
-               list_for_each_entry(frame, &lowpan_fragments, list)
-                       if (frame->tag == tag) {
-                               found = true;
-                               break;
-                       }
-
-               /* alloc new frame structure */
-               if (!found) {
-                       pr_debug("%s first fragment received for tag %d, "
-                                "begin packet reassembly", __func__, tag);
-                       frame = lowpan_alloc_new_frame(skb, len, tag);
-                       if (!frame)
-                               goto unlock_and_drop;
-               }
-
-               /* if payload fits buffer, copy it */
-               if (likely((offset * 8 + skb->len) <= frame->length))
-                       skb_copy_to_linear_data_offset(frame->skb, offset * 8,
-                                                       skb->data, skb->len);
-               else
-                       goto unlock_and_drop;
-
-               frame->bytes_rcv += skb->len;
-
-               /* frame assembling complete */
-               if ((frame->bytes_rcv == frame->length) &&
-                    frame->timer.expires > jiffies) {
-                       /* if timer haven't expired - first of all delete it */
-                       del_timer_sync(&frame->timer);
-                       list_del(&frame->list);
-                       spin_unlock_bh(&flist_lock);
-
-                       pr_debug("%s successfully reassembled fragment "
-                                "(tag %d)", __func__, tag);
-
-                       dev_kfree_skb(skb);
-                       skb = frame->skb;
-                       kfree(frame);
-
-                       if (lowpan_fetch_skb_u8(skb, &iphc0))
-                               goto drop;
-
-                       break;
-               }
-               spin_unlock_bh(&flist_lock);
-
-               return kfree_skb(skb), 0;
-       }
-       default:
-               break;
-       }
-
-       if (lowpan_fetch_skb_u8(skb, &iphc1))
-               goto drop;
-
-       _saddr = &mac_cb(skb)->sa;
-       _daddr = &mac_cb(skb)->da;
-
-       return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr,
-                               _saddr->addr_type, IEEE802154_ADDR_LEN,
-                               (u8 *)_daddr->hwaddr, _daddr->addr_type,
-                               IEEE802154_ADDR_LEN, iphc0, iphc1,
-                               lowpan_give_skb_to_devices);
-
-unlock_and_drop:
-       spin_unlock_bh(&flist_lock);
-drop:
-       kfree_skb(skb);
-       return -EINVAL;
-}
-
-static int lowpan_set_address(struct net_device *dev, void *p)
-{
-       struct sockaddr *sa = p;
-
-       if (netif_running(dev))
-               return -EBUSY;
-
-       /* TODO: validate addr */
-       memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
-
-       return 0;
-}
-
-static int
-lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
-                       int mlen, int plen, int offset, int type)
-{
-       struct sk_buff *frag;
-       int hlen;
-
-       hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
-                       LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
-
-       raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
-
-       frag = netdev_alloc_skb(skb->dev,
-                               hlen + mlen + plen + IEEE802154_MFR_SIZE);
-       if (!frag)
-               return -ENOMEM;
-
-       frag->priority = skb->priority;
-
-       /* copy header, MFR and payload */
-       skb_put(frag, mlen);
-       skb_copy_to_linear_data(frag, skb_mac_header(skb), mlen);
-
-       skb_put(frag, hlen);
-       skb_copy_to_linear_data_offset(frag, mlen, head, hlen);
-
-       skb_put(frag, plen);
-       skb_copy_to_linear_data_offset(frag, mlen + hlen,
-                                      skb_network_header(skb) + offset, plen);
-
-       raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len);
-
-       return dev_queue_xmit(frag);
-}
-
-static int
-lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
-{
-       int  err, header_length, payload_length, tag, offset = 0;
-       u8 head[5];
-
-       header_length = skb->mac_len;
-       payload_length = skb->len - header_length;
-       tag = lowpan_dev_info(dev)->fragment_tag++;
-
-       /* first fragment header */
-       head[0] = LOWPAN_DISPATCH_FRAG1 | ((payload_length >> 8) & 0x7);
-       head[1] = payload_length & 0xff;
-       head[2] = tag >> 8;
-       head[3] = tag & 0xff;
-
-       err = lowpan_fragment_xmit(skb, head, header_length, LOWPAN_FRAG_SIZE,
-                                  0, LOWPAN_DISPATCH_FRAG1);
-
-       if (err) {
-               pr_debug("%s unable to send FRAG1 packet (tag: %d)",
-                        __func__, tag);
-               goto exit;
-       }
-
-       offset = LOWPAN_FRAG_SIZE;
-
-       /* next fragment header */
-       head[0] &= ~LOWPAN_DISPATCH_FRAG1;
-       head[0] |= LOWPAN_DISPATCH_FRAGN;
-
-       while (payload_length - offset > 0) {
-               int len = LOWPAN_FRAG_SIZE;
-
-               head[4] = offset / 8;
-
-               if (payload_length - offset < len)
-                       len = payload_length - offset;
-
-               err = lowpan_fragment_xmit(skb, head, header_length,
-                                          len, offset, LOWPAN_DISPATCH_FRAGN);
-               if (err) {
-                       pr_debug("%s unable to send a subsequent FRAGN packet "
-                                "(tag: %d, offset: %d", __func__, tag, offset);
-                       goto exit;
-               }
-
-               offset += len;
-       }
-
-exit:
-       return err;
-}
-
-static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       int err = -1;
-
-       pr_debug("package xmit\n");
-
-       skb->dev = lowpan_dev_info(dev)->real_dev;
-       if (skb->dev == NULL) {
-               pr_debug("ERROR: no real wpan device found\n");
-               goto error;
-       }
-
-       /* Send directly if less than the MTU minus the 2 checksum bytes. */
-       if (skb->len <= IEEE802154_MTU - IEEE802154_MFR_SIZE) {
-               err = dev_queue_xmit(skb);
-               goto out;
-       }
-
-       pr_debug("frame is too big, fragmentation is needed\n");
-       err = lowpan_skb_fragmentation(skb, dev);
-error:
-       dev_kfree_skb(skb);
-out:
-       if (err)
-               pr_debug("ERROR: xmit failed\n");
-
-       return (err < 0) ? NET_XMIT_DROP : err;
-}
-
-static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
-{
-       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-       return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
-}
-
-static u16 lowpan_get_pan_id(const struct net_device *dev)
-{
-       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-       return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
-}
-
-static u16 lowpan_get_short_addr(const struct net_device *dev)
-{
-       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-       return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
-}
-
-static u8 lowpan_get_dsn(const struct net_device *dev)
-{
-       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
-       return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev);
-}
-
-static struct header_ops lowpan_header_ops = {
-       .create = lowpan_header_create,
-};
-
-static const struct net_device_ops lowpan_netdev_ops = {
-       .ndo_start_xmit         = lowpan_xmit,
-       .ndo_set_mac_address    = lowpan_set_address,
-};
-
-static struct ieee802154_mlme_ops lowpan_mlme = {
-       .get_pan_id = lowpan_get_pan_id,
-       .get_phy = lowpan_get_phy,
-       .get_short_addr = lowpan_get_short_addr,
-       .get_dsn = lowpan_get_dsn,
-};
-
-static void lowpan_setup(struct net_device *dev)
-{
-       dev->addr_len           = IEEE802154_ADDR_LEN;
-       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
-       dev->type               = ARPHRD_IEEE802154;
-       /* Frame Control + Sequence Number + Address fields + Security Header */
-       dev->hard_header_len    = 2 + 1 + 20 + 14;
-       dev->needed_tailroom    = 2; /* FCS */
-       dev->mtu                = 1281;
-       dev->tx_queue_len       = 0;
-       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
-       dev->watchdog_timeo     = 0;
-
-       dev->netdev_ops         = &lowpan_netdev_ops;
-       dev->header_ops         = &lowpan_header_ops;
-       dev->ml_priv            = &lowpan_mlme;
-       dev->destructor         = free_netdev;
-}
-
-static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
-{
-       if (tb[IFLA_ADDRESS]) {
-               if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
-       struct packet_type *pt, struct net_device *orig_dev)
-{
-       struct sk_buff *local_skb;
-
-       if (!netif_running(dev))
-               goto drop;
-
-       if (dev->type != ARPHRD_IEEE802154)
-               goto drop;
-
-       /* check that it's our buffer */
-       if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
-               /* Copy the packet so that the IPv6 header is
-                * properly aligned.
-                */
-               local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
-                                           skb_tailroom(skb), GFP_ATOMIC);
-               if (!local_skb)
-                       goto drop;
-
-               local_skb->protocol = htons(ETH_P_IPV6);
-               local_skb->pkt_type = PACKET_HOST;
-
-               /* Pull off the 1-byte of 6lowpan header. */
-               skb_pull(local_skb, 1);
-
-               lowpan_give_skb_to_devices(local_skb, NULL);
-
-               kfree_skb(local_skb);
-               kfree_skb(skb);
-       } else {
-               switch (skb->data[0] & 0xe0) {
-               case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
-               case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
-               case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
-                       local_skb = skb_clone(skb, GFP_ATOMIC);
-                       if (!local_skb)
-                               goto drop;
-                       process_data(local_skb);
-
-                       kfree_skb(skb);
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       return NET_RX_SUCCESS;
-
-drop:
-       kfree_skb(skb);
-       return NET_RX_DROP;
-}
-
-static int lowpan_newlink(struct net *src_net, struct net_device *dev,
-                         struct nlattr *tb[], struct nlattr *data[])
-{
-       struct net_device *real_dev;
-       struct lowpan_dev_record *entry;
-
-       pr_debug("adding new link\n");
-
-       if (!tb[IFLA_LINK])
-               return -EINVAL;
-       /* find and hold real wpan device */
-       real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
-       if (!real_dev)
-               return -ENODEV;
-       if (real_dev->type != ARPHRD_IEEE802154) {
-               dev_put(real_dev);
-               return -EINVAL;
-       }
-
-       lowpan_dev_info(dev)->real_dev = real_dev;
-       lowpan_dev_info(dev)->fragment_tag = 0;
-       mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
-
-       entry = kzalloc(sizeof(struct lowpan_dev_record), GFP_KERNEL);
-       if (!entry) {
-               dev_put(real_dev);
-               lowpan_dev_info(dev)->real_dev = NULL;
-               return -ENOMEM;
-       }
-
-       entry->ldev = dev;
-
-       /* Set the lowpan harware address to the wpan hardware address. */
-       memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN);
-
-       mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
-       INIT_LIST_HEAD(&entry->list);
-       list_add_tail(&entry->list, &lowpan_devices);
-       mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
-
-       register_netdevice(dev);
-
-       return 0;
-}
-
-static void lowpan_dellink(struct net_device *dev, struct list_head *head)
-{
-       struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
-       struct net_device *real_dev = lowpan_dev->real_dev;
-       struct lowpan_dev_record *entry, *tmp;
-
-       ASSERT_RTNL();
-
-       mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
-       list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
-               if (entry->ldev == dev) {
-                       list_del(&entry->list);
-                       kfree(entry);
-               }
-       }
-       mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
-
-       mutex_destroy(&lowpan_dev_info(dev)->dev_list_mtx);
-
-       unregister_netdevice_queue(dev, head);
-
-       dev_put(real_dev);
-}
-
-static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
-       .kind           = "lowpan",
-       .priv_size      = sizeof(struct lowpan_dev_info),
-       .setup          = lowpan_setup,
-       .newlink        = lowpan_newlink,
-       .dellink        = lowpan_dellink,
-       .validate       = lowpan_validate,
-};
-
-static inline int __init lowpan_netlink_init(void)
-{
-       return rtnl_link_register(&lowpan_link_ops);
-}
-
-static inline void lowpan_netlink_fini(void)
-{
-       rtnl_link_unregister(&lowpan_link_ops);
-}
-
-static int lowpan_device_event(struct notifier_block *unused,
-                              unsigned long event, void *ptr)
-{
-       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-       LIST_HEAD(del_list);
-       struct lowpan_dev_record *entry, *tmp;
-
-       if (dev->type != ARPHRD_IEEE802154)
-               goto out;
-
-       if (event == NETDEV_UNREGISTER) {
-               list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
-                       if (lowpan_dev_info(entry->ldev)->real_dev == dev)
-                               lowpan_dellink(entry->ldev, &del_list);
-               }
-
-               unregister_netdevice_many(&del_list);
-       }
-
-out:
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block lowpan_dev_notifier = {
-       .notifier_call = lowpan_device_event,
-};
-
-static struct packet_type lowpan_packet_type = {
-       .type = __constant_htons(ETH_P_IEEE802154),
-       .func = lowpan_rcv,
-};
-
-static int __init lowpan_init_module(void)
-{
-       int err = 0;
-
-       err = lowpan_netlink_init();
-       if (err < 0)
-               goto out;
-
-       dev_add_pack(&lowpan_packet_type);
-
-       err = register_netdevice_notifier(&lowpan_dev_notifier);
-       if (err < 0) {
-               dev_remove_pack(&lowpan_packet_type);
-               lowpan_netlink_fini();
-       }
-out:
-       return err;
-}
-
-static void __exit lowpan_cleanup_module(void)
-{
-       struct lowpan_fragment *frame, *tframe;
-
-       lowpan_netlink_fini();
-
-       dev_remove_pack(&lowpan_packet_type);
-
-       unregister_netdevice_notifier(&lowpan_dev_notifier);
-
-       /* Now 6lowpan packet_type is removed, so no new fragments are
-        * expected on RX, therefore that's the time to clean incomplete
-        * fragments.
-        */
-       spin_lock_bh(&flist_lock);
-       list_for_each_entry_safe(frame, tframe, &lowpan_fragments, list) {
-               del_timer_sync(&frame->timer);
-               list_del(&frame->list);
-               dev_kfree_skb(frame->skb);
-               kfree(frame);
-       }
-       spin_unlock_bh(&flist_lock);
-}
-
-module_init(lowpan_init_module);
-module_exit(lowpan_cleanup_module);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_RTNL_LINK("lowpan");
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
deleted file mode 100644 (file)
index 2b835db..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright 2011, Siemens AG
- * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
- */
-
-/*
- * Based on patches from Jon Smirl <jonsmirl@gmail.com>
- * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/* Jon's code is based on 6lowpan implementation for Contiki which is:
- * Copyright (c) 2008, Swedish Institute of Computer Science.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the Institute nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef __6LOWPAN_H__
-#define __6LOWPAN_H__
-
-#define UIP_802154_SHORTADDR_LEN       2  /* compressed ipv6 address length */
-#define UIP_IPH_LEN                    40 /* ipv6 fixed header size */
-#define UIP_PROTO_UDP                  17 /* ipv6 next header value for UDP */
-#define UIP_FRAGH_LEN                  8  /* ipv6 fragment header size */
-
-/*
- * ipv6 address based on mac
- * second bit-flip (Universe/Local) is done according RFC2464
- */
-#define is_addr_mac_addr_based(a, m) \
-       ((((a)->s6_addr[8])  == (((m)[0]) ^ 0x02)) &&   \
-        (((a)->s6_addr[9])  == (m)[1]) &&              \
-        (((a)->s6_addr[10]) == (m)[2]) &&              \
-        (((a)->s6_addr[11]) == (m)[3]) &&              \
-        (((a)->s6_addr[12]) == (m)[4]) &&              \
-        (((a)->s6_addr[13]) == (m)[5]) &&              \
-        (((a)->s6_addr[14]) == (m)[6]) &&              \
-        (((a)->s6_addr[15]) == (m)[7]))
-
-/* ipv6 address is unspecified */
-#define is_addr_unspecified(a)         \
-       ((((a)->s6_addr32[0]) == 0) &&  \
-        (((a)->s6_addr32[1]) == 0) &&  \
-        (((a)->s6_addr32[2]) == 0) &&  \
-        (((a)->s6_addr32[3]) == 0))
-
-/* compare ipv6 addresses prefixes */
-#define ipaddr_prefixcmp(addr1, addr2, length) \
-       (memcmp(addr1, addr2, length >> 3) == 0)
-
-/* local link, i.e. FE80::/10 */
-#define is_addr_link_local(a) (((a)->s6_addr16[0]) == htons(0xFE80))
-
-/*
- * check whether we can compress the IID to 16 bits,
- * it's possible for unicast adresses with first 49 bits are zero only.
- */
-#define lowpan_is_iid_16_bit_compressable(a)   \
-       ((((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr[10]) == 0) &&           \
-        (((a)->s6_addr[11]) == 0xff) &&        \
-        (((a)->s6_addr[12]) == 0xfe) &&        \
-        (((a)->s6_addr[13]) == 0))
-
-/* multicast address */
-#define is_addr_mcast(a) (((a)->s6_addr[0]) == 0xFF)
-
-/* check whether the 112-bit gid of the multicast address is mappable to: */
-
-/* 9 bits, for FF02::1 (all nodes) and FF02::2 (all routers) addresses only. */
-#define lowpan_is_mcast_addr_compressable(a)   \
-       ((((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr16[5]) == 0) &&          \
-        (((a)->s6_addr16[6]) == 0) &&          \
-        (((a)->s6_addr[14])  == 0) &&          \
-        ((((a)->s6_addr[15]) == 1) || (((a)->s6_addr[15]) == 2)))
-
-/* 48 bits, FFXX::00XX:XXXX:XXXX */
-#define lowpan_is_mcast_addr_compressable48(a) \
-       ((((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr[10]) == 0))
-
-/* 32 bits, FFXX::00XX:XXXX */
-#define lowpan_is_mcast_addr_compressable32(a) \
-       ((((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr16[5]) == 0) &&          \
-        (((a)->s6_addr[12]) == 0))
-
-/* 8 bits, FF02::00XX */
-#define lowpan_is_mcast_addr_compressable8(a)  \
-       ((((a)->s6_addr[1])  == 2) &&           \
-        (((a)->s6_addr16[1]) == 0) &&          \
-        (((a)->s6_addr16[2]) == 0) &&          \
-        (((a)->s6_addr16[3]) == 0) &&          \
-        (((a)->s6_addr16[4]) == 0) &&          \
-        (((a)->s6_addr16[5]) == 0) &&          \
-        (((a)->s6_addr16[6]) == 0) &&          \
-        (((a)->s6_addr[14]) == 0))
-
-#define lowpan_is_addr_broadcast(a)    \
-       ((((a)[0]) == 0xFF) &&  \
-        (((a)[1]) == 0xFF) &&  \
-        (((a)[2]) == 0xFF) &&  \
-        (((a)[3]) == 0xFF) &&  \
-        (((a)[4]) == 0xFF) &&  \
-        (((a)[5]) == 0xFF) &&  \
-        (((a)[6]) == 0xFF) &&  \
-        (((a)[7]) == 0xFF))
-
-#define LOWPAN_DISPATCH_IPV6   0x41 /* 01000001 = 65 */
-#define LOWPAN_DISPATCH_HC1    0x42 /* 01000010 = 66 */
-#define LOWPAN_DISPATCH_IPHC   0x60 /* 011xxxxx = ... */
-#define LOWPAN_DISPATCH_FRAG1  0xc0 /* 11000xxx */
-#define LOWPAN_DISPATCH_FRAGN  0xe0 /* 11100xxx */
-
-#define LOWPAN_DISPATCH_MASK   0xf8 /* 11111000 */
-
-#define LOWPAN_FRAG_TIMEOUT    (HZ * 60)       /* time-out 60 sec */
-
-#define LOWPAN_FRAG1_HEAD_SIZE 0x4
-#define LOWPAN_FRAGN_HEAD_SIZE 0x5
-
-/*
- * According IEEE802.15.4 standard:
- *   - MTU is 127 octets
- *   - maximum MHR size is 37 octets
- *   - MFR size is 2 octets
- *
- * so minimal payload size that we may guarantee is:
- *   MTU - MHR - MFR = 88 octets
- */
-#define LOWPAN_FRAG_SIZE       88
-
-/*
- * Values of fields within the IPHC encoding first byte
- * (C stands for compressed and I for inline)
- */
-#define LOWPAN_IPHC_TF         0x18
-
-#define LOWPAN_IPHC_FL_C       0x10
-#define LOWPAN_IPHC_TC_C       0x08
-#define LOWPAN_IPHC_NH_C       0x04
-#define LOWPAN_IPHC_TTL_1      0x01
-#define LOWPAN_IPHC_TTL_64     0x02
-#define LOWPAN_IPHC_TTL_255    0x03
-#define LOWPAN_IPHC_TTL_I      0x00
-
-
-/* Values of fields within the IPHC encoding second byte */
-#define LOWPAN_IPHC_CID                0x80
-
-#define LOWPAN_IPHC_ADDR_00    0x00
-#define LOWPAN_IPHC_ADDR_01    0x01
-#define LOWPAN_IPHC_ADDR_02    0x02
-#define LOWPAN_IPHC_ADDR_03    0x03
-
-#define LOWPAN_IPHC_SAC                0x40
-#define LOWPAN_IPHC_SAM                0x30
-
-#define LOWPAN_IPHC_SAM_BIT    4
-
-#define LOWPAN_IPHC_M          0x08
-#define LOWPAN_IPHC_DAC                0x04
-#define LOWPAN_IPHC_DAM_00     0x00
-#define LOWPAN_IPHC_DAM_01     0x01
-#define LOWPAN_IPHC_DAM_10     0x02
-#define LOWPAN_IPHC_DAM_11     0x03
-
-#define LOWPAN_IPHC_DAM_BIT    0
-/*
- * LOWPAN_UDP encoding (works together with IPHC)
- */
-#define LOWPAN_NHC_UDP_MASK            0xF8
-#define LOWPAN_NHC_UDP_ID              0xF0
-#define LOWPAN_NHC_UDP_CHECKSUMC       0x04
-#define LOWPAN_NHC_UDP_CHECKSUMI       0x00
-
-#define LOWPAN_NHC_UDP_4BIT_PORT       0xF0B0
-#define LOWPAN_NHC_UDP_4BIT_MASK       0xFFF0
-#define LOWPAN_NHC_UDP_8BIT_PORT       0xF000
-#define LOWPAN_NHC_UDP_8BIT_MASK       0xFF00
-
-/* values for port compression, _with checksum_ ie bit 5 set to 0 */
-#define LOWPAN_NHC_UDP_CS_P_00 0xF0 /* all inline */
-#define LOWPAN_NHC_UDP_CS_P_01 0xF1 /* source 16bit inline,
-                                       dest = 0xF0 + 8 bit inline */
-#define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline,
-                                       dest = 16 bit inline */
-#define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
-#define LOWPAN_NHC_UDP_CS_C    0x04 /* checksum elided */
-
-#ifdef DEBUG
-/* print data in line */
-static inline void raw_dump_inline(const char *caller, char *msg,
-                                  unsigned char *buf, int len)
-{
-       if (msg)
-               pr_debug("%s():%s: ", caller, msg);
-
-       print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);
-}
-
-/* print data in a table format:
- *
- * addr: xx xx xx xx xx xx
- * addr: xx xx xx xx xx xx
- * ...
- */
-static inline void raw_dump_table(const char *caller, char *msg,
-                                 unsigned char *buf, int len)
-{
-       if (msg)
-               pr_debug("%s():%s:\n", caller, msg);
-
-       print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
-}
-#else
-static inline void raw_dump_table(const char *caller, char *msg,
-                                 unsigned char *buf, int len) { }
-static inline void raw_dump_inline(const char *caller, char *msg,
-                                  unsigned char *buf, int len) { }
-#endif
-
-static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 1)))
-               return -EINVAL;
-
-       *val = skb->data[0];
-       skb_pull(skb, 1);
-
-       return 0;
-}
-
-static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 2)))
-               return -EINVAL;
-
-       *val = (skb->data[0] << 8) | skb->data[1];
-       skb_pull(skb, 2);
-
-       return 0;
-}
-
-static inline bool lowpan_fetch_skb(struct sk_buff *skb,
-               void *data, const unsigned int len)
-{
-       if (unlikely(!pskb_may_pull(skb, len)))
-               return true;
-
-       skb_copy_from_linear_data(skb, data, len);
-       skb_pull(skb, len);
-
-       return false;
-}
-
-static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
-                                      const size_t len)
-{
-       memcpy(*hc_ptr, data, len);
-       *hc_ptr += len;
-}
-
-typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
-
-int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
-               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
-               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
-               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
-int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
-                       unsigned short type, const void *_daddr,
-                       const void *_saddr, unsigned int len);
-
-#endif /* __6LOWPAN_H__ */
index 860aa2d445bae361d5d588a6c1a4e41310d0d629..211b5686d719679242d6a7b5e0cd65547ae37cd3 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
+#include <net/6lowpan.h>
 #include <net/ipv6.h>
 #include <net/af_ieee802154.h>
 
-#include "6lowpan.h"
-
 /*
  * Uncompress address function for source and
  * destination address(non-multicast).
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
new file mode 100644 (file)
index 0000000..0f5a69e
--- /dev/null
@@ -0,0 +1,674 @@
+/* Copyright 2011, Siemens AG
+ * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+/* Based on patches from Jon Smirl <jonsmirl@gmail.com>
+ * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/* Jon's code is based on 6lowpan implementation for Contiki which is:
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/bitops.h>
+#include <linux/if_arp.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <net/af_ieee802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
+#include <net/6lowpan.h>
+#include <net/ipv6.h>
+
+#include "reassembly.h"
+
+static LIST_HEAD(lowpan_devices);
+
+/* private device info */
+struct lowpan_dev_info {
+       struct net_device       *real_dev; /* real WPAN device ptr */
+       struct mutex            dev_list_mtx; /* mutex for list ops */
+       __be16                  fragment_tag;
+};
+
+struct lowpan_dev_record {
+       struct net_device *ldev;
+       struct list_head list;
+};
+
+static inline struct
+lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
+{
+       return netdev_priv(dev);
+}
+
+static inline void lowpan_address_flip(u8 *src, u8 *dest)
+{
+       int i;
+       for (i = 0; i < IEEE802154_ADDR_LEN; i++)
+               (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
+}
+
+static int lowpan_header_create(struct sk_buff *skb,
+                          struct net_device *dev,
+                          unsigned short type, const void *_daddr,
+                          const void *_saddr, unsigned int len)
+{
+       const u8 *saddr = _saddr;
+       const u8 *daddr = _daddr;
+       struct ieee802154_addr sa, da;
+
+       /* TODO:
+        * if this package isn't ipv6 one, where should it be routed?
+        */
+       if (type != ETH_P_IPV6)
+               return 0;
+
+       if (!saddr)
+               saddr = dev->dev_addr;
+
+       raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
+       raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
+
+       lowpan_header_compress(skb, dev, type, daddr, saddr, len);
+
+       /* NOTE1: I'm still unsure about the fact that compression and WPAN
+        * header are created here and not later in the xmit. So wait for
+        * an opinion of net maintainers.
+        */
+       /* NOTE2: to be absolutely correct, we must derive PANid information
+        * from MAC subif of the 'dev' and 'real_dev' network devices, but
+        * this isn't implemented in mainline yet, so currently we assign 0xff
+        */
+       mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+       mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+
+       /* prepare wpan address data */
+       sa.mode = IEEE802154_ADDR_LONG;
+       sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
+
+       /* intra-PAN communications */
+       da.pan_id = sa.pan_id;
+
+       /* if the destination address is the broadcast address, use the
+        * corresponding short address
+        */
+       if (lowpan_is_addr_broadcast(daddr)) {
+               da.mode = IEEE802154_ADDR_SHORT;
+               da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+       } else {
+               da.mode = IEEE802154_ADDR_LONG;
+               da.extended_addr = ieee802154_devaddr_from_raw(daddr);
+
+               /* request acknowledgment */
+               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+       }
+
+       return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
+                       type, (void *)&da, (void *)&sa, 0);
+}
+
+static int lowpan_give_skb_to_devices(struct sk_buff *skb,
+                                       struct net_device *dev)
+{
+       struct lowpan_dev_record *entry;
+       struct sk_buff *skb_cp;
+       int stat = NET_RX_SUCCESS;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(entry, &lowpan_devices, list)
+               if (lowpan_dev_info(entry->ldev)->real_dev == skb->dev) {
+                       skb_cp = skb_copy(skb, GFP_ATOMIC);
+                       if (!skb_cp) {
+                               stat = -ENOMEM;
+                               break;
+                       }
+
+                       skb_cp->dev = entry->ldev;
+                       stat = netif_rx(skb_cp);
+               }
+       rcu_read_unlock();
+
+       return stat;
+}
+
+static int process_data(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
+{
+       u8 iphc0, iphc1;
+       struct ieee802154_addr_sa sa, da;
+       void *sap, *dap;
+
+       raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
+       /* at least two bytes will be used for the encoding */
+       if (skb->len < 2)
+               goto drop;
+
+       if (lowpan_fetch_skb_u8(skb, &iphc0))
+               goto drop;
+
+       if (lowpan_fetch_skb_u8(skb, &iphc1))
+               goto drop;
+
+       ieee802154_addr_to_sa(&sa, &hdr->source);
+       ieee802154_addr_to_sa(&da, &hdr->dest);
+
+       if (sa.addr_type == IEEE802154_ADDR_SHORT)
+               sap = &sa.short_addr;
+       else
+               sap = &sa.hwaddr;
+
+       if (da.addr_type == IEEE802154_ADDR_SHORT)
+               dap = &da.short_addr;
+       else
+               dap = &da.hwaddr;
+
+       return lowpan_process_data(skb, skb->dev, sap, sa.addr_type,
+                                  IEEE802154_ADDR_LEN, dap, da.addr_type,
+                                  IEEE802154_ADDR_LEN, iphc0, iphc1,
+                                  lowpan_give_skb_to_devices);
+
+drop:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+static int lowpan_set_address(struct net_device *dev, void *p)
+{
+       struct sockaddr *sa = p;
+
+       if (netif_running(dev))
+               return -EBUSY;
+
+       /* TODO: validate addr */
+       memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
+
+       return 0;
+}
+
+static int
+lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
+                    int mlen, int plen, int offset, int type)
+{
+       struct sk_buff *frag;
+       int hlen;
+
+       hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
+                       LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
+
+       raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
+
+       frag = netdev_alloc_skb(skb->dev,
+                               hlen + mlen + plen + IEEE802154_MFR_SIZE);
+       if (!frag)
+               return -ENOMEM;
+
+       frag->priority = skb->priority;
+
+       /* copy header, MFR and payload */
+       skb_put(frag, mlen);
+       skb_copy_to_linear_data(frag, skb_mac_header(skb), mlen);
+
+       skb_put(frag, hlen);
+       skb_copy_to_linear_data_offset(frag, mlen, head, hlen);
+
+       skb_put(frag, plen);
+       skb_copy_to_linear_data_offset(frag, mlen + hlen,
+                                      skb_network_header(skb) + offset, plen);
+
+       raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len);
+
+       return dev_queue_xmit(frag);
+}
+
+static int
+lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
+{
+       int err;
+       u16 dgram_offset, dgram_size, payload_length, header_length,
+           lowpan_size, frag_plen, offset;
+       __be16 tag;
+       u8 head[5];
+
+       header_length = skb->mac_len;
+       payload_length = skb->len - header_length;
+       tag = lowpan_dev_info(dev)->fragment_tag++;
+       lowpan_size = skb_network_header_len(skb);
+       dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
+                    header_length;
+
+       /* first fragment header */
+       head[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x7);
+       head[1] = dgram_size & 0xff;
+       memcpy(head + 2, &tag, sizeof(tag));
+
+       /* calc the nearest payload length(divided to 8) for first fragment
+        * which fits into a IEEE802154_MTU
+        */
+       frag_plen = round_down(IEEE802154_MTU - header_length -
+                              LOWPAN_FRAG1_HEAD_SIZE - lowpan_size -
+                              IEEE802154_MFR_SIZE, 8);
+
+       err = lowpan_fragment_xmit(skb, head, header_length,
+                                  frag_plen + lowpan_size, 0,
+                                  LOWPAN_DISPATCH_FRAG1);
+       if (err) {
+               pr_debug("%s unable to send FRAG1 packet (tag: %d)",
+                        __func__, tag);
+               goto exit;
+       }
+
+       offset = lowpan_size + frag_plen;
+       dgram_offset += frag_plen;
+
+       /* next fragment header */
+       head[0] &= ~LOWPAN_DISPATCH_FRAG1;
+       head[0] |= LOWPAN_DISPATCH_FRAGN;
+
+       frag_plen = round_down(IEEE802154_MTU - header_length -
+                              LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE, 8);
+
+       while (payload_length - offset > 0) {
+               int len = frag_plen;
+
+               head[4] = dgram_offset >> 3;
+
+               if (payload_length - offset < len)
+                       len = payload_length - offset;
+
+               err = lowpan_fragment_xmit(skb, head, header_length, len,
+                                          offset, LOWPAN_DISPATCH_FRAGN);
+               if (err) {
+                       pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n",
+                                __func__, tag, offset);
+                       goto exit;
+               }
+
+               offset += len;
+               dgram_offset += len;
+       }
+
+exit:
+       return err;
+}
+
+static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       int err = -1;
+
+       pr_debug("package xmit\n");
+
+       skb->dev = lowpan_dev_info(dev)->real_dev;
+       if (skb->dev == NULL) {
+               pr_debug("ERROR: no real wpan device found\n");
+               goto error;
+       }
+
+       /* Send directly if less than the MTU minus the 2 checksum bytes. */
+       if (skb->len <= IEEE802154_MTU - IEEE802154_MFR_SIZE) {
+               err = dev_queue_xmit(skb);
+               goto out;
+       }
+
+       pr_debug("frame is too big, fragmentation is needed\n");
+       err = lowpan_skb_fragmentation(skb, dev);
+error:
+       dev_kfree_skb(skb);
+out:
+       if (err)
+               pr_debug("ERROR: xmit failed\n");
+
+       return (err < 0) ? NET_XMIT_DROP : err;
+}
+
+static struct wpan_phy *lowpan_get_phy(const struct net_device *dev)
+{
+       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+       return ieee802154_mlme_ops(real_dev)->get_phy(real_dev);
+}
+
+static __le16 lowpan_get_pan_id(const struct net_device *dev)
+{
+       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+       return ieee802154_mlme_ops(real_dev)->get_pan_id(real_dev);
+}
+
+static __le16 lowpan_get_short_addr(const struct net_device *dev)
+{
+       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+       return ieee802154_mlme_ops(real_dev)->get_short_addr(real_dev);
+}
+
+static u8 lowpan_get_dsn(const struct net_device *dev)
+{
+       struct net_device *real_dev = lowpan_dev_info(dev)->real_dev;
+       return ieee802154_mlme_ops(real_dev)->get_dsn(real_dev);
+}
+
+static struct header_ops lowpan_header_ops = {
+       .create = lowpan_header_create,
+};
+
+static struct lock_class_key lowpan_tx_busylock;
+static struct lock_class_key lowpan_netdev_xmit_lock_key;
+
+static void lowpan_set_lockdep_class_one(struct net_device *dev,
+                                        struct netdev_queue *txq,
+                                        void *_unused)
+{
+       lockdep_set_class(&txq->_xmit_lock,
+                         &lowpan_netdev_xmit_lock_key);
+}
+
+
+static int lowpan_dev_init(struct net_device *dev)
+{
+       netdev_for_each_tx_queue(dev, lowpan_set_lockdep_class_one, NULL);
+       dev->qdisc_tx_busylock = &lowpan_tx_busylock;
+       return 0;
+}
+
+static const struct net_device_ops lowpan_netdev_ops = {
+       .ndo_init               = lowpan_dev_init,
+       .ndo_start_xmit         = lowpan_xmit,
+       .ndo_set_mac_address    = lowpan_set_address,
+};
+
+static struct ieee802154_mlme_ops lowpan_mlme = {
+       .get_pan_id = lowpan_get_pan_id,
+       .get_phy = lowpan_get_phy,
+       .get_short_addr = lowpan_get_short_addr,
+       .get_dsn = lowpan_get_dsn,
+};
+
+static void lowpan_setup(struct net_device *dev)
+{
+       dev->addr_len           = IEEE802154_ADDR_LEN;
+       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+       dev->type               = ARPHRD_IEEE802154;
+       /* Frame Control + Sequence Number + Address fields + Security Header */
+       dev->hard_header_len    = 2 + 1 + 20 + 14;
+       dev->needed_tailroom    = 2; /* FCS */
+       dev->mtu                = 1281;
+       dev->tx_queue_len       = 0;
+       dev->flags              = IFF_BROADCAST | IFF_MULTICAST;
+       dev->watchdog_timeo     = 0;
+
+       dev->netdev_ops         = &lowpan_netdev_ops;
+       dev->header_ops         = &lowpan_header_ops;
+       dev->ml_priv            = &lowpan_mlme;
+       dev->destructor         = free_netdev;
+}
+
+static int lowpan_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       if (tb[IFLA_ADDRESS]) {
+               if (nla_len(tb[IFLA_ADDRESS]) != IEEE802154_ADDR_LEN)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
+       struct packet_type *pt, struct net_device *orig_dev)
+{
+       struct ieee802154_hdr hdr;
+       int ret;
+
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               goto drop;
+
+       if (!netif_running(dev))
+               goto drop_skb;
+
+       if (dev->type != ARPHRD_IEEE802154)
+               goto drop_skb;
+
+       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
+               goto drop_skb;
+
+       /* check that it's our buffer */
+       if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+               skb->protocol = htons(ETH_P_IPV6);
+               skb->pkt_type = PACKET_HOST;
+
+               /* Pull off the 1-byte of 6lowpan header. */
+               skb_pull(skb, 1);
+
+               ret = lowpan_give_skb_to_devices(skb, NULL);
+               if (ret == NET_RX_DROP)
+                       goto drop;
+       } else {
+               switch (skb->data[0] & 0xe0) {
+               case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+                       ret = process_data(skb, &hdr);
+                       if (ret == NET_RX_DROP)
+                               goto drop;
+                       break;
+               case LOWPAN_DISPATCH_FRAG1:     /* first fragment header */
+                       ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAG1);
+                       if (ret == 1) {
+                               ret = process_data(skb, &hdr);
+                               if (ret == NET_RX_DROP)
+                                       goto drop;
+                       }
+                       break;
+               case LOWPAN_DISPATCH_FRAGN:     /* next fragments headers */
+                       ret = lowpan_frag_rcv(skb, LOWPAN_DISPATCH_FRAGN);
+                       if (ret == 1) {
+                               ret = process_data(skb, &hdr);
+                               if (ret == NET_RX_DROP)
+                                       goto drop;
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return NET_RX_SUCCESS;
+drop_skb:
+       kfree_skb(skb);
+drop:
+       return NET_RX_DROP;
+}
+
+static int lowpan_newlink(struct net *src_net, struct net_device *dev,
+                         struct nlattr *tb[], struct nlattr *data[])
+{
+       struct net_device *real_dev;
+       struct lowpan_dev_record *entry;
+
+       pr_debug("adding new link\n");
+
+       if (!tb[IFLA_LINK])
+               return -EINVAL;
+       /* find and hold real wpan device */
+       real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK]));
+       if (!real_dev)
+               return -ENODEV;
+       if (real_dev->type != ARPHRD_IEEE802154) {
+               dev_put(real_dev);
+               return -EINVAL;
+       }
+
+       lowpan_dev_info(dev)->real_dev = real_dev;
+       mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry) {
+               dev_put(real_dev);
+               lowpan_dev_info(dev)->real_dev = NULL;
+               return -ENOMEM;
+       }
+
+       entry->ldev = dev;
+
+       /* Set the lowpan harware address to the wpan hardware address. */
+       memcpy(dev->dev_addr, real_dev->dev_addr, IEEE802154_ADDR_LEN);
+
+       mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
+       INIT_LIST_HEAD(&entry->list);
+       list_add_tail(&entry->list, &lowpan_devices);
+       mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
+
+       register_netdevice(dev);
+
+       return 0;
+}
+
+static void lowpan_dellink(struct net_device *dev, struct list_head *head)
+{
+       struct lowpan_dev_info *lowpan_dev = lowpan_dev_info(dev);
+       struct net_device *real_dev = lowpan_dev->real_dev;
+       struct lowpan_dev_record *entry, *tmp;
+
+       ASSERT_RTNL();
+
+       mutex_lock(&lowpan_dev_info(dev)->dev_list_mtx);
+       list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
+               if (entry->ldev == dev) {
+                       list_del(&entry->list);
+                       kfree(entry);
+               }
+       }
+       mutex_unlock(&lowpan_dev_info(dev)->dev_list_mtx);
+
+       mutex_destroy(&lowpan_dev_info(dev)->dev_list_mtx);
+
+       unregister_netdevice_queue(dev, head);
+
+       dev_put(real_dev);
+}
+
+static struct rtnl_link_ops lowpan_link_ops __read_mostly = {
+       .kind           = "lowpan",
+       .priv_size      = sizeof(struct lowpan_dev_info),
+       .setup          = lowpan_setup,
+       .newlink        = lowpan_newlink,
+       .dellink        = lowpan_dellink,
+       .validate       = lowpan_validate,
+};
+
+static inline int __init lowpan_netlink_init(void)
+{
+       return rtnl_link_register(&lowpan_link_ops);
+}
+
+static inline void lowpan_netlink_fini(void)
+{
+       rtnl_link_unregister(&lowpan_link_ops);
+}
+
+static int lowpan_device_event(struct notifier_block *unused,
+                              unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       LIST_HEAD(del_list);
+       struct lowpan_dev_record *entry, *tmp;
+
+       if (dev->type != ARPHRD_IEEE802154)
+               goto out;
+
+       if (event == NETDEV_UNREGISTER) {
+               list_for_each_entry_safe(entry, tmp, &lowpan_devices, list) {
+                       if (lowpan_dev_info(entry->ldev)->real_dev == dev)
+                               lowpan_dellink(entry->ldev, &del_list);
+               }
+
+               unregister_netdevice_many(&del_list);
+       }
+
+out:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block lowpan_dev_notifier = {
+       .notifier_call = lowpan_device_event,
+};
+
+static struct packet_type lowpan_packet_type = {
+       .type = htons(ETH_P_IEEE802154),
+       .func = lowpan_rcv,
+};
+
+static int __init lowpan_init_module(void)
+{
+       int err = 0;
+
+       err = lowpan_net_frag_init();
+       if (err < 0)
+               goto out;
+
+       err = lowpan_netlink_init();
+       if (err < 0)
+               goto out_frag;
+
+       dev_add_pack(&lowpan_packet_type);
+
+       err = register_netdevice_notifier(&lowpan_dev_notifier);
+       if (err < 0)
+               goto out_pack;
+
+       return 0;
+
+out_pack:
+       dev_remove_pack(&lowpan_packet_type);
+       lowpan_netlink_fini();
+out_frag:
+       lowpan_net_frag_exit();
+out:
+       return err;
+}
+
+static void __exit lowpan_cleanup_module(void)
+{
+       lowpan_netlink_fini();
+
+       dev_remove_pack(&lowpan_packet_type);
+
+       lowpan_net_frag_exit();
+
+       unregister_netdevice_notifier(&lowpan_dev_notifier);
+}
+
+module_init(lowpan_init_module);
+module_exit(lowpan_cleanup_module);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("lowpan");
index 9c9879d5ea64e7e3e6fe04e1de3675d3ed3c256c..8af1330b3137b0282d316190770d77150f336d56 100644 (file)
@@ -15,7 +15,7 @@ config IEEE802154_6LOWPAN
        depends on IEEE802154 && IPV6
        select 6LOWPAN_IPHC
        ---help---
-       IPv6 compression over IEEE 802.15.4.
+         IPv6 compression over IEEE 802.15.4.
 
 config 6LOWPAN_IPHC
        tristate
index e8f05885ced6806f1139a053ee8ea4fa1b228823..bf1b51497a41048442640cf02d8de1f62c18ef6a 100644 (file)
@@ -2,5 +2,9 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
 obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
 obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
 
-ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
+6lowpan-y := 6lowpan_rtnl.o reassembly.o
+ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o \
+                header_ops.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index b1ec5253752217f0f411383b9a61ad710ab74816..8330a09bfc95e6877351029cff36b542af11c66f 100644 (file)
 #define AF802154_H
 
 struct sk_buff;
-struct net_devce;
+struct net_device;
+struct ieee802154_addr;
 extern struct proto ieee802154_raw_prot;
 extern struct proto ieee802154_dgram_prot;
 void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb);
 int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb);
 struct net_device *ieee802154_get_dev(struct net *net,
-               struct ieee802154_addr *addr);
+                                     const struct ieee802154_addr *addr);
 
 #endif
index 40e606f3788f11f5dcdeb59420ff18a4ec24eab1..351d9a94ec2faa429612d6b7da26b09b63e49a25 100644 (file)
 /*
  * Utility function for families
  */
-struct net_device *ieee802154_get_dev(struct net *net,
-               struct ieee802154_addr *addr)
+struct net_device*
+ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
 {
        struct net_device *dev = NULL;
        struct net_device *tmp;
-       u16 pan_id, short_addr;
+       __le16 pan_id, short_addr;
+       u8 hwaddr[IEEE802154_ADDR_LEN];
 
-       switch (addr->addr_type) {
+       switch (addr->mode) {
        case IEEE802154_ADDR_LONG:
+               ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
                rcu_read_lock();
-               dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr);
+               dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
                if (dev)
                        dev_hold(dev);
                rcu_read_unlock();
                break;
        case IEEE802154_ADDR_SHORT:
-               if (addr->pan_id == 0xffff ||
-                   addr->short_addr == IEEE802154_ADDR_UNDEF ||
-                   addr->short_addr == 0xffff)
+               if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
+                   addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+                   addr->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST))
                        break;
 
                rtnl_lock();
@@ -86,7 +88,7 @@ struct net_device *ieee802154_get_dev(struct net *net,
                break;
        default:
                pr_warning("Unsupported ieee802154 address type: %d\n",
-                               addr->addr_type);
+                               addr->mode);
                break;
        }
 
@@ -326,7 +328,7 @@ drop:
 
 
 static struct packet_type ieee802154_packet_type = {
-       .type = __constant_htons(ETH_P_IEEE802154),
+       .type = htons(ETH_P_IEEE802154),
        .func = ieee802154_rcv,
 };
 
index 1846c1fe0d06a1f788c04b977b11f8eb70f84ce8..786437bc0c08531785d3f5fa1deb5bff8efe9e62 100644 (file)
@@ -73,10 +73,10 @@ static int dgram_init(struct sock *sk)
 {
        struct dgram_sock *ro = dgram_sk(sk);
 
-       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
-       ro->dst_addr.pan_id = 0xffff;
+       ro->dst_addr.mode = IEEE802154_ADDR_LONG;
+       ro->dst_addr.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
        ro->want_ack = 1;
-       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
        return 0;
 }
 
@@ -88,6 +88,7 @@ static void dgram_close(struct sock *sk, long timeout)
 static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
 {
        struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct ieee802154_addr haddr;
        struct dgram_sock *ro = dgram_sk(sk);
        int err = -EINVAL;
        struct net_device *dev;
@@ -102,7 +103,8 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
        if (addr->family != AF_IEEE802154)
                goto out;
 
-       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       ieee802154_addr_from_sa(&haddr, &addr->addr);
+       dev = ieee802154_get_dev(sock_net(sk), &haddr);
        if (!dev) {
                err = -ENODEV;
                goto out;
@@ -113,7 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
                goto out_put;
        }
 
-       memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr));
+       ro->src_addr = haddr;
 
        ro->bound = 1;
        err = 0;
@@ -149,8 +151,7 @@ static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
                         * of this packet since that is all
                         * that will be read.
                         */
-                       /* FIXME: parse the header for more correct value */
-                       amount = skb->len - (3+8+8);
+                       amount = skb->len - ieee802154_hdr_length(skb);
                }
                spin_unlock_bh(&sk->sk_receive_queue.lock);
                return put_user(amount, (int __user *)arg);
@@ -181,7 +182,7 @@ static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
                goto out;
        }
 
-       memcpy(&ro->dst_addr, &addr->addr, sizeof(struct ieee802154_addr));
+       ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
 
 out:
        release_sock(sk);
@@ -194,8 +195,8 @@ static int dgram_disconnect(struct sock *sk, int flags)
 
        lock_sock(sk);
 
-       ro->dst_addr.addr_type = IEEE802154_ADDR_LONG;
-       memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr));
+       ro->dst_addr.mode = IEEE802154_ADDR_LONG;
+       memset(&ro->dst_addr.extended_addr, 0xff, IEEE802154_ADDR_LEN);
 
        release_sock(sk);
 
@@ -232,7 +233,7 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk,
 
        if (size > mtu) {
                pr_debug("size = %Zu, mtu = %u\n", size, mtu);
-               err = -EINVAL;
+               err = -EMSGSIZE;
                goto out_dev;
        }
 
@@ -312,7 +313,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
 
        if (saddr) {
                saddr->family = AF_IEEE802154;
-               saddr->addr = mac_cb(skb)->sa;
+               ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
                *addr_len = sizeof(*saddr);
        }
 
@@ -328,6 +329,10 @@ out:
 
 static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               return NET_RX_DROP;
+
        if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
@@ -336,40 +341,43 @@ static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
        return NET_RX_SUCCESS;
 }
 
-static inline int ieee802154_match_sock(u8 *hw_addr, u16 pan_id,
-               u16 short_addr, struct dgram_sock *ro)
+static inline bool
+ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
+                     struct dgram_sock *ro)
 {
        if (!ro->bound)
-               return 1;
+               return true;
 
-       if (ro->src_addr.addr_type == IEEE802154_ADDR_LONG &&
-           !memcmp(ro->src_addr.hwaddr, hw_addr, IEEE802154_ADDR_LEN))
-               return 1;
+       if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
+           hw_addr == ro->src_addr.extended_addr)
+               return true;
 
-       if (ro->src_addr.addr_type == IEEE802154_ADDR_SHORT &&
-                    pan_id == ro->src_addr.pan_id &&
-                    short_addr == ro->src_addr.short_addr)
-               return 1;
+       if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
+           pan_id == ro->src_addr.pan_id &&
+           short_addr == ro->src_addr.short_addr)
+               return true;
 
-       return 0;
+       return false;
 }
 
 int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
 {
        struct sock *sk, *prev = NULL;
        int ret = NET_RX_SUCCESS;
-       u16 pan_id, short_addr;
+       __le16 pan_id, short_addr;
+       __le64 hw_addr;
 
        /* Data frame processing */
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
        pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
        short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
+       hw_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
 
        read_lock(&dgram_lock);
        sk_for_each(sk, &dgram_head) {
-               if (ieee802154_match_sock(dev->dev_addr, pan_id, short_addr,
-                                       dgram_sk(sk))) {
+               if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
+                                         dgram_sk(sk))) {
                        if (prev) {
                                struct sk_buff *clone;
                                clone = skb_clone(skb, GFP_ATOMIC);
diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c
new file mode 100644 (file)
index 0000000..bed42a4
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2014 Fraunhofer ITWM
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Written by:
+ * Phoebe Buckheister <phoebe.buckheister@itwm.fraunhofer.de>
+ */
+
+#include <net/mac802154.h>
+#include <net/ieee802154.h>
+#include <net/ieee802154_netdev.h>
+
+static int
+ieee802154_hdr_push_addr(u8 *buf, const struct ieee802154_addr *addr,
+                        bool omit_pan)
+{
+       int pos = 0;
+
+       if (addr->mode == IEEE802154_ADDR_NONE)
+               return 0;
+
+       if (!omit_pan) {
+               memcpy(buf + pos, &addr->pan_id, 2);
+               pos += 2;
+       }
+
+       switch (addr->mode) {
+       case IEEE802154_ADDR_SHORT:
+               memcpy(buf + pos, &addr->short_addr, 2);
+               pos += 2;
+               break;
+
+       case IEEE802154_ADDR_LONG:
+               memcpy(buf + pos, &addr->extended_addr, IEEE802154_ADDR_LEN);
+               pos += IEEE802154_ADDR_LEN;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return pos;
+}
+
+static int
+ieee802154_hdr_push_sechdr(u8 *buf, const struct ieee802154_sechdr *hdr)
+{
+       int pos = 5;
+
+       memcpy(buf, hdr, 1);
+       memcpy(buf + 1, &hdr->frame_counter, 4);
+
+       switch (hdr->key_id_mode) {
+       case IEEE802154_SCF_KEY_IMPLICIT:
+               return pos;
+
+       case IEEE802154_SCF_KEY_INDEX:
+               break;
+
+       case IEEE802154_SCF_KEY_SHORT_INDEX:
+               memcpy(buf + pos, &hdr->short_src, 4);
+               pos += 4;
+               break;
+
+       case IEEE802154_SCF_KEY_HW_INDEX:
+               memcpy(buf + pos, &hdr->extended_src, IEEE802154_ADDR_LEN);
+               pos += IEEE802154_ADDR_LEN;
+               break;
+       }
+
+       buf[pos++] = hdr->key_id;
+
+       return pos;
+}
+
+int
+ieee802154_hdr_push(struct sk_buff *skb, const struct ieee802154_hdr *hdr)
+{
+       u8 buf[MAC802154_FRAME_HARD_HEADER_LEN];
+       int pos = 2;
+       int rc;
+       struct ieee802154_hdr_fc fc = hdr->fc;
+
+       buf[pos++] = hdr->seq;
+
+       fc.dest_addr_mode = hdr->dest.mode;
+
+       rc = ieee802154_hdr_push_addr(buf + pos, &hdr->dest, false);
+       if (rc < 0)
+               return -EINVAL;
+       pos += rc;
+
+       fc.source_addr_mode = hdr->source.mode;
+
+       if (hdr->source.pan_id == hdr->dest.pan_id &&
+           hdr->dest.mode != IEEE802154_ADDR_NONE)
+               fc.intra_pan = true;
+
+       rc = ieee802154_hdr_push_addr(buf + pos, &hdr->source, fc.intra_pan);
+       if (rc < 0)
+               return -EINVAL;
+       pos += rc;
+
+       if (fc.security_enabled) {
+               fc.version = 1;
+
+               rc = ieee802154_hdr_push_sechdr(buf + pos, &hdr->sec);
+               if (rc < 0)
+                       return -EINVAL;
+
+               pos += rc;
+       }
+
+       memcpy(buf, &fc, 2);
+
+       memcpy(skb_push(skb, pos), buf, pos);
+
+       return pos;
+}
+EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
+
+static int
+ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan,
+                       struct ieee802154_addr *addr)
+{
+       int pos = 0;
+
+       addr->mode = mode;
+
+       if (mode == IEEE802154_ADDR_NONE)
+               return 0;
+
+       if (!omit_pan) {
+               memcpy(&addr->pan_id, buf + pos, 2);
+               pos += 2;
+       }
+
+       if (mode == IEEE802154_ADDR_SHORT) {
+               memcpy(&addr->short_addr, buf + pos, 2);
+               return pos + 2;
+       } else {
+               memcpy(&addr->extended_addr, buf + pos, IEEE802154_ADDR_LEN);
+               return pos + IEEE802154_ADDR_LEN;
+       }
+}
+
+static int ieee802154_hdr_addr_len(int mode, bool omit_pan)
+{
+       int pan_len = omit_pan ? 0 : 2;
+
+       switch (mode) {
+       case IEEE802154_ADDR_NONE: return 0;
+       case IEEE802154_ADDR_SHORT: return 2 + pan_len;
+       case IEEE802154_ADDR_LONG: return IEEE802154_ADDR_LEN + pan_len;
+       default: return -EINVAL;
+       }
+}
+
+static int
+ieee802154_hdr_get_sechdr(const u8 *buf, struct ieee802154_sechdr *hdr)
+{
+       int pos = 5;
+
+       memcpy(hdr, buf, 1);
+       memcpy(&hdr->frame_counter, buf + 1, 4);
+
+       switch (hdr->key_id_mode) {
+       case IEEE802154_SCF_KEY_IMPLICIT:
+               return pos;
+
+       case IEEE802154_SCF_KEY_INDEX:
+               break;
+
+       case IEEE802154_SCF_KEY_SHORT_INDEX:
+               memcpy(&hdr->short_src, buf + pos, 4);
+               pos += 4;
+               break;
+
+       case IEEE802154_SCF_KEY_HW_INDEX:
+               memcpy(&hdr->extended_src, buf + pos, IEEE802154_ADDR_LEN);
+               pos += IEEE802154_ADDR_LEN;
+               break;
+       }
+
+       hdr->key_id = buf[pos++];
+
+       return pos;
+}
+
+static int ieee802154_hdr_sechdr_len(u8 sc)
+{
+       switch (IEEE802154_SCF_KEY_ID_MODE(sc)) {
+       case IEEE802154_SCF_KEY_IMPLICIT: return 5;
+       case IEEE802154_SCF_KEY_INDEX: return 6;
+       case IEEE802154_SCF_KEY_SHORT_INDEX: return 10;
+       case IEEE802154_SCF_KEY_HW_INDEX: return 14;
+       default: return -EINVAL;
+       }
+}
+
+static int ieee802154_hdr_minlen(const struct ieee802154_hdr *hdr)
+{
+       int dlen, slen;
+
+       dlen = ieee802154_hdr_addr_len(hdr->fc.dest_addr_mode, false);
+       slen = ieee802154_hdr_addr_len(hdr->fc.source_addr_mode,
+                                      hdr->fc.intra_pan);
+
+       if (slen < 0 || dlen < 0)
+               return -EINVAL;
+
+       return 3 + dlen + slen + hdr->fc.security_enabled;
+}
+
+static int
+ieee802154_hdr_get_addrs(const u8 *buf, struct ieee802154_hdr *hdr)
+{
+       int pos = 0;
+
+       pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.dest_addr_mode,
+                                      false, &hdr->dest);
+       pos += ieee802154_hdr_get_addr(buf + pos, hdr->fc.source_addr_mode,
+                                      hdr->fc.intra_pan, &hdr->source);
+
+       if (hdr->fc.intra_pan)
+               hdr->source.pan_id = hdr->dest.pan_id;
+
+       return pos;
+}
+
+int
+ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
+{
+       int pos = 3, rc;
+
+       if (!pskb_may_pull(skb, 3))
+               return -EINVAL;
+
+       memcpy(hdr, skb->data, 3);
+
+       rc = ieee802154_hdr_minlen(hdr);
+       if (rc < 0 || !pskb_may_pull(skb, rc))
+               return -EINVAL;
+
+       pos += ieee802154_hdr_get_addrs(skb->data + pos, hdr);
+
+       if (hdr->fc.security_enabled) {
+               int want = pos + ieee802154_hdr_sechdr_len(skb->data[pos]);
+
+               if (!pskb_may_pull(skb, want))
+                       return -EINVAL;
+
+               pos += ieee802154_hdr_get_sechdr(skb->data + pos, &hdr->sec);
+       }
+
+       skb_pull(skb, pos);
+       return pos;
+}
+EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
+
+int
+ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
+{
+       const u8 *buf = skb_mac_header(skb);
+       int pos = 3, rc;
+
+       if (buf + 3 > skb_tail_pointer(skb))
+               return -EINVAL;
+
+       memcpy(hdr, buf, 3);
+
+       rc = ieee802154_hdr_minlen(hdr);
+       if (rc < 0 || buf + rc > skb_tail_pointer(skb))
+               return -EINVAL;
+
+       pos += ieee802154_hdr_get_addrs(buf + pos, hdr);
+       return pos;
+}
+EXPORT_SYMBOL_GPL(ieee802154_hdr_peek_addrs);
index cee4425b995689702375435f0be7dd85eca3ed73..6cbc8965be9181ce27314973532968dd7caab181 100644 (file)
@@ -53,6 +53,7 @@ int ieee802154_list_phy(struct sk_buff *skb, struct genl_info *info);
 int ieee802154_dump_phy(struct sk_buff *skb, struct netlink_callback *cb);
 int ieee802154_add_iface(struct sk_buff *skb, struct genl_info *info);
 int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info);
+int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info);
 
 enum ieee802154_mcgrp_ids {
        IEEE802154_COORD_MCGRP,
index 43f1b2bf469f40938a431582b305c45587049a04..67c151bf4b91b610835ffc60185428a9a84be8d8 100644 (file)
@@ -115,6 +115,7 @@ static const struct genl_ops ieee8021154_ops[] = {
                        ieee802154_dump_phy),
        IEEE802154_OP(IEEE802154_ADD_IFACE, ieee802154_add_iface),
        IEEE802154_OP(IEEE802154_DEL_IFACE, ieee802154_del_iface),
+       IEEE802154_OP(IEEE802154_SET_PHYPARAMS, ieee802154_set_phyparams),
        /* see nl-mac.c */
        IEEE802154_OP(IEEE802154_ASSOCIATE_REQ, ieee802154_associate_req),
        IEEE802154_OP(IEEE802154_ASSOCIATE_RESP, ieee802154_associate_resp),
index ba5c1e002f37b2630c53a0284736f5d177bded76..bda8dba4f993b0ce981888627cd3099dc2f13642 100644 (file)
 
 #include "ieee802154.h"
 
+static int nla_put_hwaddr(struct sk_buff *msg, int type, __le64 hwaddr)
+{
+       return nla_put_u64(msg, type, swab64((__force u64)hwaddr));
+}
+
+static __le64 nla_get_hwaddr(const struct nlattr *nla)
+{
+       return ieee802154_devaddr_from_raw(nla_data(nla));
+}
+
+static int nla_put_shortaddr(struct sk_buff *msg, int type, __le16 addr)
+{
+       return nla_put_u16(msg, type, le16_to_cpu(addr));
+}
+
+static __le16 nla_get_shortaddr(const struct nlattr *nla)
+{
+       return cpu_to_le16(nla_get_u16(nla));
+}
+
 int ieee802154_nl_assoc_indic(struct net_device *dev,
                struct ieee802154_addr *addr, u8 cap)
 {
@@ -46,7 +66,7 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
 
        pr_debug("%s\n", __func__);
 
-       if (addr->addr_type != IEEE802154_ADDR_LONG) {
+       if (addr->mode != IEEE802154_ADDR_LONG) {
                pr_err("%s: received non-long source address!\n", __func__);
                return -EINVAL;
        }
@@ -59,8 +79,8 @@ int ieee802154_nl_assoc_indic(struct net_device *dev,
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
-                   addr->hwaddr) ||
+           nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
+                          addr->extended_addr) ||
            nla_put_u8(msg, IEEE802154_ATTR_CAPABILITY, cap))
                goto nla_put_failure;
 
@@ -72,7 +92,7 @@ nla_put_failure:
 }
 EXPORT_SYMBOL(ieee802154_nl_assoc_indic);
 
-int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
+int ieee802154_nl_assoc_confirm(struct net_device *dev, __le16 short_addr,
                u8 status)
 {
        struct sk_buff *msg;
@@ -87,7 +107,7 @@ int ieee802154_nl_assoc_confirm(struct net_device *dev, u16 short_addr,
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
+           nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
            nla_put_u8(msg, IEEE802154_ATTR_STATUS, status))
                goto nla_put_failure;
        return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
@@ -114,13 +134,13 @@ int ieee802154_nl_disassoc_indic(struct net_device *dev,
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr))
                goto nla_put_failure;
-       if (addr->addr_type == IEEE802154_ADDR_LONG) {
-               if (nla_put(msg, IEEE802154_ATTR_SRC_HW_ADDR, IEEE802154_ADDR_LEN,
-                           addr->hwaddr))
+       if (addr->mode == IEEE802154_ADDR_LONG) {
+               if (nla_put_hwaddr(msg, IEEE802154_ATTR_SRC_HW_ADDR,
+                                  addr->extended_addr))
                        goto nla_put_failure;
        } else {
-               if (nla_put_u16(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
-                               addr->short_addr))
+               if (nla_put_shortaddr(msg, IEEE802154_ATTR_SRC_SHORT_ADDR,
+                                     addr->short_addr))
                        goto nla_put_failure;
        }
        if (nla_put_u8(msg, IEEE802154_ATTR_REASON, reason))
@@ -157,8 +177,8 @@ nla_put_failure:
 }
 EXPORT_SYMBOL(ieee802154_nl_disassoc_confirm);
 
-int ieee802154_nl_beacon_indic(struct net_device *dev,
-               u16 panid, u16 coord_addr)
+int ieee802154_nl_beacon_indic(struct net_device *dev, __le16 panid,
+                              __le16 coord_addr)
 {
        struct sk_buff *msg;
 
@@ -172,8 +192,9 @@ int ieee802154_nl_beacon_indic(struct net_device *dev,
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_COORD_SHORT_ADDR, coord_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
+           nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_SHORT_ADDR,
+                             coord_addr) ||
+           nla_put_shortaddr(msg, IEEE802154_ATTR_COORD_PAN_ID, panid))
                goto nla_put_failure;
        return ieee802154_nl_mcast(msg, IEEE802154_COORD_MCGRP);
 
@@ -243,6 +264,7 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
 {
        void *hdr;
        struct wpan_phy *phy;
+       __le16 short_addr, pan_id;
 
        pr_debug("%s\n", __func__);
 
@@ -254,15 +276,16 @@ static int ieee802154_nl_fill_iface(struct sk_buff *msg, u32 portid,
        phy = ieee802154_mlme_ops(dev)->get_phy(dev);
        BUG_ON(!phy);
 
+       short_addr = ieee802154_mlme_ops(dev)->get_short_addr(dev);
+       pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+
        if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
            nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
            nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
            nla_put(msg, IEEE802154_ATTR_HW_ADDR, IEEE802154_ADDR_LEN,
                    dev->dev_addr) ||
-           nla_put_u16(msg, IEEE802154_ATTR_SHORT_ADDR,
-                       ieee802154_mlme_ops(dev)->get_short_addr(dev)) ||
-           nla_put_u16(msg, IEEE802154_ATTR_PAN_ID,
-                       ieee802154_mlme_ops(dev)->get_pan_id(dev)))
+           nla_put_shortaddr(msg, IEEE802154_ATTR_SHORT_ADDR, short_addr) ||
+           nla_put_shortaddr(msg, IEEE802154_ATTR_PAN_ID, pan_id))
                goto nla_put_failure;
        wpan_phy_put(phy);
        return genlmsg_end(msg, hdr);
@@ -322,16 +345,16 @@ int ieee802154_associate_req(struct sk_buff *skb, struct genl_info *info)
                goto out;
 
        if (info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]) {
-               addr.addr_type = IEEE802154_ADDR_LONG;
-               nla_memcpy(addr.hwaddr,
-                               info->attrs[IEEE802154_ATTR_COORD_HW_ADDR],
-                               IEEE802154_ADDR_LEN);
+               addr.mode = IEEE802154_ADDR_LONG;
+               addr.extended_addr = nla_get_hwaddr(
+                               info->attrs[IEEE802154_ATTR_COORD_HW_ADDR]);
        } else {
-               addr.addr_type = IEEE802154_ADDR_SHORT;
-               addr.short_addr = nla_get_u16(
+               addr.mode = IEEE802154_ADDR_SHORT;
+               addr.short_addr = nla_get_shortaddr(
                                info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
        }
-       addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+       addr.pan_id = nla_get_shortaddr(
+                       info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 
        if (info->attrs[IEEE802154_ATTR_PAGE])
                page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
@@ -365,14 +388,13 @@ int ieee802154_associate_resp(struct sk_buff *skb, struct genl_info *info)
        if (!ieee802154_mlme_ops(dev)->assoc_resp)
                goto out;
 
-       addr.addr_type = IEEE802154_ADDR_LONG;
-       nla_memcpy(addr.hwaddr, info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
-                       IEEE802154_ADDR_LEN);
+       addr.mode = IEEE802154_ADDR_LONG;
+       addr.extended_addr = nla_get_hwaddr(
+                       info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-
        ret = ieee802154_mlme_ops(dev)->assoc_resp(dev, &addr,
-               nla_get_u16(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
+               nla_get_shortaddr(info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]),
                nla_get_u8(info->attrs[IEEE802154_ATTR_STATUS]));
 
 out:
@@ -398,13 +420,12 @@ int ieee802154_disassociate_req(struct sk_buff *skb, struct genl_info *info)
                goto out;
 
        if (info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]) {
-               addr.addr_type = IEEE802154_ADDR_LONG;
-               nla_memcpy(addr.hwaddr,
-                               info->attrs[IEEE802154_ATTR_DEST_HW_ADDR],
-                               IEEE802154_ADDR_LEN);
+               addr.mode = IEEE802154_ADDR_LONG;
+               addr.extended_addr = nla_get_hwaddr(
+                               info->attrs[IEEE802154_ATTR_DEST_HW_ADDR]);
        } else {
-               addr.addr_type = IEEE802154_ADDR_SHORT;
-               addr.short_addr = nla_get_u16(
+               addr.mode = IEEE802154_ADDR_SHORT;
+               addr.short_addr = nla_get_shortaddr(
                                info->attrs[IEEE802154_ATTR_DEST_SHORT_ADDR]);
        }
        addr.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
@@ -449,10 +470,11 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
        if (!ieee802154_mlme_ops(dev)->start_req)
                goto out;
 
-       addr.addr_type = IEEE802154_ADDR_SHORT;
-       addr.short_addr = nla_get_u16(
+       addr.mode = IEEE802154_ADDR_SHORT;
+       addr.short_addr = nla_get_shortaddr(
                        info->attrs[IEEE802154_ATTR_COORD_SHORT_ADDR]);
-       addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
+       addr.pan_id = nla_get_shortaddr(
+                       info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
 
        channel = nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]);
        bcn_ord = nla_get_u8(info->attrs[IEEE802154_ATTR_BCN_ORD]);
@@ -467,7 +489,7 @@ int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
                page = 0;
 
 
-       if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
+       if (addr.short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) {
                ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
                dev_put(dev);
                return -EINVAL;
index 89b265aea151eaf7f301c28f391d064b7d22edfc..222310a07762237cee3f1d339348dc73ab8f6dda 100644 (file)
@@ -55,7 +55,15 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
        mutex_lock(&phy->pib_lock);
        if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) ||
            nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) ||
-           nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel))
+           nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel) ||
+           nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, phy->transmit_power) ||
+           nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt) ||
+           nla_put_u8(msg, IEEE802154_ATTR_CCA_MODE, phy->cca_mode) ||
+           nla_put_s32(msg, IEEE802154_ATTR_CCA_ED_LEVEL, phy->cca_ed_level) ||
+           nla_put_u8(msg, IEEE802154_ATTR_CSMA_RETRIES, phy->csma_retries) ||
+           nla_put_u8(msg, IEEE802154_ATTR_CSMA_MIN_BE, phy->min_be) ||
+           nla_put_u8(msg, IEEE802154_ATTR_CSMA_MAX_BE, phy->max_be) ||
+           nla_put_s8(msg, IEEE802154_ATTR_FRAME_RETRIES, phy->frame_retries))
                goto nla_put_failure;
        for (i = 0; i < 32; i++) {
                if (phy->channels_supported[i])
@@ -354,3 +362,193 @@ out_dev:
 
        return rc;
 }
+
+static int phy_set_txpower(struct wpan_phy *phy, struct genl_info *info)
+{
+       int txpower = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]);
+       int rc;
+
+       rc = phy->set_txpower(phy, txpower);
+       if (rc < 0)
+               return rc;
+
+       phy->transmit_power = txpower;
+
+       return 0;
+}
+
+static int phy_set_lbt(struct wpan_phy *phy, struct genl_info *info)
+{
+       u8 on = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]);
+       int rc;
+
+       rc = phy->set_lbt(phy, on);
+       if (rc < 0)
+               return rc;
+
+       phy->lbt = on;
+
+       return 0;
+}
+
+static int phy_set_cca_mode(struct wpan_phy *phy, struct genl_info *info)
+{
+       u8 mode = nla_get_u8(info->attrs[IEEE802154_ATTR_CCA_MODE]);
+       int rc;
+
+       if (mode > 3)
+               return -EINVAL;
+
+       rc = phy->set_cca_mode(phy, mode);
+       if (rc < 0)
+               return rc;
+
+       phy->cca_mode = mode;
+
+       return 0;
+}
+
+static int phy_set_cca_ed_level(struct wpan_phy *phy, struct genl_info *info)
+{
+       s32 level = nla_get_s32(info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]);
+       int rc;
+
+       rc = phy->set_cca_ed_level(phy, level);
+       if (rc < 0)
+               return rc;
+
+       phy->cca_ed_level = level;
+
+       return 0;
+}
+
+static int phy_set_csma_params(struct wpan_phy *phy, struct genl_info *info)
+{
+       int rc;
+       u8 min_be = phy->min_be;
+       u8 max_be = phy->max_be;
+       u8 retries = phy->csma_retries;
+
+       if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES])
+               retries = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_RETRIES]);
+       if (info->attrs[IEEE802154_ATTR_CSMA_MIN_BE])
+               min_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MIN_BE]);
+       if (info->attrs[IEEE802154_ATTR_CSMA_MAX_BE])
+               max_be = nla_get_u8(info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]);
+
+       if (retries > 5 || max_be < 3 || max_be > 8 || min_be > max_be)
+               return -EINVAL;
+
+       rc = phy->set_csma_params(phy, min_be, max_be, retries);
+       if (rc < 0)
+               return rc;
+
+       phy->min_be = min_be;
+       phy->max_be = max_be;
+       phy->csma_retries = retries;
+
+       return 0;
+}
+
+static int phy_set_frame_retries(struct wpan_phy *phy, struct genl_info *info)
+{
+       s8 retries = nla_get_s8(info->attrs[IEEE802154_ATTR_FRAME_RETRIES]);
+       int rc;
+
+       if (retries < -1 || retries > 7)
+               return -EINVAL;
+
+       rc = phy->set_frame_retries(phy, retries);
+       if (rc < 0)
+               return rc;
+
+       phy->frame_retries = retries;
+
+       return 0;
+}
+
+int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
+{
+       struct wpan_phy *phy;
+       const char *name;
+       int rc = -ENOTSUPP;
+
+       pr_debug("%s\n", __func__);
+
+       if (!info->attrs[IEEE802154_ATTR_PHY_NAME] &&
+           !info->attrs[IEEE802154_ATTR_LBT_ENABLED] &&
+           !info->attrs[IEEE802154_ATTR_CCA_MODE] &&
+           !info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL] &&
+           !info->attrs[IEEE802154_ATTR_CSMA_RETRIES] &&
+           !info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] &&
+           !info->attrs[IEEE802154_ATTR_CSMA_MAX_BE] &&
+           !info->attrs[IEEE802154_ATTR_FRAME_RETRIES])
+               return -EINVAL;
+
+       name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
+       if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
+               return -EINVAL; /* phy name should be null-terminated */
+
+       phy = wpan_phy_find(name);
+       if (!phy)
+               return -ENODEV;
+
+       if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) ||
+           (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]) ||
+           (!phy->set_cca_mode && info->attrs[IEEE802154_ATTR_CCA_MODE]) ||
+           (!phy->set_cca_ed_level &&
+            info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]))
+               goto out;
+
+       mutex_lock(&phy->pib_lock);
+
+       if (info->attrs[IEEE802154_ATTR_TXPOWER]) {
+               rc = phy_set_txpower(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
+
+       if (info->attrs[IEEE802154_ATTR_LBT_ENABLED]) {
+               rc = phy_set_lbt(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
+
+       if (info->attrs[IEEE802154_ATTR_CCA_MODE]) {
+               rc = phy_set_cca_mode(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
+
+       if (info->attrs[IEEE802154_ATTR_CCA_ED_LEVEL]) {
+               rc = phy_set_cca_ed_level(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
+
+       if (info->attrs[IEEE802154_ATTR_CSMA_RETRIES] ||
+           info->attrs[IEEE802154_ATTR_CSMA_MIN_BE] ||
+           info->attrs[IEEE802154_ATTR_CSMA_MAX_BE]) {
+               rc = phy_set_csma_params(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
+
+       if (info->attrs[IEEE802154_ATTR_FRAME_RETRIES]) {
+               rc = phy_set_frame_retries(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
+
+       mutex_unlock(&phy->pib_lock);
+
+       wpan_phy_put(phy);
+
+       return 0;
+
+error:
+       mutex_unlock(&phy->pib_lock);
+out:
+       wpan_phy_put(phy);
+       return rc;
+}
index 6adda4d46f95255d6540f639e383c9985a949138..fd7be5e45cefb99d37df9d173c9bf7c0ab1d7dc3 100644 (file)
@@ -52,5 +52,15 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
        [IEEE802154_ATTR_DURATION] = { .type = NLA_U8, },
        [IEEE802154_ATTR_ED_LIST] = { .len = 27 },
        [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, },
+
+       [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, },
+       [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_CCA_MODE] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
+       [IEEE802154_ATTR_CSMA_RETRIES] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_CSMA_MIN_BE] = { .type = NLA_U8, },
+       [IEEE802154_ATTR_CSMA_MAX_BE] = { .type = NLA_U8, },
+
+       [IEEE802154_ATTR_FRAME_RETRIES] = { .type = NLA_S8, },
 };
 
index 41f538b8e59c9d7912cdf51287d9afa7a116c646..74d54fae33d74a58ca2628f7547250906bea663e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <net/af_ieee802154.h>
+#include <net/ieee802154_netdev.h>
 
 #include "af802154.h"
 
@@ -55,21 +56,24 @@ static void raw_close(struct sock *sk, long timeout)
        sk_common_release(sk);
 }
 
-static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
+static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
 {
-       struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
+       struct ieee802154_addr addr;
+       struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
        int err = 0;
        struct net_device *dev = NULL;
 
-       if (len < sizeof(*addr))
+       if (len < sizeof(*uaddr))
                return -EINVAL;
 
-       if (addr->family != AF_IEEE802154)
+       uaddr = (struct sockaddr_ieee802154 *)_uaddr;
+       if (uaddr->family != AF_IEEE802154)
                return -EINVAL;
 
        lock_sock(sk);
 
-       dev = ieee802154_get_dev(sock_net(sk), &addr->addr);
+       ieee802154_addr_from_sa(&addr, &uaddr->addr);
+       dev = ieee802154_get_dev(sock_net(sk), &addr);
        if (!dev) {
                err = -ENODEV;
                goto out;
@@ -209,6 +213,10 @@ out:
 
 static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (!skb)
+               return NET_RX_DROP;
+
        if (sock_queue_rcv_skb(sk, skb) < 0) {
                kfree_skb(skb);
                return NET_RX_DROP;
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c
new file mode 100644 (file)
index 0000000..ef2d543
--- /dev/null
@@ -0,0 +1,571 @@
+/*     6LoWPAN fragment reassembly
+ *
+ *
+ *     Authors:
+ *     Alexander Aring         <aar@pengutronix.de>
+ *
+ *     Based on: net/ipv6/reassembly.c
+ *
+ *     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) "6LoWPAN: " fmt
+
+#include <linux/net.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include <net/ieee802154_netdev.h>
+#include <net/6lowpan.h>
+#include <net/ipv6.h>
+#include <net/inet_frag.h>
+
+#include "reassembly.h"
+
+struct lowpan_frag_info {
+       __be16 d_tag;
+       u16 d_size;
+       u8 d_offset;
+};
+
+struct lowpan_frag_info *lowpan_cb(struct sk_buff *skb)
+{
+       return (struct lowpan_frag_info *)skb->cb;
+}
+
+static struct inet_frags lowpan_frags;
+
+static int lowpan_frag_reasm(struct lowpan_frag_queue *fq,
+                            struct sk_buff *prev, struct net_device *dev);
+
+static unsigned int lowpan_hash_frag(__be16 tag, u16 d_size,
+                                    const struct ieee802154_addr *saddr,
+                                    const struct ieee802154_addr *daddr)
+{
+       u32 c;
+
+       net_get_random_once(&lowpan_frags.rnd, sizeof(lowpan_frags.rnd));
+       c = jhash_3words(ieee802154_addr_hash(saddr),
+                        ieee802154_addr_hash(daddr),
+                        (__force u32)(tag + (d_size << 16)),
+                        lowpan_frags.rnd);
+
+       return c & (INETFRAGS_HASHSZ - 1);
+}
+
+static unsigned int lowpan_hashfn(struct inet_frag_queue *q)
+{
+       struct lowpan_frag_queue *fq;
+
+       fq = container_of(q, struct lowpan_frag_queue, q);
+       return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr);
+}
+
+static bool lowpan_frag_match(struct inet_frag_queue *q, void *a)
+{
+       struct lowpan_frag_queue *fq;
+       struct lowpan_create_arg *arg = a;
+
+       fq = container_of(q, struct lowpan_frag_queue, q);
+       return  fq->tag == arg->tag && fq->d_size == arg->d_size &&
+               ieee802154_addr_equal(&fq->saddr, arg->src) &&
+               ieee802154_addr_equal(&fq->daddr, arg->dst);
+}
+
+static void lowpan_frag_init(struct inet_frag_queue *q, void *a)
+{
+       struct lowpan_frag_queue *fq;
+       struct lowpan_create_arg *arg = a;
+
+       fq = container_of(q, struct lowpan_frag_queue, q);
+
+       fq->tag = arg->tag;
+       fq->d_size = arg->d_size;
+       fq->saddr = *arg->src;
+       fq->daddr = *arg->dst;
+}
+
+static void lowpan_frag_expire(unsigned long data)
+{
+       struct frag_queue *fq;
+       struct net *net;
+
+       fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
+       net = container_of(fq->q.net, struct net, ieee802154_lowpan.frags);
+
+       spin_lock(&fq->q.lock);
+
+       if (fq->q.last_in & INET_FRAG_COMPLETE)
+               goto out;
+
+       inet_frag_kill(&fq->q, &lowpan_frags);
+out:
+       spin_unlock(&fq->q.lock);
+       inet_frag_put(&fq->q, &lowpan_frags);
+}
+
+static inline struct lowpan_frag_queue *
+fq_find(struct net *net, const struct lowpan_frag_info *frag_info,
+       const struct ieee802154_addr *src,
+       const struct ieee802154_addr *dst)
+{
+       struct inet_frag_queue *q;
+       struct lowpan_create_arg arg;
+       unsigned int hash;
+
+       arg.tag = frag_info->d_tag;
+       arg.d_size = frag_info->d_size;
+       arg.src = src;
+       arg.dst = dst;
+
+       read_lock(&lowpan_frags.lock);
+       hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst);
+
+       q = inet_frag_find(&net->ieee802154_lowpan.frags,
+                          &lowpan_frags, &arg, hash);
+       if (IS_ERR_OR_NULL(q)) {
+               inet_frag_maybe_warn_overflow(q, pr_fmt());
+               return NULL;
+       }
+       return container_of(q, struct lowpan_frag_queue, q);
+}
+
+static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
+                            struct sk_buff *skb, const u8 frag_type)
+{
+       struct sk_buff *prev, *next;
+       struct net_device *dev;
+       int end, offset;
+
+       if (fq->q.last_in & INET_FRAG_COMPLETE)
+               goto err;
+
+       offset = lowpan_cb(skb)->d_offset << 3;
+       end = lowpan_cb(skb)->d_size;
+
+       /* Is this the final fragment? */
+       if (offset + skb->len == end) {
+               /* If we already have some bits beyond end
+                * or have different end, the segment is corrupted.
+                */
+               if (end < fq->q.len ||
+                   ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len))
+                       goto err;
+               fq->q.last_in |= INET_FRAG_LAST_IN;
+               fq->q.len = end;
+       } else {
+               if (end > fq->q.len) {
+                       /* Some bits beyond end -> corruption. */
+                       if (fq->q.last_in & INET_FRAG_LAST_IN)
+                               goto err;
+                       fq->q.len = end;
+               }
+       }
+
+       /* Find out which fragments are in front and at the back of us
+        * in the chain of fragments so far.  We must know where to put
+        * this fragment, right?
+        */
+       prev = fq->q.fragments_tail;
+       if (!prev || lowpan_cb(prev)->d_offset < lowpan_cb(skb)->d_offset) {
+               next = NULL;
+               goto found;
+       }
+       prev = NULL;
+       for (next = fq->q.fragments; next != NULL; next = next->next) {
+               if (lowpan_cb(next)->d_offset >= lowpan_cb(skb)->d_offset)
+                       break;  /* bingo! */
+               prev = next;
+       }
+
+found:
+       /* Insert this fragment in the chain of fragments. */
+       skb->next = next;
+       if (!next)
+               fq->q.fragments_tail = skb;
+       if (prev)
+               prev->next = skb;
+       else
+               fq->q.fragments = skb;
+
+       dev = skb->dev;
+       if (dev)
+               skb->dev = NULL;
+
+       fq->q.stamp = skb->tstamp;
+       if (frag_type == LOWPAN_DISPATCH_FRAG1) {
+               /* Calculate uncomp. 6lowpan header to estimate full size */
+               fq->q.meat += lowpan_uncompress_size(skb, NULL);
+               fq->q.last_in |= INET_FRAG_FIRST_IN;
+       } else {
+               fq->q.meat += skb->len;
+       }
+       add_frag_mem_limit(&fq->q, skb->truesize);
+
+       if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
+           fq->q.meat == fq->q.len) {
+               int res;
+               unsigned long orefdst = skb->_skb_refdst;
+
+               skb->_skb_refdst = 0UL;
+               res = lowpan_frag_reasm(fq, prev, dev);
+               skb->_skb_refdst = orefdst;
+               return res;
+       }
+
+       inet_frag_lru_move(&fq->q);
+       return -1;
+err:
+       kfree_skb(skb);
+       return -1;
+}
+
+/*     Check if this packet is complete.
+ *     Returns NULL on failure by any reason, and pointer
+ *     to current nexthdr field in reassembled frame.
+ *
+ *     It is called with locked fq, and caller must check that
+ *     queue is eligible for reassembly i.e. it is not COMPLETE,
+ *     the last and the first frames arrived and all the bits are here.
+ */
+static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
+                            struct net_device *dev)
+{
+       struct sk_buff *fp, *head = fq->q.fragments;
+       int sum_truesize;
+
+       inet_frag_kill(&fq->q, &lowpan_frags);
+
+       /* Make the one we just received the head. */
+       if (prev) {
+               head = prev->next;
+               fp = skb_clone(head, GFP_ATOMIC);
+
+               if (!fp)
+                       goto out_oom;
+
+               fp->next = head->next;
+               if (!fp->next)
+                       fq->q.fragments_tail = fp;
+               prev->next = fp;
+
+               skb_morph(head, fq->q.fragments);
+               head->next = fq->q.fragments->next;
+
+               consume_skb(fq->q.fragments);
+               fq->q.fragments = head;
+       }
+
+       /* Head of list must not be cloned. */
+       if (skb_unclone(head, GFP_ATOMIC))
+               goto out_oom;
+
+       /* If the first fragment is fragmented itself, we split
+        * it to two chunks: the first with data and paged part
+        * and the second, holding only fragments.
+        */
+       if (skb_has_frag_list(head)) {
+               struct sk_buff *clone;
+               int i, plen = 0;
+
+               clone = alloc_skb(0, GFP_ATOMIC);
+               if (!clone)
+                       goto out_oom;
+               clone->next = head->next;
+               head->next = clone;
+               skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+               skb_frag_list_init(head);
+               for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
+                       plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
+               clone->len = head->data_len - plen;
+               clone->data_len = clone->len;
+               head->data_len -= clone->len;
+               head->len -= clone->len;
+               add_frag_mem_limit(&fq->q, clone->truesize);
+       }
+
+       WARN_ON(head == NULL);
+
+       sum_truesize = head->truesize;
+       for (fp = head->next; fp;) {
+               bool headstolen;
+               int delta;
+               struct sk_buff *next = fp->next;
+
+               sum_truesize += fp->truesize;
+               if (skb_try_coalesce(head, fp, &headstolen, &delta)) {
+                       kfree_skb_partial(fp, headstolen);
+               } else {
+                       if (!skb_shinfo(head)->frag_list)
+                               skb_shinfo(head)->frag_list = fp;
+                       head->data_len += fp->len;
+                       head->len += fp->len;
+                       head->truesize += fp->truesize;
+               }
+               fp = next;
+       }
+       sub_frag_mem_limit(&fq->q, sum_truesize);
+
+       head->next = NULL;
+       head->dev = dev;
+       head->tstamp = fq->q.stamp;
+
+       fq->q.fragments = NULL;
+       fq->q.fragments_tail = NULL;
+
+       return 1;
+out_oom:
+       net_dbg_ratelimited("lowpan_frag_reasm: no memory for reassembly\n");
+       return -1;
+}
+
+static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type,
+                               struct lowpan_frag_info *frag_info)
+{
+       bool fail;
+       u8 pattern = 0, low = 0;
+
+       fail = lowpan_fetch_skb(skb, &pattern, 1);
+       fail |= lowpan_fetch_skb(skb, &low, 1);
+       frag_info->d_size = (pattern & 7) << 8 | low;
+       fail |= lowpan_fetch_skb(skb, &frag_info->d_tag, 2);
+
+       if (frag_type == LOWPAN_DISPATCH_FRAGN) {
+               fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1);
+       } else {
+               skb_reset_network_header(skb);
+               frag_info->d_offset = 0;
+       }
+
+       if (unlikely(fail))
+               return -EIO;
+
+       return 0;
+}
+
+int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
+{
+       struct lowpan_frag_queue *fq;
+       struct net *net = dev_net(skb->dev);
+       struct lowpan_frag_info *frag_info = lowpan_cb(skb);
+       struct ieee802154_addr source, dest;
+       int err;
+
+       source = mac_cb(skb)->source;
+       dest = mac_cb(skb)->dest;
+
+       err = lowpan_get_frag_info(skb, frag_type, frag_info);
+       if (err < 0)
+               goto err;
+
+       if (frag_info->d_size > net->ieee802154_lowpan.max_dsize)
+               goto err;
+
+       inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false);
+
+       fq = fq_find(net, frag_info, &source, &dest);
+       if (fq != NULL) {
+               int ret;
+               spin_lock(&fq->q.lock);
+               ret = lowpan_frag_queue(fq, skb, frag_type);
+               spin_unlock(&fq->q.lock);
+
+               inet_frag_put(&fq->q, &lowpan_frags);
+               return ret;
+       }
+
+err:
+       kfree_skb(skb);
+       return -1;
+}
+EXPORT_SYMBOL(lowpan_frag_rcv);
+
+#ifdef CONFIG_SYSCTL
+static struct ctl_table lowpan_frags_ns_ctl_table[] = {
+       {
+               .procname       = "6lowpanfrag_high_thresh",
+               .data           = &init_net.ieee802154_lowpan.frags.high_thresh,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+       {
+               .procname       = "6lowpanfrag_low_thresh",
+               .data           = &init_net.ieee802154_lowpan.frags.low_thresh,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+       {
+               .procname       = "6lowpanfrag_time",
+               .data           = &init_net.ieee802154_lowpan.frags.timeout,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+       },
+       {
+               .procname       = "6lowpanfrag_max_datagram_size",
+               .data           = &init_net.ieee802154_lowpan.max_dsize,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
+       { }
+};
+
+static struct ctl_table lowpan_frags_ctl_table[] = {
+       {
+               .procname       = "6lowpanfrag_secret_interval",
+               .data           = &lowpan_frags.secret_interval,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+       },
+       { }
+};
+
+static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
+{
+       struct ctl_table *table;
+       struct ctl_table_header *hdr;
+
+       table = lowpan_frags_ns_ctl_table;
+       if (!net_eq(net, &init_net)) {
+               table = kmemdup(table, sizeof(lowpan_frags_ns_ctl_table),
+                               GFP_KERNEL);
+               if (table == NULL)
+                       goto err_alloc;
+
+               table[0].data = &net->ieee802154_lowpan.frags.high_thresh;
+               table[1].data = &net->ieee802154_lowpan.frags.low_thresh;
+               table[2].data = &net->ieee802154_lowpan.frags.timeout;
+               table[3].data = &net->ieee802154_lowpan.max_dsize;
+
+               /* Don't export sysctls to unprivileged users */
+               if (net->user_ns != &init_user_ns)
+                       table[0].procname = NULL;
+       }
+
+       hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table);
+       if (hdr == NULL)
+               goto err_reg;
+
+       net->ieee802154_lowpan.sysctl.frags_hdr = hdr;
+       return 0;
+
+err_reg:
+       if (!net_eq(net, &init_net))
+               kfree(table);
+err_alloc:
+       return -ENOMEM;
+}
+
+static void __net_exit lowpan_frags_ns_sysctl_unregister(struct net *net)
+{
+       struct ctl_table *table;
+
+       table = net->ieee802154_lowpan.sysctl.frags_hdr->ctl_table_arg;
+       unregister_net_sysctl_table(net->ieee802154_lowpan.sysctl.frags_hdr);
+       if (!net_eq(net, &init_net))
+               kfree(table);
+}
+
+static struct ctl_table_header *lowpan_ctl_header;
+
+static int lowpan_frags_sysctl_register(void)
+{
+       lowpan_ctl_header = register_net_sysctl(&init_net,
+                                               "net/ieee802154/6lowpan",
+                                               lowpan_frags_ctl_table);
+       return lowpan_ctl_header == NULL ? -ENOMEM : 0;
+}
+
+static void lowpan_frags_sysctl_unregister(void)
+{
+       unregister_net_sysctl_table(lowpan_ctl_header);
+}
+#else
+static inline int lowpan_frags_ns_sysctl_register(struct net *net)
+{
+       return 0;
+}
+
+static inline void lowpan_frags_ns_sysctl_unregister(struct net *net)
+{
+}
+
+static inline int lowpan_frags_sysctl_register(void)
+{
+       return 0;
+}
+
+static inline void lowpan_frags_sysctl_unregister(void)
+{
+}
+#endif
+
+static int __net_init lowpan_frags_init_net(struct net *net)
+{
+       net->ieee802154_lowpan.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
+       net->ieee802154_lowpan.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
+       net->ieee802154_lowpan.frags.timeout = IPV6_FRAG_TIMEOUT;
+       net->ieee802154_lowpan.max_dsize = 0xFFFF;
+
+       inet_frags_init_net(&net->ieee802154_lowpan.frags);
+
+       return lowpan_frags_ns_sysctl_register(net);
+}
+
+static void __net_exit lowpan_frags_exit_net(struct net *net)
+{
+       lowpan_frags_ns_sysctl_unregister(net);
+       inet_frags_exit_net(&net->ieee802154_lowpan.frags, &lowpan_frags);
+}
+
+static struct pernet_operations lowpan_frags_ops = {
+       .init = lowpan_frags_init_net,
+       .exit = lowpan_frags_exit_net,
+};
+
+int __init lowpan_net_frag_init(void)
+{
+       int ret;
+
+       ret = lowpan_frags_sysctl_register();
+       if (ret)
+               return ret;
+
+       ret = register_pernet_subsys(&lowpan_frags_ops);
+       if (ret)
+               goto err_pernet;
+
+       lowpan_frags.hashfn = lowpan_hashfn;
+       lowpan_frags.constructor = lowpan_frag_init;
+       lowpan_frags.destructor = NULL;
+       lowpan_frags.skb_free = NULL;
+       lowpan_frags.qsize = sizeof(struct frag_queue);
+       lowpan_frags.match = lowpan_frag_match;
+       lowpan_frags.frag_expire = lowpan_frag_expire;
+       lowpan_frags.secret_interval = 10 * 60 * HZ;
+       inet_frags_init(&lowpan_frags);
+
+       return ret;
+err_pernet:
+       lowpan_frags_sysctl_unregister();
+       return ret;
+}
+
+void lowpan_net_frag_exit(void)
+{
+       inet_frags_fini(&lowpan_frags);
+       lowpan_frags_sysctl_unregister();
+       unregister_pernet_subsys(&lowpan_frags_ops);
+}
diff --git a/net/ieee802154/reassembly.h b/net/ieee802154/reassembly.h
new file mode 100644 (file)
index 0000000..74e4a7c
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef __IEEE802154_6LOWPAN_REASSEMBLY_H__
+#define __IEEE802154_6LOWPAN_REASSEMBLY_H__
+
+#include <net/inet_frag.h>
+
+struct lowpan_create_arg {
+       __be16 tag;
+       u16 d_size;
+       const struct ieee802154_addr *src;
+       const struct ieee802154_addr *dst;
+};
+
+/* Equivalent of ipv4 struct ip
+ */
+struct lowpan_frag_queue {
+       struct inet_frag_queue  q;
+
+       __be16                  tag;
+       u16                     d_size;
+       struct ieee802154_addr  saddr;
+       struct ieee802154_addr  daddr;
+};
+
+static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
+{
+       switch (a->mode) {
+       case IEEE802154_ADDR_LONG:
+               return (((__force u64)a->extended_addr) >> 32) ^
+                       (((__force u64)a->extended_addr) & 0xffffffff);
+       case IEEE802154_ADDR_SHORT:
+               return (__force u32)(a->short_addr);
+       default:
+               return 0;
+       }
+}
+
+int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
+void lowpan_net_frag_exit(void);
+int lowpan_net_frag_init(void);
+
+#endif /* __IEEE802154_6LOWPAN_REASSEMBLY_H__ */
index 4dd37615a749c6f1191d5ce35bec09ca9ac05e81..edd0962d55f9a14a18c8901ffa0fa32432c1fcf6 100644 (file)
@@ -44,9 +44,7 @@ static DEVICE_ATTR_RO(name);
 
 MASTER_SHOW(current_channel, "%d");
 MASTER_SHOW(current_page, "%d");
-MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB",
-       ((signed char) (phy->transmit_power << 2)) >> 2,
-       (phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1);
+MASTER_SHOW(transmit_power, "%d +- 1 dB");
 MASTER_SHOW(cca_mode, "%d");
 
 static ssize_t channels_supported_show(struct device *dev,
@@ -171,6 +169,12 @@ struct wpan_phy *wpan_phy_alloc(size_t priv_size)
        phy->current_channel = -1; /* not initialised */
        phy->current_page = 0; /* for compatibility */
 
+       /* defaults per 802.15.4-2011 */
+       phy->min_be = 3;
+       phy->max_be = 5;
+       phy->csma_retries = 4;
+       phy->frame_retries = -1; /* for compatibility, actual default is 3 */
+
        return phy;
 
 out:
index f8c49ce5b2839f96b5147185cfbb0402bba23da8..f032688d20d308412694cbc7ef29567a86264b4b 100644 (file)
@@ -55,4 +55,4 @@ obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
 obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
 
 obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
-                     xfrm4_output.o
+                     xfrm4_output.o xfrm4_protocol.o
index ecd2c3f245ce2b2e0b79f17417c5e6ad8c70abf6..8c54870db792cab059bff464d29776510ec3e5ec 100644 (file)
@@ -1296,8 +1296,11 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
 
        segs = ERR_PTR(-EPROTONOSUPPORT);
 
-       /* Note : following gso_segment() might change skb->encapsulation */
-       udpfrag = !skb->encapsulation && proto == IPPROTO_UDP;
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
 
        ops = rcu_dereference(inet_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment))
@@ -1502,9 +1505,9 @@ u64 snmp_fold_field64(void __percpu *mib[], int offt, size_t syncp_offset)
                bhptr = per_cpu_ptr(mib[0], cpu);
                syncp = (struct u64_stats_sync *)(bhptr + syncp_offset);
                do {
-                       start = u64_stats_fetch_begin_bh(syncp);
+                       start = u64_stats_fetch_begin_irq(syncp);
                        v = *(((u64 *) bhptr) + offt);
-               } while (u64_stats_fetch_retry_bh(syncp, start));
+               } while (u64_stats_fetch_retry_irq(syncp, start));
 
                res += v;
        }
index 717902669d2f2ef34714c215c4695ffe59ddd283..a2afa89513a06d43ecdac6033dfcf89c16ea8ffc 100644 (file)
@@ -155,6 +155,10 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
        struct iphdr *iph, *top_iph;
        struct ip_auth_hdr *ah;
        struct ah_data *ahp;
+       int seqhi_len = 0;
+       __be32 *seqhi;
+       int sglists = 0;
+       struct scatterlist *seqhisg;
 
        ahp = x->data;
        ahash = ahp->ahash;
@@ -167,14 +171,19 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
        ah = ip_auth_hdr(skb);
        ihl = ip_hdrlen(skb);
 
+       if (x->props.flags & XFRM_STATE_ESN) {
+               sglists = 1;
+               seqhi_len = sizeof(*seqhi);
+       }
        err = -ENOMEM;
-       iph = ah_alloc_tmp(ahash, nfrags, ihl);
+       iph = ah_alloc_tmp(ahash, nfrags + sglists, ihl + seqhi_len);
        if (!iph)
                goto out;
-
-       icv = ah_tmp_icv(ahash, iph, ihl);
+       seqhi = (__be32 *)((char *)iph + ihl);
+       icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
        req = ah_tmp_req(ahash, icv);
        sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
 
        memset(ah->auth_data, 0, ahp->icv_trunc_len);
 
@@ -210,10 +219,15 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
        ah->spi = x->id.spi;
        ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
 
-       sg_init_table(sg, nfrags);
-       skb_to_sgvec(skb, sg, 0, skb->len);
+       sg_init_table(sg, nfrags + sglists);
+       skb_to_sgvec_nomark(skb, sg, 0, skb->len);
 
-       ahash_request_set_crypt(req, sg, icv, skb->len);
+       if (x->props.flags & XFRM_STATE_ESN) {
+               /* Attach seqhi sg right after packet payload */
+               *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
+               sg_set_buf(seqhisg, seqhi, seqhi_len);
+       }
+       ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
        ahash_request_set_callback(req, 0, ah_output_done, skb);
 
        AH_SKB_CB(skb)->tmp = iph;
@@ -295,6 +309,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
        struct ip_auth_hdr *ah;
        struct ah_data *ahp;
        int err = -ENOMEM;
+       int seqhi_len = 0;
+       __be32 *seqhi;
+       int sglists = 0;
+       struct scatterlist *seqhisg;
 
        if (!pskb_may_pull(skb, sizeof(*ah)))
                goto out;
@@ -335,14 +353,22 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
        iph = ip_hdr(skb);
        ihl = ip_hdrlen(skb);
 
-       work_iph = ah_alloc_tmp(ahash, nfrags, ihl + ahp->icv_trunc_len);
+       if (x->props.flags & XFRM_STATE_ESN) {
+               sglists = 1;
+               seqhi_len = sizeof(*seqhi);
+       }
+
+       work_iph = ah_alloc_tmp(ahash, nfrags + sglists, ihl +
+                               ahp->icv_trunc_len + seqhi_len);
        if (!work_iph)
                goto out;
 
-       auth_data = ah_tmp_auth(work_iph, ihl);
+       seqhi = (__be32 *)((char *)work_iph + ihl);
+       auth_data = ah_tmp_auth(seqhi, seqhi_len);
        icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
        req = ah_tmp_req(ahash, icv);
        sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
 
        memcpy(work_iph, iph, ihl);
        memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
@@ -361,10 +387,15 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 
        skb_push(skb, ihl);
 
-       sg_init_table(sg, nfrags);
-       skb_to_sgvec(skb, sg, 0, skb->len);
+       sg_init_table(sg, nfrags + sglists);
+       skb_to_sgvec_nomark(skb, sg, 0, skb->len);
 
-       ahash_request_set_crypt(req, sg, icv, skb->len);
+       if (x->props.flags & XFRM_STATE_ESN) {
+               /* Attach seqhi sg right after packet payload */
+               *seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
+               sg_set_buf(seqhisg, seqhi, seqhi_len);
+       }
+       ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
        ahash_request_set_callback(req, 0, ah_input_done, skb);
 
        AH_SKB_CB(skb)->tmp = work_iph;
@@ -397,7 +428,7 @@ out:
        return err;
 }
 
-static void ah4_err(struct sk_buff *skb, u32 info)
+static int ah4_err(struct sk_buff *skb, u32 info)
 {
        struct net *net = dev_net(skb->dev);
        const struct iphdr *iph = (const struct iphdr *)skb->data;
@@ -407,23 +438,25 @@ static void ah4_err(struct sk_buff *skb, u32 info)
        switch (icmp_hdr(skb)->type) {
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
-                       return;
+                       return 0;
        case ICMP_REDIRECT:
                break;
        default:
-               return;
+               return 0;
        }
 
        x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
                              ah->spi, IPPROTO_AH, AF_INET);
        if (!x)
-               return;
+               return 0;
 
        if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
                ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
        else
                ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
        xfrm_state_put(x);
+
+       return 0;
 }
 
 static int ah_init_state(struct xfrm_state *x)
@@ -505,6 +538,10 @@ static void ah_destroy(struct xfrm_state *x)
        kfree(ahp);
 }
 
+static int ah4_rcv_cb(struct sk_buff *skb, int err)
+{
+       return 0;
+}
 
 static const struct xfrm_type ah_type =
 {
@@ -518,11 +555,12 @@ static const struct xfrm_type ah_type =
        .output         = ah_output
 };
 
-static const struct net_protocol ah4_protocol = {
+static struct xfrm4_protocol ah4_protocol = {
        .handler        =       xfrm4_rcv,
+       .input_handler  =       xfrm_input,
+       .cb_handler     =       ah4_rcv_cb,
        .err_handler    =       ah4_err,
-       .no_policy      =       1,
-       .netns_ok       =       1,
+       .priority       =       0,
 };
 
 static int __init ah4_init(void)
@@ -531,7 +569,7 @@ static int __init ah4_init(void)
                pr_info("%s: can't add xfrm type\n", __func__);
                return -EAGAIN;
        }
-       if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) {
+       if (xfrm4_protocol_register(&ah4_protocol, IPPROTO_AH) < 0) {
                pr_info("%s: can't add protocol\n", __func__);
                xfrm_unregister_type(&ah_type, AF_INET);
                return -EAGAIN;
@@ -541,7 +579,7 @@ static int __init ah4_init(void)
 
 static void __exit ah4_fini(void)
 {
-       if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0)
+       if (xfrm4_protocol_deregister(&ah4_protocol, IPPROTO_AH) < 0)
                pr_info("%s: can't remove protocol\n", __func__);
        if (xfrm_unregister_type(&ah_type, AF_INET) < 0)
                pr_info("%s: can't remove xfrm type\n", __func__);
index ac2dff3c2c1cf053cce19edf5179daf750dc2732..bdbf68bb2e2d194fcdf94553bd41a4ac9f184d7c 100644 (file)
@@ -1443,7 +1443,8 @@ static size_t inet_nlmsg_size(void)
               + nla_total_size(4) /* IFA_LOCAL */
               + nla_total_size(4) /* IFA_BROADCAST */
               + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
-              + nla_total_size(4);  /* IFA_FLAGS */
+              + nla_total_size(4)  /* IFA_FLAGS */
+              + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
 }
 
 static inline u32 cstamp_delta(unsigned long cstamp)
index 7785b28061acfecd59e4ece70815edb3dcc58977..360b565918c4b524d561a010ed7ec5df02312cdb 100644 (file)
@@ -473,7 +473,7 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
                 net_adj) & ~(blksize - 1)) + net_adj - 2;
 }
 
-static void esp4_err(struct sk_buff *skb, u32 info)
+static int esp4_err(struct sk_buff *skb, u32 info)
 {
        struct net *net = dev_net(skb->dev);
        const struct iphdr *iph = (const struct iphdr *)skb->data;
@@ -483,23 +483,25 @@ static void esp4_err(struct sk_buff *skb, u32 info)
        switch (icmp_hdr(skb)->type) {
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
-                       return;
+                       return 0;
        case ICMP_REDIRECT:
                break;
        default:
-               return;
+               return 0;
        }
 
        x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
                              esph->spi, IPPROTO_ESP, AF_INET);
        if (!x)
-               return;
+               return 0;
 
        if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
                ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
        else
                ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
        xfrm_state_put(x);
+
+       return 0;
 }
 
 static void esp_destroy(struct xfrm_state *x)
@@ -672,6 +674,11 @@ error:
        return err;
 }
 
+static int esp4_rcv_cb(struct sk_buff *skb, int err)
+{
+       return 0;
+}
+
 static const struct xfrm_type esp_type =
 {
        .description    = "ESP4",
@@ -685,11 +692,12 @@ static const struct xfrm_type esp_type =
        .output         = esp_output
 };
 
-static const struct net_protocol esp4_protocol = {
+static struct xfrm4_protocol esp4_protocol = {
        .handler        =       xfrm4_rcv,
+       .input_handler  =       xfrm_input,
+       .cb_handler     =       esp4_rcv_cb,
        .err_handler    =       esp4_err,
-       .no_policy      =       1,
-       .netns_ok       =       1,
+       .priority       =       0,
 };
 
 static int __init esp4_init(void)
@@ -698,7 +706,7 @@ static int __init esp4_init(void)
                pr_info("%s: can't add xfrm type\n", __func__);
                return -EAGAIN;
        }
-       if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) {
+       if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) {
                pr_info("%s: can't add protocol\n", __func__);
                xfrm_unregister_type(&esp_type, AF_INET);
                return -EAGAIN;
@@ -708,7 +716,7 @@ static int __init esp4_init(void)
 
 static void __exit esp4_fini(void)
 {
-       if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0)
+       if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
                pr_info("%s: can't remove protocol\n", __func__);
        if (xfrm_unregister_type(&esp_type, AF_INET) < 0)
                pr_info("%s: can't remove xfrm type\n", __func__);
index c7539e22868b37d59018730aca786176df5408ee..1a629f870274de3c1b70910ec5285f7baae139eb 100644 (file)
@@ -659,7 +659,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
        if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
            ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
-               return ip_rt_dump(skb, cb);
+               return skb->len;
 
        s_h = cb->args[0];
        s_e = cb->args[1];
index 1863422fb7d553340151b1402ee30d4be1fcde29..250be7421ab36c50ce00a25dcd3c659ca1c97f18 100644 (file)
@@ -182,6 +182,14 @@ static int gre_cisco_rcv(struct sk_buff *skb)
        int i;
        bool csum_err = false;
 
+#ifdef CONFIG_NET_IPGRE_BROADCAST
+       if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
+               /* Looped back packet, drop it! */
+               if (rt_is_output_route(skb_rtable(skb)))
+                       goto drop;
+       }
+#endif
+
        if (parse_gre_header(skb, &tpi, &csum_err) < 0)
                goto drop;
 
index bb075fc9a14f25169c175c7fcdcb86d56c709627..3b01959bf4bb0bbc208d8d564c8595c67eedd179 100644 (file)
@@ -208,7 +208,7 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f, bool force)
        }
 
        work = frag_mem_limit(nf) - nf->low_thresh;
-       while (work > 0) {
+       while (work > 0 || force) {
                spin_lock(&nf->lru_lock);
 
                if (list_empty(&nf->lru_list)) {
@@ -278,9 +278,10 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 
        atomic_inc(&qp->refcnt);
        hlist_add_head(&qp->list, &hb->chain);
+       inet_frag_lru_add(nf, qp);
        spin_unlock(&hb->chain_lock);
        read_unlock(&f->lock);
-       inet_frag_lru_add(nf, qp);
+
        return qp;
 }
 
index e9f1217a8afdaf2559ce3fd7d134489994faf440..be8abe73bb9f464a2e68679255acde3b708ce84b 100644 (file)
 #include <net/route.h>
 #include <net/xfrm.h>
 
+static bool ip_may_fragment(const struct sk_buff *skb)
+{
+       return unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) ||
+              !skb->local_df;
+}
+
+static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
+{
+       if (skb->len <= mtu || skb->local_df)
+               return false;
+
+       if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
+               return false;
+
+       return true;
+}
+
+static bool ip_gso_exceeds_dst_mtu(const struct sk_buff *skb)
+{
+       unsigned int mtu;
+
+       if (skb->local_df || !skb_is_gso(skb))
+               return false;
+
+       mtu = ip_dst_mtu_maybe_forward(skb_dst(skb), true);
+
+       /* if seglen > mtu, do software segmentation for IP fragmentation on
+        * output.  DF bit cannot be set since ip_forward would have sent
+        * icmp error.
+        */
+       return skb_gso_network_seglen(skb) > mtu;
+}
+
+/* called if GSO skb needs to be fragmented on forward */
+static int ip_forward_finish_gso(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+       netdev_features_t features;
+       struct sk_buff *segs;
+       int ret = 0;
+
+       features = netif_skb_dev_features(skb, dst->dev);
+       segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
+       if (IS_ERR(segs)) {
+               kfree_skb(skb);
+               return -ENOMEM;
+       }
+
+       consume_skb(skb);
+
+       do {
+               struct sk_buff *nskb = segs->next;
+               int err;
+
+               segs->next = NULL;
+               err = dst_output(segs);
+
+               if (err && ret == 0)
+                       ret = err;
+               segs = nskb;
+       } while (segs);
+
+       return ret;
+}
+
 static int ip_forward_finish(struct sk_buff *skb)
 {
        struct ip_options *opt  = &(IPCB(skb)->opt);
@@ -49,6 +114,9 @@ static int ip_forward_finish(struct sk_buff *skb)
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
 
+       if (ip_gso_exceeds_dst_mtu(skb))
+               return ip_forward_finish_gso(skb);
+
        return dst_output(skb);
 }
 
@@ -59,6 +127,10 @@ int ip_forward(struct sk_buff *skb)
        struct rtable *rt;      /* Route we use */
        struct ip_options *opt  = &(IPCB(skb)->opt);
 
+       /* that should never happen */
+       if (skb->pkt_type != PACKET_HOST)
+               goto drop;
+
        if (skb_warn_if_lro(skb))
                goto drop;
 
@@ -68,9 +140,6 @@ int ip_forward(struct sk_buff *skb)
        if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
                return NET_RX_SUCCESS;
 
-       if (skb->pkt_type != PACKET_HOST)
-               goto drop;
-
        skb_forward_csum(skb);
 
        /*
@@ -91,8 +160,7 @@ int ip_forward(struct sk_buff *skb)
 
        IPCB(skb)->flags |= IPSKB_FORWARDED;
        mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);
-       if (unlikely(skb->len > mtu && !skb_is_gso(skb) &&
-                    (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
+       if (!ip_may_fragment(skb) && ip_exceeds_mtu(skb, mtu)) {
                IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
                          htonl(mtu));
index 8971780aec7c5fadb4223c0391b05aa9c881ba34..1a0755fea4914c20f95d036f30638ea2677b764f 100644 (file)
@@ -422,9 +422,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       to->nf_trace = from->nf_trace;
-#endif
 #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
        to->ipvs_property = from->ipvs_property;
 #endif
@@ -449,7 +446,6 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
        __be16 not_last_frag;
        struct rtable *rt = skb_rtable(skb);
        int err = 0;
-       bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED;
 
        dev = rt->dst.dev;
 
@@ -459,7 +455,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
        iph = ip_hdr(skb);
 
-       mtu = ip_dst_mtu_maybe_forward(&rt->dst, forwarding);
+       mtu = ip_skb_dst_mtu(skb);
        if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) ||
                     (IPCB(skb)->frag_max_size &&
                      IPCB(skb)->frag_max_size > mtu))) {
@@ -825,8 +821,7 @@ static int __ip_append_data(struct sock *sk,
 
        fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
        maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
-       maxnonfragsize = (inet->pmtudisc >= IP_PMTUDISC_DO) ?
-                        mtu : 0xFFFF;
+       maxnonfragsize = ip_sk_local_df(sk) ? 0xFFFF : mtu;
 
        if (cork->length + length > maxnonfragsize - fragheaderlen) {
                ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
@@ -1149,8 +1144,7 @@ ssize_t   ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
 
        fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
        maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;
-       maxnonfragsize = (inet->pmtudisc >= IP_PMTUDISC_DO) ?
-                        mtu : 0xFFFF;
+       maxnonfragsize = ip_sk_local_df(sk) ? 0xFFFF : mtu;
 
        if (cork->length + size > maxnonfragsize - fragheaderlen) {
                ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
@@ -1311,8 +1305,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
         * to fragment the frame generated here. No matter, what transforms
         * how transforms change size of the packet, it will come out.
         */
-       if (inet->pmtudisc < IP_PMTUDISC_DO)
-               skb->local_df = 1;
+       skb->local_df = ip_sk_local_df(sk);
 
        /* DF bit is set when we want to see DF on outgoing frames.
         * If local_df is set too, we still allow to fragment this frame
index 580dd96666e09b9c88a7e5f9b57f613ce7027a2d..64741b9386329ba6a76b00ea660d78983d2efb8a 100644 (file)
@@ -186,7 +186,8 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ip_cmsg_recv);
 
-int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
+int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc,
+                bool allow_ipv6)
 {
        int err, val;
        struct cmsghdr *cmsg;
@@ -194,6 +195,22 @@ int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
        for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
                if (!CMSG_OK(msg, cmsg))
                        return -EINVAL;
+#if defined(CONFIG_IPV6)
+               if (allow_ipv6 &&
+                   cmsg->cmsg_level == SOL_IPV6 &&
+                   cmsg->cmsg_type == IPV6_PKTINFO) {
+                       struct in6_pktinfo *src_info;
+
+                       if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info)))
+                               return -EINVAL;
+                       src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+                       if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
+                               return -EINVAL;
+                       ipc->oif = src_info->ipi6_ifindex;
+                       ipc->addr = src_info->ipi6_addr.s6_addr32[3];
+                       continue;
+               }
+#endif
                if (cmsg->cmsg_level != SOL_IP)
                        continue;
                switch (cmsg->cmsg_type) {
@@ -626,7 +643,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                inet->nodefrag = val ? 1 : 0;
                break;
        case IP_MTU_DISCOVER:
-               if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_INTERFACE)
+               if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_OMIT)
                        goto e_inval;
                inet->pmtudisc = val;
                break;
index bd28f386bd02020ef3adc4295a90021d6d43a0f7..e77381d1df9a044ff6a8d01e051b8f885776cf43 100644 (file)
@@ -93,83 +93,32 @@ static void tunnel_dst_reset(struct ip_tunnel *t)
        tunnel_dst_set(t, NULL);
 }
 
-static void tunnel_dst_reset_all(struct ip_tunnel *t)
+void ip_tunnel_dst_reset_all(struct ip_tunnel *t)
 {
        int i;
 
        for_each_possible_cpu(i)
                __tunnel_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
 }
+EXPORT_SYMBOL(ip_tunnel_dst_reset_all);
 
-static struct dst_entry *tunnel_dst_get(struct ip_tunnel *t)
+static struct rtable *tunnel_rtable_get(struct ip_tunnel *t, u32 cookie)
 {
        struct dst_entry *dst;
 
        rcu_read_lock();
        dst = rcu_dereference(this_cpu_ptr(t->dst_cache)->dst);
-       if (dst)
+       if (dst) {
+               if (dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
+                       rcu_read_unlock();
+                       tunnel_dst_reset(t);
+                       return NULL;
+               }
                dst_hold(dst);
-       rcu_read_unlock();
-       return dst;
-}
-
-static struct dst_entry *tunnel_dst_check(struct ip_tunnel *t, u32 cookie)
-{
-       struct dst_entry *dst = tunnel_dst_get(t);
-
-       if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) {
-               tunnel_dst_reset(t);
-               return NULL;
-       }
-
-       return dst;
-}
-
-/* Often modified stats are per cpu, other are shared (netdev->stats) */
-struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
-                                               struct rtnl_link_stats64 *tot)
-{
-       int i;
-
-       for_each_possible_cpu(i) {
-               const struct pcpu_sw_netstats *tstats =
-                                                  per_cpu_ptr(dev->tstats, i);
-               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
-               unsigned int start;
-
-               do {
-                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
-                       rx_packets = tstats->rx_packets;
-                       tx_packets = tstats->tx_packets;
-                       rx_bytes = tstats->rx_bytes;
-                       tx_bytes = tstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
-
-               tot->rx_packets += rx_packets;
-               tot->tx_packets += tx_packets;
-               tot->rx_bytes   += rx_bytes;
-               tot->tx_bytes   += tx_bytes;
        }
-
-       tot->multicast = dev->stats.multicast;
-
-       tot->rx_crc_errors = dev->stats.rx_crc_errors;
-       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
-       tot->rx_length_errors = dev->stats.rx_length_errors;
-       tot->rx_frame_errors = dev->stats.rx_frame_errors;
-       tot->rx_errors = dev->stats.rx_errors;
-
-       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
-       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
-       tot->tx_dropped = dev->stats.tx_dropped;
-       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
-       tot->tx_errors = dev->stats.tx_errors;
-
-       tot->collisions  = dev->stats.collisions;
-
-       return tot;
+       rcu_read_unlock();
+       return (struct rtable *)dst;
 }
-EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
 
 static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p,
                                __be16 flags, __be32 key)
@@ -286,13 +235,17 @@ static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn,
 {
        unsigned int h;
        __be32 remote;
+       __be32 i_key = parms->i_key;
 
        if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr))
                remote = parms->iph.daddr;
        else
                remote = 0;
 
-       h = ip_tunnel_hash(parms->i_key, remote);
+       if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI))
+               i_key = 0;
+
+       h = ip_tunnel_hash(i_key, remote);
        return &itn->tunnels[h];
 }
 
@@ -449,7 +402,7 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
        fbt = netdev_priv(itn->fb_tunnel_dev);
        dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms);
        if (IS_ERR(dev))
-               return NULL;
+               return ERR_CAST(dev);
 
        dev->mtu = ip_tunnel_bind_dev(dev);
 
@@ -467,9 +420,6 @@ int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
 
 #ifdef CONFIG_NET_IPGRE_BROADCAST
        if (ipv4_is_multicast(iph->daddr)) {
-               /* Looped back packet, drop it! */
-               if (rt_is_output_route(skb_rtable(skb)))
-                       goto drop;
                tunnel->dev->stats.multicast++;
                skb->pkt_type = PACKET_BROADCAST;
        }
@@ -584,7 +534,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        struct flowi4 fl4;
        u8     tos, ttl;
        __be16 df;
-       struct rtable *rt = NULL;       /* Route to the other host */
+       struct rtable *rt;              /* Route to the other host */
        unsigned int max_headroom;      /* The extra header space needed */
        __be32 dst;
        int err;
@@ -657,8 +607,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
        init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
                         tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link);
 
-       if (connected)
-               rt = (struct rtable *)tunnel_dst_check(tunnel, 0);
+       rt = connected ? tunnel_rtable_get(tunnel, 0) : NULL;
 
        if (!rt) {
                rt = ip_route_output_key(tunnel->net, &fl4);
@@ -766,7 +715,7 @@ static void ip_tunnel_update(struct ip_tunnel_net *itn,
                if (set_mtu)
                        dev->mtu = mtu;
        }
-       tunnel_dst_reset_all(t);
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(dev);
 }
 
@@ -803,9 +752,13 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
 
                t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type);
 
-               if (!t && (cmd == SIOCADDTUNNEL))
+               if (!t && (cmd == SIOCADDTUNNEL)) {
                        t = ip_tunnel_create(net, itn, p);
-
+                       if (IS_ERR(t)) {
+                               err = PTR_ERR(t);
+                               break;
+                       }
+               }
                if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
                        if (t != NULL) {
                                if (t->dev != dev) {
@@ -832,8 +785,9 @@ int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd)
                if (t) {
                        err = 0;
                        ip_tunnel_update(itn, t, dev, p, true);
-               } else
-                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+               } else {
+                       err = -ENOENT;
+               }
                break;
 
        case SIOCDELTUNNEL:
@@ -1048,19 +1002,13 @@ int ip_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
        struct iphdr *iph = &tunnel->parms.iph;
-       int i, err;
+       int err;
 
        dev->destructor = ip_tunnel_dev_free;
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *ipt_stats;
-               ipt_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&ipt_stats->syncp);
-       }
-
        tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
        if (!tunnel->dst_cache) {
                free_percpu(dev->tstats);
@@ -1095,7 +1043,7 @@ void ip_tunnel_uninit(struct net_device *dev)
        if (itn->fb_tunnel_dev != dev)
                ip_tunnel_del(netdev_priv(dev));
 
-       tunnel_dst_reset_all(tunnel);
+       ip_tunnel_dst_reset_all(tunnel);
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_uninit);
 
index 6156f4ef5e919ccdc470f8cdb5a27593dedbe2c3..e0c2b1d2ea4eb825aa76c15199b366bc600f841a 100644 (file)
@@ -148,3 +148,49 @@ error:
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(iptunnel_handle_offloads);
+
+/* Often modified stats are per cpu, other are shared (netdev->stats) */
+struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev,
+                                               struct rtnl_link_stats64 *tot)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               const struct pcpu_sw_netstats *tstats =
+                                                  per_cpu_ptr(dev->tstats, i);
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+               unsigned int start;
+
+               do {
+                       start = u64_stats_fetch_begin_irq(&tstats->syncp);
+                       rx_packets = tstats->rx_packets;
+                       tx_packets = tstats->tx_packets;
+                       rx_bytes = tstats->rx_bytes;
+                       tx_bytes = tstats->tx_bytes;
+               } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
+
+               tot->rx_packets += rx_packets;
+               tot->tx_packets += tx_packets;
+               tot->rx_bytes   += rx_bytes;
+               tot->tx_bytes   += tx_bytes;
+       }
+
+       tot->multicast = dev->stats.multicast;
+
+       tot->rx_crc_errors = dev->stats.rx_crc_errors;
+       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+       tot->rx_length_errors = dev->stats.rx_length_errors;
+       tot->rx_frame_errors = dev->stats.rx_frame_errors;
+       tot->rx_errors = dev->stats.rx_errors;
+
+       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+       tot->tx_dropped = dev->stats.tx_dropped;
+       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+       tot->tx_errors = dev->stats.tx_errors;
+
+       tot->collisions  = dev->stats.collisions;
+
+       return tot;
+}
+EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64);
index 48eafae5176946841b53b95e7da8a46650fa548d..687ddef4e5747274fc9c248b73d3869ed57fe21f 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/if_ether.h>
+#include <linux/icmpv6.h>
 
 #include <net/sock.h>
 #include <net/ip.h>
@@ -49,8 +50,8 @@ static struct rtnl_link_ops vti_link_ops __read_mostly;
 static int vti_net_id __read_mostly;
 static int vti_tunnel_init(struct net_device *dev);
 
-/* We dont digest the packet therefore let the packet pass */
-static int vti_rcv(struct sk_buff *skb)
+static int vti_input(struct sk_buff *skb, int nexthdr, __be32 spi,
+                    int encap_type)
 {
        struct ip_tunnel *tunnel;
        const struct iphdr *iph = ip_hdr(skb);
@@ -60,79 +61,120 @@ static int vti_rcv(struct sk_buff *skb)
        tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
                                  iph->saddr, iph->daddr, 0);
        if (tunnel != NULL) {
-               struct pcpu_sw_netstats *tstats;
-               u32 oldmark = skb->mark;
-               int ret;
-
-
-               /* temporarily mark the skb with the tunnel o_key, to
-                * only match policies with this mark.
-                */
-               skb->mark = be32_to_cpu(tunnel->parms.o_key);
-               ret = xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb);
-               skb->mark = oldmark;
-               if (!ret)
-                       return -1;
-
-               tstats = this_cpu_ptr(tunnel->dev->tstats);
-               u64_stats_update_begin(&tstats->syncp);
-               tstats->rx_packets++;
-               tstats->rx_bytes += skb->len;
-               u64_stats_update_end(&tstats->syncp);
-
-               secpath_reset(skb);
-               skb->dev = tunnel->dev;
+               if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+                       goto drop;
+
+               XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = tunnel;
+               skb->mark = be32_to_cpu(tunnel->parms.i_key);
+
+               return xfrm_input(skb, nexthdr, spi, encap_type);
+       }
+
+       return -EINVAL;
+drop:
+       kfree_skb(skb);
+       return 0;
+}
+
+static int vti_rcv(struct sk_buff *skb)
+{
+       XFRM_SPI_SKB_CB(skb)->family = AF_INET;
+       XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
+
+       return vti_input(skb, ip_hdr(skb)->protocol, 0, 0);
+}
+
+static int vti_rcv_cb(struct sk_buff *skb, int err)
+{
+       unsigned short family;
+       struct net_device *dev;
+       struct pcpu_sw_netstats *tstats;
+       struct xfrm_state *x;
+       struct ip_tunnel *tunnel = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4;
+
+       if (!tunnel)
                return 1;
+
+       dev = tunnel->dev;
+
+       if (err) {
+               dev->stats.rx_errors++;
+               dev->stats.rx_dropped++;
+
+               return 0;
        }
 
-       return -1;
+       x = xfrm_input_state(skb);
+       family = x->inner_mode->afinfo->family;
+
+       if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
+               return -EPERM;
+
+       skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(skb->dev)));
+       skb->dev = dev;
+
+       tstats = this_cpu_ptr(dev->tstats);
+
+       u64_stats_update_begin(&tstats->syncp);
+       tstats->rx_packets++;
+       tstats->rx_bytes += skb->len;
+       u64_stats_update_end(&tstats->syncp);
+
+       return 0;
 }
 
-/* This function assumes it is being called from dev_queue_xmit()
- * and that skb is filled properly by that function.
- */
+static bool vti_state_check(const struct xfrm_state *x, __be32 dst, __be32 src)
+{
+       xfrm_address_t *daddr = (xfrm_address_t *)&dst;
+       xfrm_address_t *saddr = (xfrm_address_t *)&src;
 
-static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+       /* if there is no transform then this tunnel is not functional.
+        * Or if the xfrm is not mode tunnel.
+        */
+       if (!x || x->props.mode != XFRM_MODE_TUNNEL ||
+           x->props.family != AF_INET)
+               return false;
+
+       if (!dst)
+               return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET);
+
+       if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET))
+               return false;
+
+       return true;
+}
+
+static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
+                           struct flowi *fl)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
-       struct iphdr  *tiph = &tunnel->parms.iph;
-       u8     tos;
-       struct rtable *rt;              /* Route to the other host */
+       struct ip_tunnel_parm *parms = &tunnel->parms;
+       struct dst_entry *dst = skb_dst(skb);
        struct net_device *tdev;        /* Device to other host */
-       struct iphdr  *old_iph = ip_hdr(skb);
-       __be32 dst = tiph->daddr;
-       struct flowi4 fl4;
        int err;
 
-       if (skb->protocol != htons(ETH_P_IP))
-               goto tx_error;
-
-       tos = old_iph->tos;
+       if (!dst) {
+               dev->stats.tx_carrier_errors++;
+               goto tx_error_icmp;
+       }
 
-       memset(&fl4, 0, sizeof(fl4));
-       flowi4_init_output(&fl4, tunnel->parms.link,
-                          be32_to_cpu(tunnel->parms.o_key), RT_TOS(tos),
-                          RT_SCOPE_UNIVERSE,
-                          IPPROTO_IPIP, 0,
-                          dst, tiph->saddr, 0, 0);
-       rt = ip_route_output_key(dev_net(dev), &fl4);
-       if (IS_ERR(rt)) {
+       dst_hold(dst);
+       dst = xfrm_lookup(tunnel->net, dst, fl, NULL, 0);
+       if (IS_ERR(dst)) {
                dev->stats.tx_carrier_errors++;
                goto tx_error_icmp;
        }
-       /* if there is no transform then this tunnel is not functional.
-        * Or if the xfrm is not mode tunnel.
-        */
-       if (!rt->dst.xfrm ||
-           rt->dst.xfrm->props.mode != XFRM_MODE_TUNNEL) {
+
+       if (!vti_state_check(dst->xfrm, parms->iph.daddr, parms->iph.saddr)) {
                dev->stats.tx_carrier_errors++;
-               ip_rt_put(rt);
+               dst_release(dst);
                goto tx_error_icmp;
        }
-       tdev = rt->dst.dev;
+
+       tdev = dst->dev;
 
        if (tdev == dev) {
-               ip_rt_put(rt);
+               dst_release(dst);
                dev->stats.collisions++;
                goto tx_error;
        }
@@ -146,10 +188,8 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                        tunnel->err_count = 0;
        }
 
-       memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-       skb_dst_drop(skb);
-       skb_dst_set(skb, &rt->dst);
-       nf_reset(skb);
+       skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
+       skb_dst_set(skb, dst);
        skb->dev = skb_dst(skb)->dev;
 
        err = dst_output(skb);
@@ -166,6 +206,95 @@ tx_error:
        return NETDEV_TX_OK;
 }
 
+/* This function assumes it is being called from dev_queue_xmit()
+ * and that skb is filled properly by that function.
+ */
+static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+       struct flowi fl;
+
+       memset(&fl, 0, sizeof(fl));
+
+       skb->mark = be32_to_cpu(tunnel->parms.o_key);
+
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+               xfrm_decode_session(skb, &fl, AF_INET);
+               memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+               break;
+       case htons(ETH_P_IPV6):
+               xfrm_decode_session(skb, &fl, AF_INET6);
+               memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+               break;
+       default:
+               dev->stats.tx_errors++;
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       return vti_xmit(skb, dev, &fl);
+}
+
+static int vti4_err(struct sk_buff *skb, u32 info)
+{
+       __be32 spi;
+       struct xfrm_state *x;
+       struct ip_tunnel *tunnel;
+       struct ip_esp_hdr *esph;
+       struct ip_auth_hdr *ah ;
+       struct ip_comp_hdr *ipch;
+       struct net *net = dev_net(skb->dev);
+       const struct iphdr *iph = (const struct iphdr *)skb->data;
+       int protocol = iph->protocol;
+       struct ip_tunnel_net *itn = net_generic(net, vti_net_id);
+
+       tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, TUNNEL_NO_KEY,
+                                 iph->daddr, iph->saddr, 0);
+       if (!tunnel)
+               return -1;
+
+       switch (protocol) {
+       case IPPROTO_ESP:
+               esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
+               spi = esph->spi;
+               break;
+       case IPPROTO_AH:
+               ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2));
+               spi = ah->spi;
+               break;
+       case IPPROTO_COMP:
+               ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
+               spi = htonl(ntohs(ipch->cpi));
+               break;
+       default:
+               return 0;
+       }
+
+       switch (icmp_hdr(skb)->type) {
+       case ICMP_DEST_UNREACH:
+               if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
+                       return 0;
+       case ICMP_REDIRECT:
+               break;
+       default:
+               return 0;
+       }
+
+       x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+                             spi, protocol, AF_INET);
+       if (!x)
+               return 0;
+
+       if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
+               ipv4_update_pmtu(skb, net, info, 0, 0, protocol, 0);
+       else
+               ipv4_redirect(skb, net, 0, 0, protocol, 0);
+       xfrm_state_put(x);
+
+       return 0;
+}
+
 static int
 vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -181,12 +310,13 @@ vti_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        return -EINVAL;
        }
 
+       p.i_flags |= VTI_ISVTI;
        err = ip_tunnel_ioctl(dev, &p, cmd);
        if (err)
                return err;
 
        if (cmd != SIOCDELTUNNEL) {
-               p.i_flags |= GRE_KEY | VTI_ISVTI;
+               p.i_flags |= GRE_KEY;
                p.o_flags |= GRE_KEY;
        }
 
@@ -224,7 +354,6 @@ static int vti_tunnel_init(struct net_device *dev)
        dev->flags              = IFF_NOARP;
        dev->iflink             = 0;
        dev->addr_len           = 4;
-       dev->features           |= NETIF_F_NETNS_LOCAL;
        dev->features           |= NETIF_F_LLTX;
        dev->priv_flags         &= ~IFF_XMIT_DST_RELEASE;
 
@@ -241,9 +370,28 @@ static void __net_init vti_fb_tunnel_init(struct net_device *dev)
        iph->ihl                = 5;
 }
 
-static struct xfrm_tunnel_notifier vti_handler __read_mostly = {
+static struct xfrm4_protocol vti_esp4_protocol __read_mostly = {
        .handler        =       vti_rcv,
-       .priority       =       1,
+       .input_handler  =       vti_input,
+       .cb_handler     =       vti_rcv_cb,
+       .err_handler    =       vti4_err,
+       .priority       =       100,
+};
+
+static struct xfrm4_protocol vti_ah4_protocol __read_mostly = {
+       .handler        =       vti_rcv,
+       .input_handler  =       vti_input,
+       .cb_handler     =       vti_rcv_cb,
+       .err_handler    =       vti4_err,
+       .priority       =       100,
+};
+
+static struct xfrm4_protocol vti_ipcomp4_protocol __read_mostly = {
+       .handler        =       vti_rcv,
+       .input_handler  =       vti_input,
+       .cb_handler     =       vti_rcv_cb,
+       .err_handler    =       vti4_err,
+       .priority       =       100,
 };
 
 static int __net_init vti_init_net(struct net *net)
@@ -287,6 +435,8 @@ static void vti_netlink_parms(struct nlattr *data[],
        if (!data)
                return;
 
+       parms->i_flags = VTI_ISVTI;
+
        if (data[IFLA_VTI_LINK])
                parms->link = nla_get_u32(data[IFLA_VTI_LINK]);
 
@@ -382,10 +532,31 @@ static int __init vti_init(void)
        err = register_pernet_device(&vti_net_ops);
        if (err < 0)
                return err;
-       err = xfrm4_mode_tunnel_input_register(&vti_handler);
+       err = xfrm4_protocol_register(&vti_esp4_protocol, IPPROTO_ESP);
+       if (err < 0) {
+               unregister_pernet_device(&vti_net_ops);
+               pr_info("vti init: can't register tunnel\n");
+
+               return err;
+       }
+
+       err = xfrm4_protocol_register(&vti_ah4_protocol, IPPROTO_AH);
+       if (err < 0) {
+               xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
+               unregister_pernet_device(&vti_net_ops);
+               pr_info("vti init: can't register tunnel\n");
+
+               return err;
+       }
+
+       err = xfrm4_protocol_register(&vti_ipcomp4_protocol, IPPROTO_COMP);
        if (err < 0) {
+               xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
+               xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
                unregister_pernet_device(&vti_net_ops);
                pr_info("vti init: can't register tunnel\n");
+
+               return err;
        }
 
        err = rtnl_link_register(&vti_link_ops);
@@ -395,7 +566,9 @@ static int __init vti_init(void)
        return err;
 
 rtnl_link_failed:
-       xfrm4_mode_tunnel_input_deregister(&vti_handler);
+       xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP);
+       xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH);
+       xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP);
        unregister_pernet_device(&vti_net_ops);
        return err;
 }
@@ -403,8 +576,13 @@ rtnl_link_failed:
 static void __exit vti_fini(void)
 {
        rtnl_link_unregister(&vti_link_ops);
-       if (xfrm4_mode_tunnel_input_deregister(&vti_handler))
+       if (xfrm4_protocol_deregister(&vti_ipcomp4_protocol, IPPROTO_COMP))
                pr_info("vti close: can't deregister tunnel\n");
+       if (xfrm4_protocol_deregister(&vti_ah4_protocol, IPPROTO_AH))
+               pr_info("vti close: can't deregister tunnel\n");
+       if (xfrm4_protocol_deregister(&vti_esp4_protocol, IPPROTO_ESP))
+               pr_info("vti close: can't deregister tunnel\n");
+
 
        unregister_pernet_device(&vti_net_ops);
 }
index 826be4cb482a29b401f2314da6581e1127a7a731..c0855d50a3fa775831ada20254b74d94f5d410ae 100644 (file)
@@ -23,7 +23,7 @@
 #include <net/protocol.h>
 #include <net/sock.h>
 
-static void ipcomp4_err(struct sk_buff *skb, u32 info)
+static int ipcomp4_err(struct sk_buff *skb, u32 info)
 {
        struct net *net = dev_net(skb->dev);
        __be32 spi;
@@ -34,24 +34,26 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
        switch (icmp_hdr(skb)->type) {
        case ICMP_DEST_UNREACH:
                if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
-                       return;
+                       return 0;
        case ICMP_REDIRECT:
                break;
        default:
-               return;
+               return 0;
        }
 
        spi = htonl(ntohs(ipch->cpi));
        x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
                              spi, IPPROTO_COMP, AF_INET);
        if (!x)
-               return;
+               return 0;
 
        if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
                ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
        else
                ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
        xfrm_state_put(x);
+
+       return 0;
 }
 
 /* We always hold one tunnel user reference to indicate a tunnel */
@@ -147,6 +149,11 @@ out:
        return err;
 }
 
+static int ipcomp4_rcv_cb(struct sk_buff *skb, int err)
+{
+       return 0;
+}
+
 static const struct xfrm_type ipcomp_type = {
        .description    = "IPCOMP4",
        .owner          = THIS_MODULE,
@@ -157,11 +164,12 @@ static const struct xfrm_type ipcomp_type = {
        .output         = ipcomp_output
 };
 
-static const struct net_protocol ipcomp4_protocol = {
+static struct xfrm4_protocol ipcomp4_protocol = {
        .handler        =       xfrm4_rcv,
+       .input_handler  =       xfrm_input,
+       .cb_handler     =       ipcomp4_rcv_cb,
        .err_handler    =       ipcomp4_err,
-       .no_policy      =       1,
-       .netns_ok       =       1,
+       .priority       =       0,
 };
 
 static int __init ipcomp4_init(void)
@@ -170,7 +178,7 @@ static int __init ipcomp4_init(void)
                pr_info("%s: can't add xfrm type\n", __func__);
                return -EAGAIN;
        }
-       if (inet_add_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0) {
+       if (xfrm4_protocol_register(&ipcomp4_protocol, IPPROTO_COMP) < 0) {
                pr_info("%s: can't add protocol\n", __func__);
                xfrm_unregister_type(&ipcomp_type, AF_INET);
                return -EAGAIN;
@@ -180,7 +188,7 @@ static int __init ipcomp4_init(void)
 
 static void __exit ipcomp4_fini(void)
 {
-       if (inet_del_protocol(&ipcomp4_protocol, IPPROTO_COMP) < 0)
+       if (xfrm4_protocol_deregister(&ipcomp4_protocol, IPPROTO_COMP) < 0)
                pr_info("%s: can't remove protocol\n", __func__);
        if (xfrm_unregister_type(&ipcomp_type, AF_INET) < 0)
                pr_info("%s: can't remove xfrm type\n", __func__);
index efa1138fa523be1ed228b66accbfa9ed75920265..b3e86ea7b71b7e480ce64d243e3c1951484a7cbb 100644 (file)
@@ -273,7 +273,7 @@ static int __init ic_open_devs(void)
 
                msleep(1);
 
-               if time_before(jiffies, next_msg)
+               if (time_before(jiffies, next_msg))
                        continue;
 
                elapsed = jiffies_to_msecs(jiffies - start);
index b9b3472975ba31a646502dcd8c76046869be4e98..28863570dd60557ca27d8c73c7590b926c7dcf57 100644 (file)
@@ -2255,13 +2255,14 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
 }
 
 static int ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
-                           u32 portid, u32 seq, struct mfc_cache *c, int cmd)
+                           u32 portid, u32 seq, struct mfc_cache *c, int cmd,
+                           int flags)
 {
        struct nlmsghdr *nlh;
        struct rtmsg *rtm;
        int err;
 
-       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -2329,7 +2330,7 @@ static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
        if (skb == NULL)
                goto errout;
 
-       err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
+       err = ipmr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
        if (err < 0)
                goto errout;
 
@@ -2368,7 +2369,8 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
                                if (ipmr_fill_mroute(mrt, skb,
                                                     NETLINK_CB(cb->skb).portid,
                                                     cb->nlh->nlmsg_seq,
-                                                    mfc, RTM_NEWROUTE) < 0)
+                                                    mfc, RTM_NEWROUTE,
+                                                    NLM_F_MULTI) < 0)
                                        goto done;
 next_entry:
                                e++;
@@ -2382,7 +2384,8 @@ next_entry:
                        if (ipmr_fill_mroute(mrt, skb,
                                             NETLINK_CB(cb->skb).portid,
                                             cb->nlh->nlmsg_seq,
-                                            mfc, RTM_NEWROUTE) < 0) {
+                                            mfc, RTM_NEWROUTE,
+                                            NLM_F_MULTI) < 0) {
                                spin_unlock_bh(&mfc_unres_lock);
                                goto done;
                        }
index c3e0adea9c277585f01dff2f1740787bb3d19a66..7ebd6e37875cc95b08d294ff64306925d05e550e 100644 (file)
@@ -61,7 +61,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
                skb_dst_set(skb, NULL);
                dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), skb->sk, 0);
                if (IS_ERR(dst))
-                       return PTR_ERR(dst);;
+                       return PTR_ERR(dst);
                skb_dst_set(skb, dst);
        }
 #endif
index 81c6910cfa925b315c8efda5e3d79af817c82c88..a26ce035e3fad076a1d76fae0c377771300c7a04 100644 (file)
@@ -61,6 +61,11 @@ config NFT_CHAIN_NAT_IPV4
          packet transformations such as the source, destination address and
          source and destination ports.
 
+config NFT_REJECT_IPV4
+       depends on NF_TABLES_IPV4
+       default NFT_REJECT
+       tristate
+
 config NF_TABLES_ARP
        depends on NF_TABLES
        tristate "ARP nf_tables support"
index c16be9d58420dad15b4218ec119b34d184a7ea7e..90b82405331e1736c8bb4f0d4cacfd3c8fd4e783 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
 obj-$(CONFIG_NF_TABLES_IPV4) += nf_tables_ipv4.o
 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV4) += nft_chain_route_ipv4.o
 obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o
+obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
 obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
 
 # generic IP tables 
index 9eea059dd6216225950428819104bfcae77d10ba..574f7ebba0b6238d8e61ffd08dead06a07a619c5 100644 (file)
@@ -229,7 +229,10 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
                        ret = nf_ct_expect_related(rtcp_exp);
                        if (ret == 0)
                                break;
-                       else if (ret != -EBUSY) {
+                       else if (ret == -EBUSY) {
+                               nf_ct_unexpect_related(rtp_exp);
+                               continue;
+                       } else if (ret < 0) {
                                nf_ct_unexpect_related(rtp_exp);
                                nated_port = 0;
                                break;
index d551e31b416e02e728a433293d25317e9c930dcb..7c676671329d9432eb2392f6b4fc649ebcdae97f 100644 (file)
@@ -1198,8 +1198,8 @@ static int snmp_translate(struct nf_conn *ct,
                map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
        } else {
                /* DNAT replies */
-               map.from = NOCT1(&ct->tuplehash[dir].tuple.src.u3.ip);
-               map.to = NOCT1(&ct->tuplehash[!dir].tuple.dst.u3.ip);
+               map.from = NOCT1(&ct->tuplehash[!dir].tuple.src.u3.ip);
+               map.to = NOCT1(&ct->tuplehash[dir].tuple.dst.u3.ip);
        }
 
        if (map.from == map.to)
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c
new file mode 100644 (file)
index 0000000..e79718a
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 Eric Leblond <eric@regit.org>
+ *
+ * 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.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/icmp.h>
+#include <net/netfilter/ipv4/nf_reject.h>
+#include <net/netfilter/nft_reject.h>
+
+void nft_reject_ipv4_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt)
+{
+       struct nft_reject *priv = nft_expr_priv(expr);
+
+       switch (priv->type) {
+       case NFT_REJECT_ICMP_UNREACH:
+               nf_send_unreach(pkt->skb, priv->icmp_code);
+               break;
+       case NFT_REJECT_TCP_RST:
+               nf_send_reset(pkt->skb, pkt->ops->hooknum);
+               break;
+       }
+
+       data[NFT_REG_VERDICT].verdict = NF_DROP;
+}
+EXPORT_SYMBOL_GPL(nft_reject_ipv4_eval);
+
+static struct nft_expr_type nft_reject_ipv4_type;
+static const struct nft_expr_ops nft_reject_ipv4_ops = {
+       .type           = &nft_reject_ipv4_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
+       .eval           = nft_reject_ipv4_eval,
+       .init           = nft_reject_init,
+       .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_ipv4_type __read_mostly = {
+       .family         = NFPROTO_IPV4,
+       .name           = "reject",
+       .ops            = &nft_reject_ipv4_ops,
+       .policy         = nft_reject_policy,
+       .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
+};
+
+static int __init nft_reject_ipv4_module_init(void)
+{
+       return nft_register_expr(&nft_reject_ipv4_type);
+}
+
+static void __exit nft_reject_ipv4_module_exit(void)
+{
+       nft_unregister_expr(&nft_reject_ipv4_type);
+}
+
+module_init(nft_reject_ipv4_module_init);
+module_exit(nft_reject_ipv4_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS_NFT_AF_EXPR(AF_INET, "reject");
index 2d11c094296e77ceb36b4121df01d7e5318de591..f4b19e5dde54c4b2971610db527202a640b40f09 100644 (file)
@@ -727,7 +727,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
        sock_tx_timestamp(sk, &ipc.tx_flags);
 
        if (msg->msg_controllen) {
-               err = ip_cmsg_send(sock_net(sk), msg, &ipc);
+               err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
                if (err)
                        return err;
                if (ipc.opt)
index a6c8a80ec9d67299e39008f18a3adb0dcfae1389..ad737fad6d8b82dec74fab1260015e539647271d 100644 (file)
@@ -273,6 +273,7 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK),
        SNMP_MIB_ITEM("TCPSYNChallenge", LINUX_MIB_TCPSYNCHALLENGE),
        SNMP_MIB_ITEM("TCPFastOpenActive", LINUX_MIB_TCPFASTOPENACTIVE),
+       SNMP_MIB_ITEM("TCPFastOpenActiveFail", LINUX_MIB_TCPFASTOPENACTIVEFAIL),
        SNMP_MIB_ITEM("TCPFastOpenPassive", LINUX_MIB_TCPFASTOPENPASSIVE),
        SNMP_MIB_ITEM("TCPFastOpenPassiveFail", LINUX_MIB_TCPFASTOPENPASSIVEFAIL),
        SNMP_MIB_ITEM("TCPFastOpenListenOverflow", LINUX_MIB_TCPFASTOPENLISTENOVERFLOW),
@@ -280,6 +281,11 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES),
        SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS),
        SNMP_MIB_ITEM("TCPAutoCorking", LINUX_MIB_TCPAUTOCORKING),
+       SNMP_MIB_ITEM("TCPFromZeroWindowAdv", LINUX_MIB_TCPFROMZEROWINDOWADV),
+       SNMP_MIB_ITEM("TCPToZeroWindowAdv", LINUX_MIB_TCPTOZEROWINDOWADV),
+       SNMP_MIB_ITEM("TCPWantZeroWindowAdv", LINUX_MIB_TCPWANTZEROWINDOWADV),
+       SNMP_MIB_ITEM("TCPSynRetrans", LINUX_MIB_TCPSYNRETRANS),
+       SNMP_MIB_ITEM("TCPOrigDataSent", LINUX_MIB_TCPORIGDATASENT),
        SNMP_MIB_SENTINEL
 };
 
index c04518f4850a4c0a3d1de182d75cb2a963c7f583..a9dbe58bdfe767e62642db954b89532dab928a96 100644 (file)
@@ -524,7 +524,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        ipc.oif = sk->sk_bound_dev_if;
 
        if (msg->msg_controllen) {
-               err = ip_cmsg_send(sock_net(sk), msg, &ipc);
+               err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
                if (err)
                        goto out;
                if (ipc.opt)
index 25071b48921cebc4788a1f4b0b5fa118832f5910..1be9e990514da98dbc651f847f5b429d72889da6 100644 (file)
@@ -139,11 +139,6 @@ static void                 ip_do_redirect(struct dst_entry *dst, struct sock *sk,
                                        struct sk_buff *skb);
 static void            ipv4_dst_destroy(struct dst_entry *dst);
 
-static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
-                           int how)
-{
-}
-
 static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old)
 {
        WARN_ON(1);
@@ -162,7 +157,6 @@ static struct dst_ops ipv4_dst_ops = {
        .mtu =                  ipv4_mtu,
        .cow_metrics =          ipv4_cow_metrics,
        .destroy =              ipv4_dst_destroy,
-       .ifdown =               ipv4_dst_ifdown,
        .negative_advice =      ipv4_negative_advice,
        .link_failure =         ipv4_link_failure,
        .update_pmtu =          ip_rt_update_pmtu,
@@ -697,7 +691,6 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
 
 out_unlock:
        spin_unlock_bh(&fnhe_lock);
-       return;
 }
 
 static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4,
@@ -1597,6 +1590,7 @@ static int __mkroute_input(struct sk_buff *skb,
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
+       RT_CACHE_STAT_INC(in_slow_tot);
 
        rth->dst.input = ip_forward;
        rth->dst.output = ip_output;
@@ -1695,10 +1689,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        fl4.daddr = daddr;
        fl4.saddr = saddr;
        err = fib_lookup(net, &fl4, &res);
-       if (err != 0)
+       if (err != 0) {
+               if (!IN_DEV_FORWARD(in_dev))
+                       err = -EHOSTUNREACH;
                goto no_route;
-
-       RT_CACHE_STAT_INC(in_slow_tot);
+       }
 
        if (res.type == RTN_BROADCAST)
                goto brd_input;
@@ -1712,8 +1707,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
                goto local_input;
        }
 
-       if (!IN_DEV_FORWARD(in_dev))
+       if (!IN_DEV_FORWARD(in_dev)) {
+               err = -EHOSTUNREACH;
                goto no_route;
+       }
        if (res.type != RTN_UNICAST)
                goto martian_destination;
 
@@ -1768,6 +1765,7 @@ local_input:
        rth->rt_gateway = 0;
        rth->rt_uses_gateway = 0;
        INIT_LIST_HEAD(&rth->rt_uncached);
+       RT_CACHE_STAT_INC(in_slow_tot);
        if (res.type == RTN_UNREACHABLE) {
                rth->dst.input= ip_error;
                rth->dst.error= -err;
@@ -2470,11 +2468,6 @@ errout_free:
        goto errout;
 }
 
-int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
-{
-       return skb->len;
-}
-
 void ip_rt_multicast_event(struct in_device *in_dev)
 {
        rt_cache_flush(dev_net(in_dev->dev));
index 4475b3bb494d5d126dd844b0159629cd672afbdc..4bd6d52eeffb6c7ddc3e98054a7070826a4c4dcd 100644 (file)
@@ -387,7 +387,7 @@ void tcp_init_sock(struct sock *sk)
        INIT_LIST_HEAD(&tp->tsq_node);
 
        icsk->icsk_rto = TCP_TIMEOUT_INIT;
-       tp->mdev = TCP_TIMEOUT_INIT;
+       tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT);
 
        /* So many TCP implementations out there (incorrectly) count the
         * initial SYN frame in their delayed-ACK and congestion control
@@ -1044,7 +1044,8 @@ void tcp_free_fastopen_req(struct tcp_sock *tp)
        }
 }
 
-static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
+static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
+                               int *copied, size_t size)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int err, flags;
@@ -1059,11 +1060,12 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *size)
        if (unlikely(tp->fastopen_req == NULL))
                return -ENOBUFS;
        tp->fastopen_req->data = msg;
+       tp->fastopen_req->size = size;
 
        flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
        err = __inet_stream_connect(sk->sk_socket, msg->msg_name,
                                    msg->msg_namelen, flags);
-       *size = tp->fastopen_req->copied;
+       *copied = tp->fastopen_req->copied;
        tcp_free_fastopen_req(tp);
        return err;
 }
@@ -1083,7 +1085,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        flags = msg->msg_flags;
        if (flags & MSG_FASTOPEN) {
-               err = tcp_sendmsg_fastopen(sk, msg, &copied_syn);
+               err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
                if (err == -EINPROGRESS && copied_syn > 0)
                        goto out;
                else if (err)
@@ -2229,7 +2231,7 @@ adjudge_to_death:
        /*      This is a (useful) BSD violating of the RFC. There is a
         *      problem with TCP as specified in that the other end could
         *      keep a socket open forever with no application left this end.
-        *      We use a 3 minute timeout (about the same as BSD) then kill
+        *      We use a 1 minute timeout (about the same as BSD) then kill
         *      our end. If they send after that then tough - BUT: long enough
         *      that we won't make the old 4*rto = almost no time - whoops
         *      reset mistake.
@@ -2339,7 +2341,7 @@ int tcp_disconnect(struct sock *sk, int flags)
 
        sk->sk_shutdown = 0;
        sock_reset_flag(sk, SOCK_DONE);
-       tp->srtt = 0;
+       tp->srtt_us = 0;
        if ((tp->write_seq += tp->max_window + 2) == 0)
                tp->write_seq = 1;
        icsk->icsk_backoff = 0;
@@ -2783,8 +2785,8 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info)
 
        info->tcpi_pmtu = icsk->icsk_pmtu_cookie;
        info->tcpi_rcv_ssthresh = tp->rcv_ssthresh;
-       info->tcpi_rtt = jiffies_to_usecs(tp->srtt)>>3;
-       info->tcpi_rttvar = jiffies_to_usecs(tp->mdev)>>2;
+       info->tcpi_rtt = tp->srtt_us >> 3;
+       info->tcpi_rttvar = tp->mdev_us >> 2;
        info->tcpi_snd_ssthresh = tp->snd_ssthresh;
        info->tcpi_snd_cwnd = tp->snd_cwnd;
        info->tcpi_advmss = tp->advmss;
@@ -2794,6 +2796,11 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info)
        info->tcpi_rcv_space = tp->rcvq_space.space;
 
        info->tcpi_total_retrans = tp->total_retrans;
+
+       info->tcpi_pacing_rate = sk->sk_pacing_rate != ~0U ?
+                                       sk->sk_pacing_rate : ~0ULL;
+       info->tcpi_max_pacing_rate = sk->sk_max_pacing_rate != ~0U ?
+                                       sk->sk_max_pacing_rate : ~0ULL;
 }
 EXPORT_SYMBOL_GPL(tcp_get_info);
 
index ad37bf18ae4b95a6870a8019ecc3ca9ff55d7679..2b9464c93b8859fcbef0f900f70a4bed2dc6e617 100644 (file)
@@ -290,8 +290,7 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
        left = tp->snd_cwnd - in_flight;
        if (sk_can_gso(sk) &&
            left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
-           left * tp->mss_cache < sk->sk_gso_max_size &&
-           left < sk->sk_gso_max_segs)
+           left < tp->xmit_size_goal_segs)
                return true;
        return left <= tcp_max_tso_deferred_mss(tp);
 }
@@ -362,21 +361,12 @@ u32 tcp_reno_ssthresh(struct sock *sk)
 }
 EXPORT_SYMBOL_GPL(tcp_reno_ssthresh);
 
-/* Lower bound on congestion window with halving. */
-u32 tcp_reno_min_cwnd(const struct sock *sk)
-{
-       const struct tcp_sock *tp = tcp_sk(sk);
-       return tp->snd_ssthresh/2;
-}
-EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
-
 struct tcp_congestion_ops tcp_reno = {
        .flags          = TCP_CONG_NON_RESTRICTED,
        .name           = "reno",
        .owner          = THIS_MODULE,
        .ssthresh       = tcp_reno_ssthresh,
        .cong_avoid     = tcp_reno_cong_avoid,
-       .min_cwnd       = tcp_reno_min_cwnd,
 };
 
 /* Initial congestion control used (until SYN)
@@ -388,6 +378,5 @@ struct tcp_congestion_ops tcp_init_congestion_ops  = {
        .owner          = THIS_MODULE,
        .ssthresh       = tcp_reno_ssthresh,
        .cong_avoid     = tcp_reno_cong_avoid,
-       .min_cwnd       = tcp_reno_min_cwnd,
 };
 EXPORT_SYMBOL_GPL(tcp_init_congestion_ops);
index 828e4c3ffbaf2d724086a0d408781dd99056a5bf..8bf224516ba2a26a661d16f89aaee32301d09397 100644 (file)
@@ -476,10 +476,6 @@ static int __init cubictcp_register(void)
        /* divide by bic_scale and by constant Srtt (100ms) */
        do_div(cube_factor, bic_scale * 10);
 
-       /* hystart needs ms clock resolution */
-       if (hystart && HZ < 1000)
-               cubictcp.flags |= TCP_CONG_RTT_STAMP;
-
        return tcp_register_congestion_control(&cubictcp);
 }
 
index 8ed9305dfdf4f63dc06e951be32a9c5e0b023d1e..8b9e7bad77c09a0c07706b955c29b81d4e71a542 100644 (file)
@@ -162,7 +162,6 @@ static struct tcp_congestion_ops tcp_highspeed __read_mostly = {
        .init           = hstcp_init,
        .ssthresh       = hstcp_ssthresh,
        .cong_avoid     = hstcp_cong_avoid,
-       .min_cwnd       = tcp_reno_min_cwnd,
 
        .owner          = THIS_MODULE,
        .name           = "highspeed"
index 478fe82611bff24459349cb14fd1ce6d8a9f26ac..a15a799bf76888f3633b27cf57e8e05f30339601 100644 (file)
@@ -21,7 +21,7 @@ struct hybla {
        u32   rho2;           /* Rho * Rho, integer part */
        u32   rho_3ls;        /* Rho parameter, <<3 */
        u32   rho2_7ls;       /* Rho^2, <<7     */
-       u32   minrtt;         /* Minimum smoothed round trip time value seen */
+       u32   minrtt_us;      /* Minimum smoothed round trip time value seen */
 };
 
 /* Hybla reference round trip time (default= 1/40 sec = 25 ms), in ms */
@@ -35,7 +35,9 @@ static inline void hybla_recalc_param (struct sock *sk)
 {
        struct hybla *ca = inet_csk_ca(sk);
 
-       ca->rho_3ls = max_t(u32, tcp_sk(sk)->srtt / msecs_to_jiffies(rtt0), 8);
+       ca->rho_3ls = max_t(u32,
+                           tcp_sk(sk)->srtt_us / (rtt0 * USEC_PER_MSEC),
+                           8U);
        ca->rho = ca->rho_3ls >> 3;
        ca->rho2_7ls = (ca->rho_3ls * ca->rho_3ls) << 1;
        ca->rho2 = ca->rho2_7ls >> 7;
@@ -59,7 +61,7 @@ static void hybla_init(struct sock *sk)
        hybla_recalc_param(sk);
 
        /* set minimum rtt as this is the 1st ever seen */
-       ca->minrtt = tp->srtt;
+       ca->minrtt_us = tp->srtt_us;
        tp->snd_cwnd = ca->rho;
 }
 
@@ -94,9 +96,9 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked,
        int is_slowstart = 0;
 
        /*  Recalculate rho only if this srtt is the lowest */
-       if (tp->srtt < ca->minrtt){
+       if (tp->srtt_us < ca->minrtt_us) {
                hybla_recalc_param(sk);
-               ca->minrtt = tp->srtt;
+               ca->minrtt_us = tp->srtt_us;
        }
 
        if (!tcp_is_cwnd_limited(sk, in_flight))
@@ -166,7 +168,6 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked,
 static struct tcp_congestion_ops tcp_hybla __read_mostly = {
        .init           = hybla_init,
        .ssthresh       = tcp_reno_ssthresh,
-       .min_cwnd       = tcp_reno_min_cwnd,
        .cong_avoid     = hybla_cong_avoid,
        .set_state      = hybla_state,
 
index e498a62b8f972d29126f24569c2dbc85037b80a7..863d105e30150391e9ac3ce8545c0411e4d083ab 100644 (file)
@@ -325,10 +325,8 @@ static void tcp_illinois_info(struct sock *sk, u32 ext,
 }
 
 static struct tcp_congestion_ops tcp_illinois __read_mostly = {
-       .flags          = TCP_CONG_RTT_STAMP,
        .init           = tcp_illinois_init,
        .ssthresh       = tcp_illinois_ssthresh,
-       .min_cwnd       = tcp_reno_min_cwnd,
        .cong_avoid     = tcp_illinois_cong_avoid,
        .set_state      = tcp_illinois_state,
        .get_info       = tcp_illinois_info,
index 65cf90e063d5adcc98f15b044e35b20e1668352a..e1661f46fd19fb588555e9f769b9eed2c02fd27d 100644 (file)
@@ -667,10 +667,11 @@ static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb)
  * To save cycles in the RFC 1323 implementation it was better to break
  * it up into three procedures. -- erics
  */
-static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
+static void tcp_rtt_estimator(struct sock *sk, long mrtt_us)
 {
        struct tcp_sock *tp = tcp_sk(sk);
-       long m = mrtt; /* RTT */
+       long m = mrtt_us; /* RTT */
+       u32 srtt = tp->srtt_us;
 
        /*      The following amusing code comes from Jacobson's
         *      article in SIGCOMM '88.  Note that rtt and mdev
@@ -688,14 +689,12 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
         * does not matter how to _calculate_ it. Seems, it was trap
         * that VJ failed to avoid. 8)
         */
-       if (m == 0)
-               m = 1;
-       if (tp->srtt != 0) {
-               m -= (tp->srtt >> 3);   /* m is now error in rtt est */
-               tp->srtt += m;          /* rtt = 7/8 rtt + 1/8 new */
+       if (srtt != 0) {
+               m -= (srtt >> 3);       /* m is now error in rtt est */
+               srtt += m;              /* rtt = 7/8 rtt + 1/8 new */
                if (m < 0) {
                        m = -m;         /* m is now abs(error) */
-                       m -= (tp->mdev >> 2);   /* similar update on mdev */
+                       m -= (tp->mdev_us >> 2);   /* similar update on mdev */
                        /* This is similar to one of Eifel findings.
                         * Eifel blocks mdev updates when rtt decreases.
                         * This solution is a bit different: we use finer gain
@@ -707,27 +706,29 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
                        if (m > 0)
                                m >>= 3;
                } else {
-                       m -= (tp->mdev >> 2);   /* similar update on mdev */
+                       m -= (tp->mdev_us >> 2);   /* similar update on mdev */
                }
-               tp->mdev += m;          /* mdev = 3/4 mdev + 1/4 new */
-               if (tp->mdev > tp->mdev_max) {
-                       tp->mdev_max = tp->mdev;
-                       if (tp->mdev_max > tp->rttvar)
-                               tp->rttvar = tp->mdev_max;
+               tp->mdev_us += m;               /* mdev = 3/4 mdev + 1/4 new */
+               if (tp->mdev_us > tp->mdev_max_us) {
+                       tp->mdev_max_us = tp->mdev_us;
+                       if (tp->mdev_max_us > tp->rttvar_us)
+                               tp->rttvar_us = tp->mdev_max_us;
                }
                if (after(tp->snd_una, tp->rtt_seq)) {
-                       if (tp->mdev_max < tp->rttvar)
-                               tp->rttvar -= (tp->rttvar - tp->mdev_max) >> 2;
+                       if (tp->mdev_max_us < tp->rttvar_us)
+                               tp->rttvar_us -= (tp->rttvar_us - tp->mdev_max_us) >> 2;
                        tp->rtt_seq = tp->snd_nxt;
-                       tp->mdev_max = tcp_rto_min(sk);
+                       tp->mdev_max_us = tcp_rto_min_us(sk);
                }
        } else {
                /* no previous measure. */
-               tp->srtt = m << 3;      /* take the measured time to be rtt */
-               tp->mdev = m << 1;      /* make sure rto = 3*rtt */
-               tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
+               srtt = m << 3;          /* take the measured time to be rtt */
+               tp->mdev_us = m << 1;   /* make sure rto = 3*rtt */
+               tp->rttvar_us = max(tp->mdev_us, tcp_rto_min_us(sk));
+               tp->mdev_max_us = tp->rttvar_us;
                tp->rtt_seq = tp->snd_nxt;
        }
+       tp->srtt_us = max(1U, srtt);
 }
 
 /* Set the sk_pacing_rate to allow proper sizing of TSO packets.
@@ -742,18 +743,12 @@ static void tcp_update_pacing_rate(struct sock *sk)
        u64 rate;
 
        /* set sk_pacing_rate to 200 % of current rate (mss * cwnd / srtt) */
-       rate = (u64)tp->mss_cache * 2 * (HZ << 3);
+       rate = (u64)tp->mss_cache * 2 * (USEC_PER_SEC << 3);
 
        rate *= max(tp->snd_cwnd, tp->packets_out);
 
-       /* Correction for small srtt : minimum srtt being 8 (1 jiffy << 3),
-        * be conservative and assume srtt = 1 (125 us instead of 1.25 ms)
-        * We probably need usec resolution in the future.
-        * Note: This also takes care of possible srtt=0 case,
-        * when tcp_rtt_estimator() was not yet called.
-        */
-       if (tp->srtt > 8 + 2)
-               do_div(rate, tp->srtt);
+       if (likely(tp->srtt_us))
+               do_div(rate, tp->srtt_us);
 
        /* ACCESS_ONCE() is needed because sch_fq fetches sk_pacing_rate
         * without any lock. We want to make sure compiler wont store
@@ -1120,10 +1115,10 @@ static bool tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb,
 }
 
 struct tcp_sacktag_state {
-       int reord;
-       int fack_count;
-       int flag;
-       s32 rtt; /* RTT measured by SACKing never-retransmitted data */
+       int     reord;
+       int     fack_count;
+       long    rtt_us; /* RTT measured by SACKing never-retransmitted data */
+       int     flag;
 };
 
 /* Check if skb is fully within the SACK block. In presence of GSO skbs,
@@ -1184,7 +1179,8 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
 static u8 tcp_sacktag_one(struct sock *sk,
                          struct tcp_sacktag_state *state, u8 sacked,
                          u32 start_seq, u32 end_seq,
-                         int dup_sack, int pcount, u32 xmit_time)
+                         int dup_sack, int pcount,
+                         const struct skb_mstamp *xmit_time)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        int fack_count = state->fack_count;
@@ -1225,8 +1221,13 @@ static u8 tcp_sacktag_one(struct sock *sk,
                                if (!after(end_seq, tp->high_seq))
                                        state->flag |= FLAG_ORIG_SACK_ACKED;
                                /* Pick the earliest sequence sacked for RTT */
-                               if (state->rtt < 0)
-                                       state->rtt = tcp_time_stamp - xmit_time;
+                               if (state->rtt_us < 0) {
+                                       struct skb_mstamp now;
+
+                                       skb_mstamp_get(&now);
+                                       state->rtt_us = skb_mstamp_us_delta(&now,
+                                                               xmit_time);
+                               }
                        }
 
                        if (sacked & TCPCB_LOST) {
@@ -1285,7 +1286,7 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
         */
        tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked,
                        start_seq, end_seq, dup_sack, pcount,
-                       TCP_SKB_CB(skb)->when);
+                       &skb->skb_mstamp);
 
        if (skb == tp->lost_skb_hint)
                tp->lost_cnt_hint += pcount;
@@ -1563,7 +1564,7 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk,
                                                TCP_SKB_CB(skb)->end_seq,
                                                dup_sack,
                                                tcp_skb_pcount(skb),
-                                               TCP_SKB_CB(skb)->when);
+                                               &skb->skb_mstamp);
 
                        if (!before(TCP_SKB_CB(skb)->seq,
                                    tcp_highest_sack_seq(tp)))
@@ -1620,7 +1621,7 @@ static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_bl
 
 static int
 tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
-                       u32 prior_snd_una, s32 *sack_rtt)
+                       u32 prior_snd_una, long *sack_rtt_us)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        const unsigned char *ptr = (skb_transport_header(ack_skb) +
@@ -1638,7 +1639,7 @@ tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb,
 
        state.flag = 0;
        state.reord = tp->packets_out;
-       state.rtt = -1;
+       state.rtt_us = -1L;
 
        if (!tp->sacked_out) {
                if (WARN_ON(tp->fackets_out))
@@ -1822,7 +1823,7 @@ out:
        WARN_ON((int)tp->retrans_out < 0);
        WARN_ON((int)tcp_packets_in_flight(tp) < 0);
 #endif
-       *sack_rtt = state.rtt;
+       *sack_rtt_us = state.rtt_us;
        return state.flag;
 }
 
@@ -1943,8 +1944,9 @@ void tcp_enter_loss(struct sock *sk, int how)
                if (skb == tcp_send_head(sk))
                        break;
 
-               if (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS)
+               if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
                        tp->undo_marker = 0;
+
                TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED;
                if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED) || how) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED;
@@ -2032,10 +2034,12 @@ static bool tcp_pause_early_retransmit(struct sock *sk, int flag)
         * available, or RTO is scheduled to fire first.
         */
        if (sysctl_tcp_early_retrans < 2 || sysctl_tcp_early_retrans > 3 ||
-           (flag & FLAG_ECE) || !tp->srtt)
+           (flag & FLAG_ECE) || !tp->srtt_us)
                return false;
 
-       delay = max_t(unsigned long, (tp->srtt >> 5), msecs_to_jiffies(2));
+       delay = max(usecs_to_jiffies(tp->srtt_us >> 5),
+                   msecs_to_jiffies(2));
+
        if (!time_after(inet_csk(sk)->icsk_timeout, (jiffies + delay)))
                return false;
 
@@ -2882,7 +2886,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked,
 }
 
 static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag,
-                                     s32 seq_rtt, s32 sack_rtt)
+                                     long seq_rtt_us, long sack_rtt_us)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
 
@@ -2892,10 +2896,10 @@ static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag,
         * is acked (RFC6298).
         */
        if (flag & FLAG_RETRANS_DATA_ACKED)
-               seq_rtt = -1;
+               seq_rtt_us = -1L;
 
-       if (seq_rtt < 0)
-               seq_rtt = sack_rtt;
+       if (seq_rtt_us < 0)
+               seq_rtt_us = sack_rtt_us;
 
        /* RTTM Rule: A TSecr value received in a segment is used to
         * update the averaged RTT measurement only if the segment
@@ -2903,14 +2907,14 @@ static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag,
         * left edge of the send window.
         * See draft-ietf-tcplw-high-performance-00, section 3.3.
         */
-       if (seq_rtt < 0 && tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
+       if (seq_rtt_us < 0 && tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
            flag & FLAG_ACKED)
-               seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
+               seq_rtt_us = jiffies_to_usecs(tcp_time_stamp - tp->rx_opt.rcv_tsecr);
 
-       if (seq_rtt < 0)
+       if (seq_rtt_us < 0)
                return false;
 
-       tcp_rtt_estimator(sk, seq_rtt);
+       tcp_rtt_estimator(sk, seq_rtt_us);
        tcp_set_rto(sk);
 
        /* RFC6298: only reset backoff on valid RTT measurement. */
@@ -2922,16 +2926,16 @@ static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag,
 static void tcp_synack_rtt_meas(struct sock *sk, const u32 synack_stamp)
 {
        struct tcp_sock *tp = tcp_sk(sk);
-       s32 seq_rtt = -1;
+       long seq_rtt_us = -1L;
 
        if (synack_stamp && !tp->total_retrans)
-               seq_rtt = tcp_time_stamp - synack_stamp;
+               seq_rtt_us = jiffies_to_usecs(tcp_time_stamp - synack_stamp);
 
        /* If the ACK acks both the SYNACK and the (Fast Open'd) data packets
         * sent in SYN_RECV, SYNACK RTT is the smooth RTT computed in tcp_ack()
         */
-       if (!tp->srtt)
-               tcp_ack_update_rtt(sk, FLAG_SYN_ACKED, seq_rtt, -1);
+       if (!tp->srtt_us)
+               tcp_ack_update_rtt(sk, FLAG_SYN_ACKED, seq_rtt_us, -1L);
 }
 
 static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 acked, u32 in_flight)
@@ -3020,26 +3024,27 @@ static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb)
  * arrived at the other end.
  */
 static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
-                              u32 prior_snd_una, s32 sack_rtt)
+                              u32 prior_snd_una, long sack_rtt_us)
 {
-       struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
-       struct sk_buff *skb;
-       u32 now = tcp_time_stamp;
+       struct skb_mstamp first_ackt, last_ackt, now;
+       struct tcp_sock *tp = tcp_sk(sk);
+       u32 prior_sacked = tp->sacked_out;
+       u32 reord = tp->packets_out;
        bool fully_acked = true;
-       int flag = 0;
+       long ca_seq_rtt_us = -1L;
+       long seq_rtt_us = -1L;
+       struct sk_buff *skb;
        u32 pkts_acked = 0;
-       u32 reord = tp->packets_out;
-       u32 prior_sacked = tp->sacked_out;
-       s32 seq_rtt = -1;
-       s32 ca_seq_rtt = -1;
-       ktime_t last_ackt = net_invalid_timestamp();
        bool rtt_update;
+       int flag = 0;
+
+       first_ackt.v64 = 0;
 
        while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) {
                struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
-               u32 acked_pcount;
                u8 sacked = scb->sacked;
+               u32 acked_pcount;
 
                /* Determine how many packets and what bytes were acked, tso and else */
                if (after(scb->end_seq, tp->snd_una)) {
@@ -3061,11 +3066,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                                tp->retrans_out -= acked_pcount;
                        flag |= FLAG_RETRANS_DATA_ACKED;
                } else {
-                       ca_seq_rtt = now - scb->when;
-                       last_ackt = skb->tstamp;
-                       if (seq_rtt < 0) {
-                               seq_rtt = ca_seq_rtt;
-                       }
+                       last_ackt = skb->skb_mstamp;
+                       WARN_ON_ONCE(last_ackt.v64 == 0);
+                       if (!first_ackt.v64)
+                               first_ackt = last_ackt;
+
                        if (!(sacked & TCPCB_SACKED_ACKED))
                                reord = min(pkts_acked, reord);
                        if (!after(scb->end_seq, tp->high_seq))
@@ -3111,7 +3116,13 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
        if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))
                flag |= FLAG_SACK_RENEGING;
 
-       rtt_update = tcp_ack_update_rtt(sk, flag, seq_rtt, sack_rtt);
+       skb_mstamp_get(&now);
+       if (first_ackt.v64) {
+               seq_rtt_us = skb_mstamp_us_delta(&now, &first_ackt);
+               ca_seq_rtt_us = skb_mstamp_us_delta(&now, &last_ackt);
+       }
+
+       rtt_update = tcp_ack_update_rtt(sk, flag, seq_rtt_us, sack_rtt_us);
 
        if (flag & FLAG_ACKED) {
                const struct tcp_congestion_ops *ca_ops
@@ -3139,25 +3150,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 
                tp->fackets_out -= min(pkts_acked, tp->fackets_out);
 
-               if (ca_ops->pkts_acked) {
-                       s32 rtt_us = -1;
-
-                       /* Is the ACK triggering packet unambiguous? */
-                       if (!(flag & FLAG_RETRANS_DATA_ACKED)) {
-                               /* High resolution needed and available? */
-                               if (ca_ops->flags & TCP_CONG_RTT_STAMP &&
-                                   !ktime_equal(last_ackt,
-                                                net_invalid_timestamp()))
-                                       rtt_us = ktime_us_delta(ktime_get_real(),
-                                                               last_ackt);
-                               else if (ca_seq_rtt >= 0)
-                                       rtt_us = jiffies_to_usecs(ca_seq_rtt);
-                       }
+               if (ca_ops->pkts_acked)
+                       ca_ops->pkts_acked(sk, pkts_acked, ca_seq_rtt_us);
 
-                       ca_ops->pkts_acked(sk, pkts_acked, rtt_us);
-               }
-       } else if (skb && rtt_update && sack_rtt >= 0 &&
-                  sack_rtt > (s32)(now - TCP_SKB_CB(skb)->when)) {
+       } else if (skb && rtt_update && sack_rtt_us >= 0 &&
+                  sack_rtt_us > skb_mstamp_us_delta(&now, &skb->skb_mstamp)) {
                /* Do not re-arm RTO if the sack RTT is measured from data sent
                 * after when the head was last (re)transmitted. Otherwise the
                 * timeout may continue to extend in loss recovery.
@@ -3367,12 +3364,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
        u32 ack_seq = TCP_SKB_CB(skb)->seq;
        u32 ack = TCP_SKB_CB(skb)->ack_seq;
        bool is_dupack = false;
-       u32 prior_in_flight, prior_cwnd = tp->snd_cwnd, prior_rtt = tp->srtt;
+       u32 prior_in_flight;
        u32 prior_fackets;
        int prior_packets = tp->packets_out;
        const int prior_unsacked = tp->packets_out - tp->sacked_out;
        int acked = 0; /* Number of packets newly acked */
-       s32 sack_rtt = -1;
+       long sack_rtt_us = -1L;
 
        /* If the ack is older than previous acks
         * then we can probably ignore it.
@@ -3430,7 +3427,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
                if (TCP_SKB_CB(skb)->sacked)
                        flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
-                                                       &sack_rtt);
+                                                       &sack_rtt_us);
 
                if (TCP_ECN_rcv_ecn_echo(tp, tcp_hdr(skb)))
                        flag |= FLAG_ECE;
@@ -3449,7 +3446,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
        /* See if we can take anything off of the retransmit queue. */
        acked = tp->packets_out;
-       flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, sack_rtt);
+       flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una,
+                                   sack_rtt_us);
        acked -= tp->packets_out;
 
        /* Advance cwnd if state allows */
@@ -3472,8 +3470,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
 
        if (icsk->icsk_pending == ICSK_TIME_RETRANS)
                tcp_schedule_loss_probe(sk);
-       if (tp->srtt != prior_rtt || tp->snd_cwnd != prior_cwnd)
-               tcp_update_pacing_rate(sk);
+       tcp_update_pacing_rate(sk);
        return 1;
 
 no_queue:
@@ -3502,7 +3499,7 @@ old_ack:
         */
        if (TCP_SKB_CB(skb)->sacked) {
                flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una,
-                                               &sack_rtt);
+                                               &sack_rtt_us);
                tcp_fastretrans_alert(sk, acked, prior_unsacked,
                                      is_dupack, flag);
        }
@@ -5398,9 +5395,12 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
                                break;
                }
                tcp_rearm_rto(sk);
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVEFAIL);
                return true;
        }
        tp->syn_data_acked = tp->syn_data;
+       if (tp->syn_data_acked)
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE);
        return false;
 }
 
index 3cf9765104978cbf8ed49d184f926f23130cd4fd..6379894ec210c0f3077366a539417385671c5faa 100644 (file)
@@ -435,7 +435,7 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                        break;
 
                icsk->icsk_backoff--;
-               inet_csk(sk)->icsk_rto = (tp->srtt ? __tcp_set_rto(tp) :
+               inet_csk(sk)->icsk_rto = (tp->srtt_us ? __tcp_set_rto(tp) :
                        TCP_TIMEOUT_INIT) << icsk->icsk_backoff;
                tcp_bound_rto(sk);
 
@@ -854,8 +854,10 @@ static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req)
 {
        int res = tcp_v4_send_synack(sk, NULL, req, 0);
 
-       if (!res)
+       if (!res) {
                TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
+       }
        return res;
 }
 
@@ -878,8 +880,6 @@ bool tcp_syn_flood_action(struct sock *sk,
        bool want_cookie = false;
        struct listen_sock *lopt;
 
-
-
 #ifdef CONFIG_SYN_COOKIES
        if (sysctl_tcp_syncookies) {
                msg = "Sending cookies";
@@ -2628,7 +2628,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 {
        __be32 dest, src;
        __u16 destp, srcp;
-       long delta = tw->tw_ttd - jiffies;
+       s32 delta = tw->tw_ttd - inet_tw_time_stamp();
 
        dest  = tw->tw_daddr;
        src   = tw->tw_rcv_saddr;
index 991d62a2f9bb3abb1d155d075c202c1ea558ca7f..c9aecae313276d134ef56d1385ac44266c200a51 100644 (file)
@@ -315,11 +315,9 @@ static void tcp_lp_pkts_acked(struct sock *sk, u32 num_acked, s32 rtt_us)
 }
 
 static struct tcp_congestion_ops tcp_lp __read_mostly = {
-       .flags = TCP_CONG_RTT_STAMP,
        .init = tcp_lp_init,
        .ssthresh = tcp_reno_ssthresh,
        .cong_avoid = tcp_lp_cong_avoid,
-       .min_cwnd = tcp_reno_min_cwnd,
        .pkts_acked = tcp_lp_pkts_acked,
 
        .owner = THIS_MODULE,
index d547075d830014d5932fbc98741f8c77b4c1e590..dcaf72f10216c22f00ef918963d260d4ce472b99 100644 (file)
@@ -33,6 +33,11 @@ struct tcp_fastopen_metrics {
        struct  tcp_fastopen_cookie     cookie;
 };
 
+/* TCP_METRIC_MAX includes 2 extra fields for userspace compatibility
+ * Kernel only stores RTT and RTTVAR in usec resolution
+ */
+#define TCP_METRIC_MAX_KERNEL (TCP_METRIC_MAX - 2)
+
 struct tcp_metrics_block {
        struct tcp_metrics_block __rcu  *tcpm_next;
        struct inetpeer_addr            tcpm_saddr;
@@ -41,7 +46,7 @@ struct tcp_metrics_block {
        u32                             tcpm_ts;
        u32                             tcpm_ts_stamp;
        u32                             tcpm_lock;
-       u32                             tcpm_vals[TCP_METRIC_MAX + 1];
+       u32                             tcpm_vals[TCP_METRIC_MAX_KERNEL + 1];
        struct tcp_fastopen_metrics     tcpm_fastopen;
 
        struct rcu_head                 rcu_head;
@@ -59,12 +64,6 @@ static u32 tcp_metric_get(struct tcp_metrics_block *tm,
        return tm->tcpm_vals[idx];
 }
 
-static u32 tcp_metric_get_jiffies(struct tcp_metrics_block *tm,
-                                 enum tcp_metric_index idx)
-{
-       return msecs_to_jiffies(tm->tcpm_vals[idx]);
-}
-
 static void tcp_metric_set(struct tcp_metrics_block *tm,
                           enum tcp_metric_index idx,
                           u32 val)
@@ -72,13 +71,6 @@ static void tcp_metric_set(struct tcp_metrics_block *tm,
        tm->tcpm_vals[idx] = val;
 }
 
-static void tcp_metric_set_msecs(struct tcp_metrics_block *tm,
-                                enum tcp_metric_index idx,
-                                u32 val)
-{
-       tm->tcpm_vals[idx] = jiffies_to_msecs(val);
-}
-
 static bool addr_same(const struct inetpeer_addr *a,
                      const struct inetpeer_addr *b)
 {
@@ -101,9 +93,11 @@ struct tcpm_hash_bucket {
 
 static DEFINE_SPINLOCK(tcp_metrics_lock);
 
-static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst,
+static void tcpm_suck_dst(struct tcp_metrics_block *tm,
+                         const struct dst_entry *dst,
                          bool fastopen_clear)
 {
+       u32 msval;
        u32 val;
 
        tm->tcpm_stamp = jiffies;
@@ -121,8 +115,11 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst,
                val |= 1 << TCP_METRIC_REORDERING;
        tm->tcpm_lock = val;
 
-       tm->tcpm_vals[TCP_METRIC_RTT] = dst_metric_raw(dst, RTAX_RTT);
-       tm->tcpm_vals[TCP_METRIC_RTTVAR] = dst_metric_raw(dst, RTAX_RTTVAR);
+       msval = dst_metric_raw(dst, RTAX_RTT);
+       tm->tcpm_vals[TCP_METRIC_RTT] = msval * USEC_PER_MSEC;
+
+       msval = dst_metric_raw(dst, RTAX_RTTVAR);
+       tm->tcpm_vals[TCP_METRIC_RTTVAR] = msval * USEC_PER_MSEC;
        tm->tcpm_vals[TCP_METRIC_SSTHRESH] = dst_metric_raw(dst, RTAX_SSTHRESH);
        tm->tcpm_vals[TCP_METRIC_CWND] = dst_metric_raw(dst, RTAX_CWND);
        tm->tcpm_vals[TCP_METRIC_REORDERING] = dst_metric_raw(dst, RTAX_REORDERING);
@@ -384,7 +381,7 @@ void tcp_update_metrics(struct sock *sk)
                dst_confirm(dst);
 
        rcu_read_lock();
-       if (icsk->icsk_backoff || !tp->srtt) {
+       if (icsk->icsk_backoff || !tp->srtt_us) {
                /* This session failed to estimate rtt. Why?
                 * Probably, no packets returned in time.  Reset our
                 * results.
@@ -399,8 +396,8 @@ void tcp_update_metrics(struct sock *sk)
        if (!tm)
                goto out_unlock;
 
-       rtt = tcp_metric_get_jiffies(tm, TCP_METRIC_RTT);
-       m = rtt - tp->srtt;
+       rtt = tcp_metric_get(tm, TCP_METRIC_RTT);
+       m = rtt - tp->srtt_us;
 
        /* If newly calculated rtt larger than stored one, store new
         * one. Otherwise, use EWMA. Remember, rtt overestimation is
@@ -408,10 +405,10 @@ void tcp_update_metrics(struct sock *sk)
         */
        if (!tcp_metric_locked(tm, TCP_METRIC_RTT)) {
                if (m <= 0)
-                       rtt = tp->srtt;
+                       rtt = tp->srtt_us;
                else
                        rtt -= (m >> 3);
-               tcp_metric_set_msecs(tm, TCP_METRIC_RTT, rtt);
+               tcp_metric_set(tm, TCP_METRIC_RTT, rtt);
        }
 
        if (!tcp_metric_locked(tm, TCP_METRIC_RTTVAR)) {
@@ -422,16 +419,16 @@ void tcp_update_metrics(struct sock *sk)
 
                /* Scale deviation to rttvar fixed point */
                m >>= 1;
-               if (m < tp->mdev)
-                       m = tp->mdev;
+               if (m < tp->mdev_us)
+                       m = tp->mdev_us;
 
-               var = tcp_metric_get_jiffies(tm, TCP_METRIC_RTTVAR);
+               var = tcp_metric_get(tm, TCP_METRIC_RTTVAR);
                if (m >= var)
                        var = m;
                else
                        var -= (var - m) >> 2;
 
-               tcp_metric_set_msecs(tm, TCP_METRIC_RTTVAR, var);
+               tcp_metric_set(tm, TCP_METRIC_RTTVAR, var);
        }
 
        if (tcp_in_initial_slowstart(tp)) {
@@ -528,7 +525,7 @@ void tcp_init_metrics(struct sock *sk)
                tp->reordering = val;
        }
 
-       crtt = tcp_metric_get_jiffies(tm, TCP_METRIC_RTT);
+       crtt = tcp_metric_get(tm, TCP_METRIC_RTT);
        rcu_read_unlock();
 reset:
        /* The initial RTT measurement from the SYN/SYN-ACK is not ideal
@@ -551,18 +548,20 @@ reset:
         * to low value, and then abruptly stops to do it and starts to delay
         * ACKs, wait for troubles.
         */
-       if (crtt > tp->srtt) {
+       if (crtt > tp->srtt_us) {
                /* Set RTO like tcp_rtt_estimator(), but from cached RTT. */
-               crtt >>= 3;
+               crtt /= 8 * USEC_PER_MSEC;
                inet_csk(sk)->icsk_rto = crtt + max(2 * crtt, tcp_rto_min(sk));
-       } else if (tp->srtt == 0) {
+       } else if (tp->srtt_us == 0) {
                /* RFC6298: 5.7 We've failed to get a valid RTT sample from
                 * 3WHS. This is most likely due to retransmission,
                 * including spurious one. Reset the RTO back to 3secs
                 * from the more aggressive 1sec to avoid more spurious
                 * retransmission.
                 */
-               tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_FALLBACK;
+               tp->rttvar_us = jiffies_to_usecs(TCP_TIMEOUT_FALLBACK);
+               tp->mdev_us = tp->mdev_max_us = tp->rttvar_us;
+
                inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK;
        }
        /* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been
@@ -809,10 +808,26 @@ static int tcp_metrics_fill_info(struct sk_buff *msg,
                nest = nla_nest_start(msg, TCP_METRICS_ATTR_VALS);
                if (!nest)
                        goto nla_put_failure;
-               for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
-                       if (!tm->tcpm_vals[i])
+               for (i = 0; i < TCP_METRIC_MAX_KERNEL + 1; i++) {
+                       u32 val = tm->tcpm_vals[i];
+
+                       if (!val)
                                continue;
-                       if (nla_put_u32(msg, i + 1, tm->tcpm_vals[i]) < 0)
+                       if (i == TCP_METRIC_RTT) {
+                               if (nla_put_u32(msg, TCP_METRIC_RTT_US + 1,
+                                               val) < 0)
+                                       goto nla_put_failure;
+                               n++;
+                               val = max(val / 1000, 1U);
+                       }
+                       if (i == TCP_METRIC_RTTVAR) {
+                               if (nla_put_u32(msg, TCP_METRIC_RTTVAR_US + 1,
+                                               val) < 0)
+                                       goto nla_put_failure;
+                               n++;
+                               val = max(val / 1000, 1U);
+                       }
+                       if (nla_put_u32(msg, i + 1, val) < 0)
                                goto nla_put_failure;
                        n++;
                }
index 7a436c517e443f5c201251dbb90552f703f7a9b5..ca788ada5bd3619f2db2b3865e6469eb7c60f015 100644 (file)
@@ -398,8 +398,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 
                tcp_init_wl(newtp, treq->rcv_isn);
 
-               newtp->srtt = 0;
-               newtp->mdev = TCP_TIMEOUT_INIT;
+               newtp->srtt_us = 0;
+               newtp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT);
                newicsk->icsk_rto = TCP_TIMEOUT_INIT;
 
                newtp->packets_out = 0;
index 03d26b85eab8520c552040f527d37323be91bd68..699fb102e9710694f342951cf194facd153f7d37 100644 (file)
@@ -86,6 +86,9 @@ static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb)
            icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) {
                tcp_rearm_rto(sk);
        }
+
+       NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT,
+                     tcp_skb_pcount(skb));
 }
 
 /* SND.NXT, if window was not shrunk.
@@ -269,6 +272,7 @@ EXPORT_SYMBOL(tcp_select_initial_window);
 static u16 tcp_select_window(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
+       u32 old_win = tp->rcv_wnd;
        u32 cur_win = tcp_receive_window(tp);
        u32 new_win = __tcp_select_window(sk);
 
@@ -281,6 +285,9 @@ static u16 tcp_select_window(struct sock *sk)
                 *
                 * Relax Will Robinson.
                 */
+               if (new_win == 0)
+                       NET_INC_STATS(sock_net(sk),
+                                     LINUX_MIB_TCPWANTZEROWINDOWADV);
                new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale);
        }
        tp->rcv_wnd = new_win;
@@ -298,8 +305,14 @@ static u16 tcp_select_window(struct sock *sk)
        new_win >>= tp->rx_opt.rcv_wscale;
 
        /* If we advertise zero window, disable fast path. */
-       if (new_win == 0)
+       if (new_win == 0) {
                tp->pred_flags = 0;
+               if (old_win)
+                       NET_INC_STATS(sock_net(sk),
+                                     LINUX_MIB_TCPTOZEROWINDOWADV);
+       } else if (old_win == 0) {
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFROMZEROWINDOWADV);
+       }
 
        return new_win;
 }
@@ -698,7 +711,8 @@ static void tcp_tsq_handler(struct sock *sk)
        if ((1 << sk->sk_state) &
            (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_CLOSING |
             TCPF_CLOSE_WAIT  | TCPF_LAST_ACK))
-               tcp_write_xmit(sk, tcp_current_mss(sk), 0, 0, GFP_ATOMIC);
+               tcp_write_xmit(sk, tcp_current_mss(sk), tcp_sk(sk)->nonagle,
+                              0, GFP_ATOMIC);
 }
 /*
  * One tasklet per cpu tries to send more skbs.
@@ -766,6 +780,17 @@ void tcp_release_cb(struct sock *sk)
        if (flags & (1UL << TCP_TSQ_DEFERRED))
                tcp_tsq_handler(sk);
 
+       /* Here begins the tricky part :
+        * We are called from release_sock() with :
+        * 1) BH disabled
+        * 2) sk_lock.slock spinlock held
+        * 3) socket owned by us (sk->sk_lock.owned == 1)
+        *
+        * But following code is meant to be called from BH handlers,
+        * so we should keep BH disabled, but early release socket ownership
+        */
+       sock_release_ownership(sk);
+
        if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
                tcp_write_timer_handler(sk);
                __sock_put(sk);
@@ -855,16 +880,12 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
        if (clone_it) {
                const struct sk_buff *fclone = skb + 1;
 
-               /* If congestion control is doing timestamping, we must
-                * take such a timestamp before we potentially clone/copy.
-                */
-               if (icsk->icsk_ca_ops->flags & TCP_CONG_RTT_STAMP)
-                       __net_timestamp(skb);
+               skb_mstamp_get(&skb->skb_mstamp);
 
                if (unlikely(skb->fclone == SKB_FCLONE_ORIG &&
                             fclone->fclone == SKB_FCLONE_CLONE))
-                       NET_INC_STATS_BH(sock_net(sk),
-                                        LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
+                       NET_INC_STATS(sock_net(sk),
+                                     LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES);
 
                if (unlikely(skb_cloned(skb)))
                        skb = pskb_copy(skb, gfp_mask);
@@ -872,6 +893,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
                        skb = skb_clone(skb, gfp_mask);
                if (unlikely(!skb))
                        return -ENOBUFS;
+               /* Our usage of tstamp should remain private */
+               skb->tstamp.tv64 = 0;
        }
 
        inet = inet_sk(sk);
@@ -1414,7 +1437,7 @@ static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now,
  *    With Minshall's modification: all sent small packets are ACKed.
  */
 static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp,
-                           unsigned int mss_now, int nonagle)
+                           int nonagle)
 {
        return partial &&
                ((nonagle & TCP_NAGLE_CORK) ||
@@ -1446,7 +1469,7 @@ static unsigned int tcp_mss_split_point(const struct sock *sk,
         * to include this last segment in this skb.
         * Otherwise, we'll split the skb at last MSS boundary
         */
-       if (tcp_nagle_check(partial != 0, tp, mss_now, nonagle))
+       if (tcp_nagle_check(partial != 0, tp, nonagle))
                return needed - partial;
 
        return needed;
@@ -1509,7 +1532,7 @@ static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buf
        if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN))
                return true;
 
-       if (!tcp_nagle_check(skb->len < cur_mss, tp, cur_mss, nonagle))
+       if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle))
                return true;
 
        return false;
@@ -1904,7 +1927,15 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
 
                if (atomic_read(&sk->sk_wmem_alloc) > limit) {
                        set_bit(TSQ_THROTTLED, &tp->tsq_flags);
-                       break;
+                       /* It is possible TX completion already happened
+                        * before we set TSQ_THROTTLED, so we must
+                        * test again the condition.
+                        * We abuse smp_mb__after_clear_bit() because
+                        * there is no smp_mb__after_set_bit() yet
+                        */
+                       smp_mb__after_clear_bit();
+                       if (atomic_read(&sk->sk_wmem_alloc) > limit)
+                               break;
                }
 
                limit = mss_now;
@@ -1955,7 +1986,7 @@ bool tcp_schedule_loss_probe(struct sock *sk)
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        u32 timeout, tlp_time_stamp, rto_time_stamp;
-       u32 rtt = tp->srtt >> 3;
+       u32 rtt = usecs_to_jiffies(tp->srtt_us >> 3);
 
        if (WARN_ON(icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS))
                return false;
@@ -1977,7 +2008,7 @@ bool tcp_schedule_loss_probe(struct sock *sk)
        /* Schedule a loss probe in 2*RTT for SACK capable connections
         * in Open state, that are either limited by cwnd or application.
         */
-       if (sysctl_tcp_early_retrans < 3 || !rtt || !tp->packets_out ||
+       if (sysctl_tcp_early_retrans < 3 || !tp->srtt_us || !tp->packets_out ||
            !tcp_is_sack(tp) || inet_csk(sk)->icsk_ca_state != TCP_CA_Open)
                return false;
 
@@ -2062,7 +2093,6 @@ rearm_timer:
        if (likely(!err))
                NET_INC_STATS_BH(sock_net(sk),
                                 LINUX_MIB_TCPLOSSPROBES);
-       return;
 }
 
 /* Push out any pending frames which were held back due to
@@ -2160,7 +2190,8 @@ u32 __tcp_select_window(struct sock *sk)
         */
        int mss = icsk->icsk_ack.rcv_mss;
        int free_space = tcp_space(sk);
-       int full_space = min_t(int, tp->window_clamp, tcp_full_space(sk));
+       int allowed_space = tcp_full_space(sk);
+       int full_space = min_t(int, tp->window_clamp, allowed_space);
        int window;
 
        if (mss > full_space)
@@ -2173,7 +2204,19 @@ u32 __tcp_select_window(struct sock *sk)
                        tp->rcv_ssthresh = min(tp->rcv_ssthresh,
                                               4U * tp->advmss);
 
-               if (free_space < mss)
+               /* free_space might become our new window, make sure we don't
+                * increase it due to wscale.
+                */
+               free_space = round_down(free_space, 1 << tp->rx_opt.rcv_wscale);
+
+               /* if free space is less than mss estimate, or is below 1/16th
+                * of the maximum allowed, try to move to zero-window, else
+                * tcp_clamp_window() will grow rcv buf up to tcp_rmem[2], and
+                * new incoming data is dropped due to memory limits.
+                * With large window, mss test triggers way too late in order
+                * to announce zero window in time before rmem limit kicks in.
+                */
+               if (free_space < (allowed_space >> 4) || free_space < mss)
                        return 0;
        }
 
@@ -2328,6 +2371,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
        unsigned int cur_mss;
+       int err;
 
        /* Inconslusive MTU probe */
        if (icsk->icsk_mtup.probe_size) {
@@ -2391,11 +2435,15 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
                     skb_headroom(skb) >= 0xFFFF)) {
                struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
                                                   GFP_ATOMIC);
-               return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
-                             -ENOBUFS;
+               err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
+                            -ENOBUFS;
        } else {
-               return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
+               err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
        }
+
+       if (likely(!err))
+               TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS;
+       return err;
 }
 
 int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
@@ -2406,7 +2454,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        if (err == 0) {
                /* Update global TCP statistics. */
                TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS);
-
+               if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)
+                       NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
                tp->total_retrans++;
 
 #if FASTRETRANS_DEBUG > 0
@@ -2692,7 +2741,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        int tcp_header_size;
        int mss;
 
-       skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
+       skb = sock_wmalloc(sk, MAX_TCP_HEADER, 1, GFP_ATOMIC);
        if (unlikely(!skb)) {
                dst_release(dst);
                return NULL;
@@ -2762,7 +2811,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
        th->window = htons(min(req->rcv_wnd, 65535U));
        tcp_options_write((__be32 *)(th + 1), tp, &opts);
        th->doff = (tcp_header_size >> 2);
-       TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, tcp_skb_pcount(skb));
+       TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_OUTSEGS);
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Okay, we have all we need - do the md5 hash if needed */
@@ -2899,7 +2948,12 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
        space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) -
                MAX_TCP_OPTION_SPACE;
 
-       syn_data = skb_copy_expand(syn, skb_headroom(syn), space,
+       space = min_t(size_t, space, fo->size);
+
+       /* limit to order-0 allocations */
+       space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER));
+
+       syn_data = skb_copy_expand(syn, MAX_TCP_HEADER, space,
                                   sk->sk_allocation);
        if (syn_data == NULL)
                goto fallback;
@@ -2929,9 +2983,15 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
        tcp_connect_queue_skb(sk, data);
        fo->copied = data->len;
 
+       /* syn_data is about to be sent, we need to take current time stamps
+        * for the packets that are in write queue : SYN packet and DATA
+        */
+       skb_mstamp_get(&syn->skb_mstamp);
+       data->skb_mstamp = syn->skb_mstamp;
+
        if (tcp_transmit_skb(sk, syn_data, 0, sk->sk_allocation) == 0) {
                tp->syn_data = (fo->copied > 0);
-               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENACTIVE);
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT);
                goto done;
        }
        syn_data = NULL;
@@ -3019,8 +3079,9 @@ void tcp_send_delayed_ack(struct sock *sk)
                 * Do not use inet_csk(sk)->icsk_rto here, use results of rtt measurements
                 * directly.
                 */
-               if (tp->srtt) {
-                       int rtt = max(tp->srtt >> 3, TCP_DELACK_MIN);
+               if (tp->srtt_us) {
+                       int rtt = max_t(int, usecs_to_jiffies(tp->srtt_us >> 3),
+                                       TCP_DELACK_MIN);
 
                        if (rtt < max_ato)
                                max_ato = rtt;
index 1f2d37613c9e068058171abd53efa8709d63657e..3b66610d41562035c541304924fc27a4eb416a6e 100644 (file)
@@ -154,7 +154,7 @@ static void jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        p->snd_wnd = tp->snd_wnd;
                        p->rcv_wnd = tp->rcv_wnd;
                        p->ssthresh = tcp_current_ssthresh(sk);
-                       p->srtt = tp->srtt >> 3;
+                       p->srtt = tp->srtt_us >> 3;
 
                        tcp_probe.head = (tcp_probe.head + 1) & (bufsize - 1);
                }
index 19ea6c2951f3b35a29a9ddc04f8578f7abe3f87c..0ac50836da4d42832f3aa35c9a4cebbf79f69981 100644 (file)
@@ -39,7 +39,6 @@ static u32 tcp_scalable_ssthresh(struct sock *sk)
 static struct tcp_congestion_ops tcp_scalable __read_mostly = {
        .ssthresh       = tcp_scalable_ssthresh,
        .cong_avoid     = tcp_scalable_cong_avoid,
-       .min_cwnd       = tcp_reno_min_cwnd,
 
        .owner          = THIS_MODULE,
        .name           = "scalable",
index 64f0354c84c7a8956230f2794b4dcb56331d98fc..286227abed10656a5efeb7026a9741ad1b6c6207 100644 (file)
@@ -165,6 +165,9 @@ static int tcp_write_timeout(struct sock *sk)
                        dst_negative_advice(sk);
                        if (tp->syn_fastopen || tp->syn_data)
                                tcp_fastopen_cache_set(sk, 0, NULL, true);
+                       if (tp->syn_data)
+                               NET_INC_STATS_BH(sock_net(sk),
+                                                LINUX_MIB_TCPFASTOPENACTIVEFAIL);
                }
                retry_until = icsk->icsk_syn_retries ? : sysctl_tcp_syn_retries;
                syn_set = true;
index 06cae62bf20845fe67b6eff1c7919ec4f342569f..48539fff6357a4e778c537b99bb9a7fd49eb43b3 100644 (file)
@@ -306,11 +306,9 @@ void tcp_vegas_get_info(struct sock *sk, u32 ext, struct sk_buff *skb)
 EXPORT_SYMBOL_GPL(tcp_vegas_get_info);
 
 static struct tcp_congestion_ops tcp_vegas __read_mostly = {
-       .flags          = TCP_CONG_RTT_STAMP,
        .init           = tcp_vegas_init,
        .ssthresh       = tcp_reno_ssthresh,
        .cong_avoid     = tcp_vegas_cong_avoid,
-       .min_cwnd       = tcp_reno_min_cwnd,
        .pkts_acked     = tcp_vegas_pkts_acked,
        .set_state      = tcp_vegas_state,
        .cwnd_event     = tcp_vegas_cwnd_event,
index 326475a94865c2fd0cbcf7bffe97c21d37159683..1b8e28fcd7e1cab3edd586db1b716742a4402fd7 100644 (file)
@@ -203,7 +203,6 @@ static u32 tcp_veno_ssthresh(struct sock *sk)
 }
 
 static struct tcp_congestion_ops tcp_veno __read_mostly = {
-       .flags          = TCP_CONG_RTT_STAMP,
        .init           = tcp_veno_init,
        .ssthresh       = tcp_veno_ssthresh,
        .cong_avoid     = tcp_veno_cong_avoid,
index 76a1e23259e1fa713bb447486e4e94848e419d41..b94a04ae2ed5672eca79a172c5c3467a677186a1 100644 (file)
@@ -276,7 +276,6 @@ static struct tcp_congestion_ops tcp_westwood __read_mostly = {
        .init           = tcp_westwood_init,
        .ssthresh       = tcp_reno_ssthresh,
        .cong_avoid     = tcp_reno_cong_avoid,
-       .min_cwnd       = tcp_westwood_bw_rttmin,
        .cwnd_event     = tcp_westwood_event,
        .get_info       = tcp_westwood_info,
        .pkts_acked     = tcp_westwood_pkts_acked,
index 1a8d271f994da4f5e5ad765b342c82e1efe198fa..5ede0e727945add71904a2d3c57d334e77e94baf 100644 (file)
@@ -227,11 +227,9 @@ static u32 tcp_yeah_ssthresh(struct sock *sk) {
 }
 
 static struct tcp_congestion_ops tcp_yeah __read_mostly = {
-       .flags          = TCP_CONG_RTT_STAMP,
        .init           = tcp_yeah_init,
        .ssthresh       = tcp_yeah_ssthresh,
        .cong_avoid     = tcp_yeah_cong_avoid,
-       .min_cwnd       = tcp_reno_min_cwnd,
        .set_state      = tcp_vegas_state,
        .cwnd_event     = tcp_vegas_cwnd_event,
        .get_info       = tcp_vegas_get_info,
index 77bd16fa9f34381a79e40f3b9c4b0adb4631f186..4468e1adc094a1f6f12eb20cf7c79a9b9187826d 100644 (file)
@@ -931,7 +931,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        sock_tx_timestamp(sk, &ipc.tx_flags);
 
        if (msg->msg_controllen) {
-               err = ip_cmsg_send(sock_net(sk), msg, &ipc);
+               err = ip_cmsg_send(sock_net(sk), msg, &ipc,
+                                  sk->sk_family == AF_INET6);
                if (err)
                        return err;
                if (ipc.opt)
index 25f5cee3a08a3ea22f2b30ef15809da73af44f08..88b4023ecfcfc85df907ff7472354084b3b16264 100644 (file)
@@ -17,6 +17,8 @@
 static DEFINE_SPINLOCK(udp_offload_lock);
 static struct udp_offload_priv __rcu *udp_offload_base __read_mostly;
 
+#define udp_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&udp_offload_lock))
+
 struct udp_offload_priv {
        struct udp_offload      *offload;
        struct rcu_head         rcu;
@@ -100,8 +102,7 @@ out:
 
 int udp_add_offload(struct udp_offload *uo)
 {
-       struct udp_offload_priv __rcu **head = &udp_offload_base;
-       struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_KERNEL);
+       struct udp_offload_priv *new_offload = kzalloc(sizeof(*new_offload), GFP_ATOMIC);
 
        if (!new_offload)
                return -ENOMEM;
@@ -109,8 +110,8 @@ int udp_add_offload(struct udp_offload *uo)
        new_offload->offload = uo;
 
        spin_lock(&udp_offload_lock);
-       rcu_assign_pointer(new_offload->next, rcu_dereference(*head));
-       rcu_assign_pointer(*head, new_offload);
+       new_offload->next = udp_offload_base;
+       rcu_assign_pointer(udp_offload_base, new_offload);
        spin_unlock(&udp_offload_lock);
 
        return 0;
@@ -130,12 +131,12 @@ void udp_del_offload(struct udp_offload *uo)
 
        spin_lock(&udp_offload_lock);
 
-       uo_priv = rcu_dereference(*head);
+       uo_priv = udp_deref_protected(*head);
        for (; uo_priv != NULL;
-               uo_priv = rcu_dereference(*head)) {
-
+            uo_priv = udp_deref_protected(*head)) {
                if (uo_priv->offload == uo) {
-                       rcu_assign_pointer(*head, rcu_dereference(uo_priv->next));
+                       rcu_assign_pointer(*head,
+                                          udp_deref_protected(uo_priv->next));
                        goto unlock;
                }
                head = &uo_priv->next;
index 1f12c8b4586497931831515e06a8005140863ff5..aac6197b7a7132f31af9a80d960d94d4a9f92290 100644 (file)
@@ -37,15 +37,6 @@ drop:
        return NET_RX_DROP;
 }
 
-int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
-                   int encap_type)
-{
-       XFRM_SPI_SKB_CB(skb)->family = AF_INET;
-       XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
-       return xfrm_input(skb, nexthdr, spi, encap_type);
-}
-EXPORT_SYMBOL(xfrm4_rcv_encap);
-
 int xfrm4_transport_finish(struct sk_buff *skb, int async)
 {
        struct iphdr *iph = ip_hdr(skb);
index 31b18152528fe4dbf9e500ae0c9a2a1a5a3a2adf..05f2b484954feda957d04ff2f0300eedf9c97263 100644 (file)
 #include <net/ip.h>
 #include <net/xfrm.h>
 
-/* Informational hook. The decap is still done here. */
-static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly;
-static DEFINE_MUTEX(xfrm4_mode_tunnel_input_mutex);
-
-int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler)
-{
-       struct xfrm_tunnel_notifier __rcu **pprev;
-       struct xfrm_tunnel_notifier *t;
-       int ret = -EEXIST;
-       int priority = handler->priority;
-
-       mutex_lock(&xfrm4_mode_tunnel_input_mutex);
-
-       for (pprev = &rcv_notify_handlers;
-            (t = rcu_dereference_protected(*pprev,
-            lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
-            pprev = &t->next) {
-               if (t->priority > priority)
-                       break;
-               if (t->priority == priority)
-                       goto err;
-
-       }
-
-       handler->next = *pprev;
-       rcu_assign_pointer(*pprev, handler);
-
-       ret = 0;
-
-err:
-       mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_register);
-
-int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler)
-{
-       struct xfrm_tunnel_notifier __rcu **pprev;
-       struct xfrm_tunnel_notifier *t;
-       int ret = -ENOENT;
-
-       mutex_lock(&xfrm4_mode_tunnel_input_mutex);
-       for (pprev = &rcv_notify_handlers;
-            (t = rcu_dereference_protected(*pprev,
-            lockdep_is_held(&xfrm4_mode_tunnel_input_mutex))) != NULL;
-            pprev = &t->next) {
-               if (t == handler) {
-                       *pprev = handler->next;
-                       ret = 0;
-                       break;
-               }
-       }
-       mutex_unlock(&xfrm4_mode_tunnel_input_mutex);
-       synchronize_net();
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(xfrm4_mode_tunnel_input_deregister);
-
 static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
 {
        struct iphdr *inner_iph = ipip_hdr(skb);
@@ -127,14 +68,8 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
        return 0;
 }
 
-#define for_each_input_rcu(head, handler)      \
-       for (handler = rcu_dereference(head);   \
-            handler != NULL;                   \
-            handler = rcu_dereference(handler->next))
-
 static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       struct xfrm_tunnel_notifier *handler;
        int err = -EINVAL;
 
        if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
@@ -143,9 +78,6 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
                goto out;
 
-       for_each_input_rcu(rcv_notify_handlers, handler)
-               handler->handler(skb);
-
        err = skb_unclone(skb, GFP_ATOMIC);
        if (err)
                goto out;
index e1a63930a96789b7df67a8b9914cd3bb69fb1cd9..6156f68a1e90b53f7504a1e6f729b60c29d52b3a 100644 (file)
@@ -325,6 +325,7 @@ void __init xfrm4_init(void)
 
        xfrm4_state_init();
        xfrm4_policy_init();
+       xfrm4_protocol_init();
 #ifdef CONFIG_SYSCTL
        register_pernet_subsys(&xfrm4_net_ops);
 #endif
diff --git a/net/ipv4/xfrm4_protocol.c b/net/ipv4/xfrm4_protocol.c
new file mode 100644 (file)
index 0000000..7f7b243
--- /dev/null
@@ -0,0 +1,286 @@
+/* xfrm4_protocol.c - Generic xfrm protocol multiplexer.
+ *
+ * Copyright (C) 2013 secunet Security Networks AG
+ *
+ * Author:
+ * Steffen Klassert <steffen.klassert@secunet.com>
+ *
+ * Based on:
+ * net/ipv4/tunnel4.c
+ *
+ *     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/init.h>
+#include <linux/mutex.h>
+#include <linux/skbuff.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
+static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
+static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
+static DEFINE_MUTEX(xfrm4_protocol_mutex);
+
+static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
+{
+       switch (protocol) {
+       case IPPROTO_ESP:
+               return &esp4_handlers;
+       case IPPROTO_AH:
+               return &ah4_handlers;
+       case IPPROTO_COMP:
+               return &ipcomp4_handlers;
+       }
+
+       return NULL;
+}
+
+#define for_each_protocol_rcu(head, handler)           \
+       for (handler = rcu_dereference(head);           \
+            handler != NULL;                           \
+            handler = rcu_dereference(handler->next))  \
+
+int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
+{
+       int ret;
+       struct xfrm4_protocol *handler;
+
+       for_each_protocol_rcu(*proto_handlers(protocol), handler)
+               if ((ret = handler->cb_handler(skb, err)) <= 0)
+                       return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(xfrm4_rcv_cb);
+
+int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
+                   int encap_type)
+{
+       int ret;
+       struct xfrm4_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
+       XFRM_SPI_SKB_CB(skb)->family = AF_INET;
+       XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
+
+       for_each_protocol_rcu(*proto_handlers(nexthdr), handler)
+               if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
+                       return ret;
+
+       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+EXPORT_SYMBOL(xfrm4_rcv_encap);
+
+static int xfrm4_esp_rcv(struct sk_buff *skb)
+{
+       int ret;
+       struct xfrm4_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
+
+       for_each_protocol_rcu(esp4_handlers, handler)
+               if ((ret = handler->handler(skb)) != -EINVAL)
+                       return ret;
+
+       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static void xfrm4_esp_err(struct sk_buff *skb, u32 info)
+{
+       struct xfrm4_protocol *handler;
+
+       for_each_protocol_rcu(esp4_handlers, handler)
+               if (!handler->err_handler(skb, info))
+                       break;
+}
+
+static int xfrm4_ah_rcv(struct sk_buff *skb)
+{
+       int ret;
+       struct xfrm4_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
+
+       for_each_protocol_rcu(ah4_handlers, handler)
+               if ((ret = handler->handler(skb)) != -EINVAL)
+                       return ret;;
+
+       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static void xfrm4_ah_err(struct sk_buff *skb, u32 info)
+{
+       struct xfrm4_protocol *handler;
+
+       for_each_protocol_rcu(ah4_handlers, handler)
+               if (!handler->err_handler(skb, info))
+                       break;
+}
+
+static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
+{
+       int ret;
+       struct xfrm4_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
+
+       for_each_protocol_rcu(ipcomp4_handlers, handler)
+               if ((ret = handler->handler(skb)) != -EINVAL)
+                       return ret;
+
+       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static void xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
+{
+       struct xfrm4_protocol *handler;
+
+       for_each_protocol_rcu(ipcomp4_handlers, handler)
+               if (!handler->err_handler(skb, info))
+                       break;
+}
+
+static const struct net_protocol esp4_protocol = {
+       .handler        =       xfrm4_esp_rcv,
+       .err_handler    =       xfrm4_esp_err,
+       .no_policy      =       1,
+       .netns_ok       =       1,
+};
+
+static const struct net_protocol ah4_protocol = {
+       .handler        =       xfrm4_ah_rcv,
+       .err_handler    =       xfrm4_ah_err,
+       .no_policy      =       1,
+       .netns_ok       =       1,
+};
+
+static const struct net_protocol ipcomp4_protocol = {
+       .handler        =       xfrm4_ipcomp_rcv,
+       .err_handler    =       xfrm4_ipcomp_err,
+       .no_policy      =       1,
+       .netns_ok       =       1,
+};
+
+static struct xfrm_input_afinfo xfrm4_input_afinfo = {
+       .family         =       AF_INET,
+       .owner          =       THIS_MODULE,
+       .callback       =       xfrm4_rcv_cb,
+};
+
+static inline const struct net_protocol *netproto(unsigned char protocol)
+{
+       switch (protocol) {
+       case IPPROTO_ESP:
+               return &esp4_protocol;
+       case IPPROTO_AH:
+               return &ah4_protocol;
+       case IPPROTO_COMP:
+               return &ipcomp4_protocol;
+       }
+
+       return NULL;
+}
+
+int xfrm4_protocol_register(struct xfrm4_protocol *handler,
+                           unsigned char protocol)
+{
+       struct xfrm4_protocol __rcu **pprev;
+       struct xfrm4_protocol *t;
+       bool add_netproto = false;
+       int ret = -EEXIST;
+       int priority = handler->priority;
+
+       mutex_lock(&xfrm4_protocol_mutex);
+
+       if (!rcu_dereference_protected(*proto_handlers(protocol),
+                                      lockdep_is_held(&xfrm4_protocol_mutex)))
+               add_netproto = true;
+
+       for (pprev = proto_handlers(protocol);
+            (t = rcu_dereference_protected(*pprev,
+                       lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t->priority < priority)
+                       break;
+               if (t->priority == priority)
+                       goto err;
+       }
+
+       handler->next = *pprev;
+       rcu_assign_pointer(*pprev, handler);
+
+       ret = 0;
+
+err:
+       mutex_unlock(&xfrm4_protocol_mutex);
+
+       if (add_netproto) {
+               if (inet_add_protocol(netproto(protocol), protocol)) {
+                       pr_err("%s: can't add protocol\n", __func__);
+                       ret = -EAGAIN;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(xfrm4_protocol_register);
+
+int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
+                             unsigned char protocol)
+{
+       struct xfrm4_protocol __rcu **pprev;
+       struct xfrm4_protocol *t;
+       int ret = -ENOENT;
+
+       mutex_lock(&xfrm4_protocol_mutex);
+
+       for (pprev = proto_handlers(protocol);
+            (t = rcu_dereference_protected(*pprev,
+                       lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t == handler) {
+                       *pprev = handler->next;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (!rcu_dereference_protected(*proto_handlers(protocol),
+                                      lockdep_is_held(&xfrm4_protocol_mutex))) {
+               if (inet_del_protocol(netproto(protocol), protocol) < 0) {
+                       pr_err("%s: can't remove protocol\n", __func__);
+                       ret = -EAGAIN;
+               }
+       }
+
+       mutex_unlock(&xfrm4_protocol_mutex);
+
+       synchronize_net();
+
+       return ret;
+}
+EXPORT_SYMBOL(xfrm4_protocol_deregister);
+
+void __init xfrm4_protocol_init(void)
+{
+       xfrm_input_register_afinfo(&xfrm4_input_afinfo);
+}
+EXPORT_SYMBOL(xfrm4_protocol_init);
index d92e5586783e518c1f5db2b1bd3261766ff7a913..438a73aa777cf560f38a87801b03b8ce20a315b1 100644 (file)
@@ -138,6 +138,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
 config IPV6_VTI
 tristate "Virtual (secure) IPv6: tunneling"
        select IPV6_TUNNEL
+       select NET_IP_TUNNEL
        depends on INET6_XFRM_MODE_TUNNEL
        ---help---
        Tunneling means encapsulating data of one protocol type within
index 17bb830872db21e07080ed9f6a0ef93cbccee9b7..2fe68364bb20610c39f20a21b4d32498ff5741d1 100644 (file)
@@ -16,7 +16,7 @@ ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
 ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
 
 ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
-       xfrm6_output.o
+       xfrm6_output.o xfrm6_protocol.o
 ipv6-$(CONFIG_NETFILTER) += netfilter.o
 ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
 ipv6-$(CONFIG_PROC_FS) += proc.o
index ad235690684c97f873e0c24b774d5184055fe7e2..6c7fa0853fc74ef179b00de52d78aecee342e18b 100644 (file)
@@ -133,10 +133,12 @@ static int ipv6_count_addresses(struct inet6_dev *idev);
 static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
 static DEFINE_SPINLOCK(addrconf_hash_lock);
 
-static void addrconf_verify(unsigned long);
+static void addrconf_verify(void);
+static void addrconf_verify_rtnl(void);
+static void addrconf_verify_work(struct work_struct *);
 
-static DEFINE_TIMER(addr_chk_timer, addrconf_verify, 0, 0);
-static DEFINE_SPINLOCK(addrconf_verify_lock);
+static struct workqueue_struct *addrconf_wq;
+static DECLARE_DELAYED_WORK(addr_chk_work, addrconf_verify_work);
 
 static void addrconf_join_anycast(struct inet6_ifaddr *ifp);
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp);
@@ -151,7 +153,7 @@ static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx,
                                                  u32 flags, u32 noflags);
 
 static void addrconf_dad_start(struct inet6_ifaddr *ifp);
-static void addrconf_dad_timer(unsigned long data);
+static void addrconf_dad_work(struct work_struct *w);
 static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
 static void addrconf_dad_run(struct inet6_dev *idev);
 static void addrconf_rs_timer(unsigned long data);
@@ -247,9 +249,9 @@ static void addrconf_del_rs_timer(struct inet6_dev *idev)
                __in6_dev_put(idev);
 }
 
-static void addrconf_del_dad_timer(struct inet6_ifaddr *ifp)
+static void addrconf_del_dad_work(struct inet6_ifaddr *ifp)
 {
-       if (del_timer(&ifp->dad_timer))
+       if (cancel_delayed_work(&ifp->dad_work))
                __in6_ifa_put(ifp);
 }
 
@@ -261,12 +263,12 @@ static void addrconf_mod_rs_timer(struct inet6_dev *idev,
        mod_timer(&idev->rs_timer, jiffies + when);
 }
 
-static void addrconf_mod_dad_timer(struct inet6_ifaddr *ifp,
-                                  unsigned long when)
+static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp,
+                                  unsigned long delay)
 {
-       if (!timer_pending(&ifp->dad_timer))
+       if (!delayed_work_pending(&ifp->dad_work))
                in6_ifa_hold(ifp);
-       mod_timer(&ifp->dad_timer, jiffies + when);
+       mod_delayed_work(addrconf_wq, &ifp->dad_work, delay);
 }
 
 static int snmp6_alloc_dev(struct inet6_dev *idev)
@@ -751,8 +753,9 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
 
        in6_dev_put(ifp->idev);
 
-       if (del_timer(&ifp->dad_timer))
-               pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
+       if (cancel_delayed_work(&ifp->dad_work))
+               pr_notice("delayed DAD work was pending while freeing ifa=%p\n",
+                         ifp);
 
        if (ifp->state != INET6_IFADDR_STATE_DEAD) {
                pr_warn("Freeing alive inet6 address %p\n", ifp);
@@ -849,8 +852,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
-       setup_timer(&ifa->dad_timer, addrconf_dad_timer,
-                   (unsigned long)ifa);
+       INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work);
        INIT_HLIST_NODE(&ifa->addr_lst);
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
@@ -990,6 +992,8 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
        enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP;
        unsigned long expires;
 
+       ASSERT_RTNL();
+
        spin_lock_bh(&ifp->state_lock);
        state = ifp->state;
        ifp->state = INET6_IFADDR_STATE_DEAD;
@@ -1021,7 +1025,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 
        write_unlock_bh(&ifp->idev->lock);
 
-       addrconf_del_dad_timer(ifp);
+       addrconf_del_dad_work(ifp);
 
        ipv6_ifa_notify(RTM_DELADDR, ifp);
 
@@ -1103,8 +1107,11 @@ retry:
         * Lifetime is greater than REGEN_ADVANCE time units.  In particular,
         * an implementation must not create a temporary address with a zero
         * Preferred Lifetime.
+        * Use age calculation as in addrconf_verify to avoid unnecessary
+        * temporary addresses being generated.
         */
-       if (tmp_prefered_lft <= regen_advance) {
+       age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
+       if (tmp_prefered_lft <= regen_advance + age) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                ret = -1;
@@ -1601,7 +1608,7 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
 {
        if (ifp->flags&IFA_F_PERMANENT) {
                spin_lock_bh(&ifp->lock);
-               addrconf_del_dad_timer(ifp);
+               addrconf_del_dad_work(ifp);
                ifp->flags |= IFA_F_TENTATIVE;
                if (dad_failed)
                        ifp->flags |= IFA_F_DADFAILED;
@@ -1622,20 +1629,21 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
                        spin_unlock_bh(&ifp->lock);
                }
                ipv6_del_addr(ifp);
-       } else
+       } else {
                ipv6_del_addr(ifp);
+       }
 }
 
 static int addrconf_dad_end(struct inet6_ifaddr *ifp)
 {
        int err = -ENOENT;
 
-       spin_lock(&ifp->state_lock);
+       spin_lock_bh(&ifp->state_lock);
        if (ifp->state == INET6_IFADDR_STATE_DAD) {
                ifp->state = INET6_IFADDR_STATE_POSTDAD;
                err = 0;
        }
-       spin_unlock(&ifp->state_lock);
+       spin_unlock_bh(&ifp->state_lock);
 
        return err;
 }
@@ -1668,7 +1676,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
                }
        }
 
-       addrconf_dad_stop(ifp, 1);
+       spin_lock_bh(&ifp->state_lock);
+       /* transition from _POSTDAD to _ERRDAD */
+       ifp->state = INET6_IFADDR_STATE_ERRDAD;
+       spin_unlock_bh(&ifp->state_lock);
+
+       addrconf_mod_dad_work(ifp, 0);
 }
 
 /* Join to solicited addr multicast group. */
@@ -1677,6 +1690,8 @@ void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr)
 {
        struct in6_addr maddr;
 
+       ASSERT_RTNL();
+
        if (dev->flags&(IFF_LOOPBACK|IFF_NOARP))
                return;
 
@@ -1688,6 +1703,8 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
 {
        struct in6_addr maddr;
 
+       ASSERT_RTNL();
+
        if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP))
                return;
 
@@ -1698,6 +1715,9 @@ void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr)
 static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
+
+       ASSERT_RTNL();
+
        if (ifp->prefix_len >= 127) /* RFC 6164 */
                return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -1709,6 +1729,9 @@ static void addrconf_join_anycast(struct inet6_ifaddr *ifp)
 static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
 {
        struct in6_addr addr;
+
+       ASSERT_RTNL();
+
        if (ifp->prefix_len >= 127) /* RFC 6164 */
                return;
        ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len);
@@ -2268,11 +2291,13 @@ ok:
                                return;
                        }
 
-                       ifp->flags |= IFA_F_MANAGETEMPADDR;
                        update_lft = 0;
                        create = 1;
+                       spin_lock_bh(&ifp->lock);
+                       ifp->flags |= IFA_F_MANAGETEMPADDR;
                        ifp->cstamp = jiffies;
                        ifp->tokenized = tokenized;
+                       spin_unlock_bh(&ifp->lock);
                        addrconf_dad_start(ifp);
                }
 
@@ -2323,7 +2348,7 @@ ok:
                                         create, now);
 
                        in6_ifa_put(ifp);
-                       addrconf_verify(0);
+                       addrconf_verify();
                }
        }
        inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo);
@@ -2472,7 +2497,7 @@ static int inet6_addr_add(struct net *net, int ifindex,
                        manage_tempaddrs(idev, ifp, valid_lft, prefered_lft,
                                         true, jiffies);
                in6_ifa_put(ifp);
-               addrconf_verify(0);
+               addrconf_verify_rtnl();
                return 0;
        }
 
@@ -2783,6 +2808,8 @@ static void addrconf_gre_config(struct net_device *dev)
        ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
        if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
                addrconf_add_linklocal(idev, &addr);
+       else
+               addrconf_prefix_route(&addr, 64, dev, 0, 0);
 }
 #endif
 
@@ -3006,7 +3033,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                hlist_for_each_entry_rcu(ifa, h, addr_lst) {
                        if (ifa->idev == idev) {
                                hlist_del_init_rcu(&ifa->addr_lst);
-                               addrconf_del_dad_timer(ifa);
+                               addrconf_del_dad_work(ifa);
                                goto restart;
                        }
                }
@@ -3044,7 +3071,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
        while (!list_empty(&idev->addr_list)) {
                ifa = list_first_entry(&idev->addr_list,
                                       struct inet6_ifaddr, if_list);
-               addrconf_del_dad_timer(ifa);
+               addrconf_del_dad_work(ifa);
 
                list_del(&ifa->if_list);
 
@@ -3143,10 +3170,10 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
                rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);
 
        ifp->dad_probes = idev->cnf.dad_transmits;
-       addrconf_mod_dad_timer(ifp, rand_num);
+       addrconf_mod_dad_work(ifp, rand_num);
 }
 
-static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
 {
        struct inet6_dev *idev = ifp->idev;
        struct net_device *dev = idev->dev;
@@ -3198,25 +3225,68 @@ out:
        read_unlock_bh(&idev->lock);
 }
 
-static void addrconf_dad_timer(unsigned long data)
+static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+{
+       bool begin_dad = false;
+
+       spin_lock_bh(&ifp->state_lock);
+       if (ifp->state != INET6_IFADDR_STATE_DEAD) {
+               ifp->state = INET6_IFADDR_STATE_PREDAD;
+               begin_dad = true;
+       }
+       spin_unlock_bh(&ifp->state_lock);
+
+       if (begin_dad)
+               addrconf_mod_dad_work(ifp, 0);
+}
+
+static void addrconf_dad_work(struct work_struct *w)
 {
-       struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
+       struct inet6_ifaddr *ifp = container_of(to_delayed_work(w),
+                                               struct inet6_ifaddr,
+                                               dad_work);
        struct inet6_dev *idev = ifp->idev;
        struct in6_addr mcaddr;
 
+       enum {
+               DAD_PROCESS,
+               DAD_BEGIN,
+               DAD_ABORT,
+       } action = DAD_PROCESS;
+
+       rtnl_lock();
+
+       spin_lock_bh(&ifp->state_lock);
+       if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
+               action = DAD_BEGIN;
+               ifp->state = INET6_IFADDR_STATE_DAD;
+       } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) {
+               action = DAD_ABORT;
+               ifp->state = INET6_IFADDR_STATE_POSTDAD;
+       }
+       spin_unlock_bh(&ifp->state_lock);
+
+       if (action == DAD_BEGIN) {
+               addrconf_dad_begin(ifp);
+               goto out;
+       } else if (action == DAD_ABORT) {
+               addrconf_dad_stop(ifp, 1);
+               goto out;
+       }
+
        if (!ifp->dad_probes && addrconf_dad_end(ifp))
                goto out;
 
-       write_lock(&idev->lock);
+       write_lock_bh(&idev->lock);
        if (idev->dead || !(idev->if_flags & IF_READY)) {
-               write_unlock(&idev->lock);
+               write_unlock_bh(&idev->lock);
                goto out;
        }
 
        spin_lock(&ifp->lock);
        if (ifp->state == INET6_IFADDR_STATE_DEAD) {
                spin_unlock(&ifp->lock);
-               write_unlock(&idev->lock);
+               write_unlock_bh(&idev->lock);
                goto out;
        }
 
@@ -3227,7 +3297,7 @@ static void addrconf_dad_timer(unsigned long data)
 
                ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
                spin_unlock(&ifp->lock);
-               write_unlock(&idev->lock);
+               write_unlock_bh(&idev->lock);
 
                addrconf_dad_completed(ifp);
 
@@ -3235,16 +3305,17 @@ static void addrconf_dad_timer(unsigned long data)
        }
 
        ifp->dad_probes--;
-       addrconf_mod_dad_timer(ifp,
-                              NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
+       addrconf_mod_dad_work(ifp,
+                             NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
        spin_unlock(&ifp->lock);
-       write_unlock(&idev->lock);
+       write_unlock_bh(&idev->lock);
 
        /* send a neighbour solicitation for our addr */
        addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
        ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any);
 out:
        in6_ifa_put(ifp);
+       rtnl_unlock();
 }
 
 /* ifp->idev must be at least read locked */
@@ -3271,7 +3342,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
        struct in6_addr lladdr;
        bool send_rs, send_mld;
 
-       addrconf_del_dad_timer(ifp);
+       addrconf_del_dad_work(ifp);
 
        /*
         *      Configure the address for reception. Now it is valid.
@@ -3512,23 +3583,23 @@ int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr)
  *     Periodic address status verification
  */
 
-static void addrconf_verify(unsigned long foo)
+static void addrconf_verify_rtnl(void)
 {
        unsigned long now, next, next_sec, next_sched;
        struct inet6_ifaddr *ifp;
        int i;
 
+       ASSERT_RTNL();
+
        rcu_read_lock_bh();
-       spin_lock(&addrconf_verify_lock);
        now = jiffies;
        next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
 
-       del_timer(&addr_chk_timer);
+       cancel_delayed_work(&addr_chk_work);
 
        for (i = 0; i < IN6_ADDR_HSIZE; i++) {
 restart:
-               hlist_for_each_entry_rcu_bh(ifp,
-                                        &inet6_addr_lst[i], addr_lst) {
+               hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[i], addr_lst) {
                        unsigned long age;
 
                        /* When setting preferred_lft to a value not zero or
@@ -3623,13 +3694,22 @@ restart:
 
        ADBG(KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
              now, next, next_sec, next_sched);
-
-       addr_chk_timer.expires = next_sched;
-       add_timer(&addr_chk_timer);
-       spin_unlock(&addrconf_verify_lock);
+       mod_delayed_work(addrconf_wq, &addr_chk_work, next_sched - now);
        rcu_read_unlock_bh();
 }
 
+static void addrconf_verify_work(struct work_struct *w)
+{
+       rtnl_lock();
+       addrconf_verify_rtnl();
+       rtnl_unlock();
+}
+
+static void addrconf_verify(void)
+{
+       mod_delayed_work(addrconf_wq, &addr_chk_work, 0);
+}
+
 static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local,
                                     struct in6_addr **peer_pfx)
 {
@@ -3686,6 +3766,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
        bool was_managetempaddr;
        bool had_prefixroute;
 
+       ASSERT_RTNL();
+
        if (!valid_lft || (prefered_lft > valid_lft))
                return -EINVAL;
 
@@ -3751,7 +3833,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
                                 !was_managetempaddr, jiffies);
        }
 
-       addrconf_verify(0);
+       addrconf_verify_rtnl();
 
        return 0;
 }
@@ -4381,6 +4463,8 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
        bool update_rs = false;
        struct in6_addr ll_addr;
 
+       ASSERT_RTNL();
+
        if (token == NULL)
                return -EINVAL;
        if (ipv6_addr_any(token))
@@ -4429,7 +4513,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
        }
 
        write_unlock_bh(&idev->lock);
-       addrconf_verify(0);
+       addrconf_verify_rtnl();
        return 0;
 }
 
@@ -4631,6 +4715,9 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 {
        struct net *net = dev_net(ifp->idev->dev);
 
+       if (event)
+               ASSERT_RTNL();
+
        inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
 
        switch (event) {
@@ -5239,6 +5326,12 @@ int __init addrconf_init(void)
        if (err < 0)
                goto out_addrlabel;
 
+       addrconf_wq = create_workqueue("ipv6_addrconf");
+       if (!addrconf_wq) {
+               err = -ENOMEM;
+               goto out_nowq;
+       }
+
        /* The addrconf netdev notifier requires that loopback_dev
         * has it's ipv6 private information allocated and setup
         * before it can bring up and give link-local addresses
@@ -5269,7 +5362,7 @@ int __init addrconf_init(void)
 
        register_netdevice_notifier(&ipv6_dev_notf);
 
-       addrconf_verify(0);
+       addrconf_verify();
 
        rtnl_af_register(&inet6_ops);
 
@@ -5297,6 +5390,8 @@ errout:
        rtnl_af_unregister(&inet6_ops);
        unregister_netdevice_notifier(&ipv6_dev_notf);
 errlo:
+       destroy_workqueue(addrconf_wq);
+out_nowq:
        unregister_pernet_subsys(&addrconf_ops);
 out_addrlabel:
        ipv6_addr_label_cleanup();
@@ -5332,7 +5427,8 @@ void addrconf_cleanup(void)
        for (i = 0; i < IN6_ADDR_HSIZE; i++)
                WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
        spin_unlock_bh(&addrconf_hash_lock);
-
-       del_timer(&addr_chk_timer);
+       cancel_delayed_work(&addr_chk_work);
        rtnl_unlock();
+
+       destroy_workqueue(addrconf_wq);
 }
index b30ad3741b46732ee2c38bc851fa759ac02ff698..731e1e1722d9b4322f3907e57e3a1fd1994230b5 100644 (file)
@@ -6,7 +6,7 @@
  */
 /*
  * Author:
- *     YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org>
+ *     YOSHIFUJI Hideaki @ USAGI/WIDE Project <yoshfuji@linux-ipv6.org>
  */
 
 #include <linux/kernel.h>
 #if 0
 #define ADDRLABEL(x...) printk(x)
 #else
-#define ADDRLABEL(x...) do { ; } while(0)
+#define ADDRLABEL(x...) do { ; } while (0)
 #endif
 
 /*
  * Policy Table
  */
-struct ip6addrlbl_entry
-{
+struct ip6addrlbl_entry {
 #ifdef CONFIG_NET_NS
        struct net *lbl_net;
 #endif
@@ -88,39 +87,39 @@ static const __net_initconst struct ip6addrlbl_init_table
        {       /* ::/0 */
                .prefix = &in6addr_any,
                .label = 1,
-       },    /* fc00::/7 */
-               .prefix = &(struct in6_addr){{{ 0xfc }}},
+       }, {    /* fc00::/7 */
+               .prefix = &(struct in6_addr){ { { 0xfc } } } ,
                .prefixlen = 7,
                .label = 5,
-       },    /* fec0::/10 */
-               .prefix = &(struct in6_addr){{{ 0xfe, 0xc0 }}},
+       }, {    /* fec0::/10 */
+               .prefix = &(struct in6_addr){ { { 0xfe, 0xc0 } } },
                .prefixlen = 10,
                .label = 11,
-       },    /* 2002::/16 */
-               .prefix = &(struct in6_addr){{{ 0x20, 0x02 }}},
+       }, {    /* 2002::/16 */
+               .prefix = &(struct in6_addr){ { { 0x20, 0x02 } } },
                .prefixlen = 16,
                .label = 2,
-       },    /* 3ffe::/16 */
-               .prefix = &(struct in6_addr){{{ 0x3f, 0xfe }}},
+       }, {    /* 3ffe::/16 */
+               .prefix = &(struct in6_addr){ { { 0x3f, 0xfe } } },
                .prefixlen = 16,
                .label = 12,
-       },    /* 2001::/32 */
-               .prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
+       }, {    /* 2001::/32 */
+               .prefix = &(struct in6_addr){ { { 0x20, 0x01 } } },
                .prefixlen = 32,
                .label = 6,
-       },    /* 2001:10::/28 */
-               .prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}},
+       }, {    /* 2001:10::/28 */
+               .prefix = &(struct in6_addr){ { { 0x20, 0x01, 0x00, 0x10 } } },
                .prefixlen = 28,
                .label = 7,
-       },    /* ::ffff:0:0 */
-               .prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}},
+       }, {    /* ::ffff:0:0 */
+               .prefix = &(struct in6_addr){ { { [10] = 0xff, [11] = 0xff } } },
                .prefixlen = 96,
                .label = 4,
-       },    /* ::/96 */
+       }, {    /* ::/96 */
                .prefix = &in6addr_any,
                .prefixlen = 96,
                .label = 3,
-       },    /* ::1/128 */
+       }, {    /* ::1/128 */
                .prefix = &in6addr_loopback,
                .prefixlen = 128,
                .label = 0,
@@ -441,7 +440,7 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh)
        if (label == IPV6_ADDR_LABEL_DEFAULT)
                return -EINVAL;
 
-       switch(nlh->nlmsg_type) {
+       switch (nlh->nlmsg_type) {
        case RTM_NEWADDRLABEL:
                if (ifal->ifal_index &&
                    !__dev_get_by_index(net, ifal->ifal_index))
@@ -505,12 +504,13 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
        hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) {
                if (idx >= s_idx &&
                    net_eq(ip6addrlbl_net(p), net)) {
-                       if ((err = ip6addrlbl_fill(skb, p,
-                                                  ip6addrlbl_table.seq,
-                                                  NETLINK_CB(cb->skb).portid,
-                                                  cb->nlh->nlmsg_seq,
-                                                  RTM_NEWADDRLABEL,
-                                                  NLM_F_MULTI)) <= 0)
+                       err = ip6addrlbl_fill(skb, p,
+                                             ip6addrlbl_table.seq,
+                                             NETLINK_CB(cb->skb).portid,
+                                             cb->nlh->nlmsg_seq,
+                                             RTM_NEWADDRLABEL,
+                                             NLM_F_MULTI);
+                       if (err <= 0)
                                break;
                }
                idx++;
@@ -527,7 +527,7 @@ static inline int ip6addrlbl_msgsize(void)
                + nla_total_size(4);    /* IFAL_LABEL */
 }
 
-static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdrnlh)
+static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh)
 {
        struct net *net = sock_net(in_skb->sk);
        struct ifaddrlblmsg *ifal;
@@ -568,7 +568,8 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh)
                goto out;
        }
 
-       if (!(skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL))) {
+       skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL);
+       if (!skb) {
                ip6addrlbl_put(p);
                return -ENOBUFS;
        }
index 81e496a2e0083c42fe94729a486647aa23c8aed0..72a4930bdc0a0e0d43e1a6ad8670e6a1df1608f4 100644 (file)
@@ -346,6 +346,10 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
        struct ip_auth_hdr *ah;
        struct ah_data *ahp;
        struct tmp_ext *iph_ext;
+       int seqhi_len = 0;
+       __be32 *seqhi;
+       int sglists = 0;
+       struct scatterlist *seqhisg;
 
        ahp = x->data;
        ahash = ahp->ahash;
@@ -359,15 +363,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
        if (extlen)
                extlen += sizeof(*iph_ext);
 
+       if (x->props.flags & XFRM_STATE_ESN) {
+               sglists = 1;
+               seqhi_len = sizeof(*seqhi);
+       }
        err = -ENOMEM;
-       iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen);
+       iph_base = ah_alloc_tmp(ahash, nfrags + sglists, IPV6HDR_BASELEN +
+                               extlen + seqhi_len);
        if (!iph_base)
                goto out;
 
        iph_ext = ah_tmp_ext(iph_base);
-       icv = ah_tmp_icv(ahash, iph_ext, extlen);
+       seqhi = (__be32 *)((char *)iph_ext + extlen);
+       icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
        req = ah_tmp_req(ahash, icv);
        sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
 
        ah = ip_auth_hdr(skb);
        memset(ah->auth_data, 0, ahp->icv_trunc_len);
@@ -411,10 +422,15 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
        ah->spi = x->id.spi;
        ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
 
-       sg_init_table(sg, nfrags);
-       skb_to_sgvec(skb, sg, 0, skb->len);
+       sg_init_table(sg, nfrags + sglists);
+       skb_to_sgvec_nomark(skb, sg, 0, skb->len);
 
-       ahash_request_set_crypt(req, sg, icv, skb->len);
+       if (x->props.flags & XFRM_STATE_ESN) {
+               /* Attach seqhi sg right after packet payload */
+               *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
+               sg_set_buf(seqhisg, seqhi, seqhi_len);
+       }
+       ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
        ahash_request_set_callback(req, 0, ah6_output_done, skb);
 
        AH_SKB_CB(skb)->tmp = iph_base;
@@ -514,6 +530,10 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
        int nexthdr;
        int nfrags;
        int err = -ENOMEM;
+       int seqhi_len = 0;
+       __be32 *seqhi;
+       int sglists = 0;
+       struct scatterlist *seqhisg;
 
        if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
                goto out;
@@ -550,14 +570,22 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 
        skb_push(skb, hdr_len);
 
-       work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len);
+       if (x->props.flags & XFRM_STATE_ESN) {
+               sglists = 1;
+               seqhi_len = sizeof(*seqhi);
+       }
+
+       work_iph = ah_alloc_tmp(ahash, nfrags + sglists, hdr_len +
+                               ahp->icv_trunc_len + seqhi_len);
        if (!work_iph)
                goto out;
 
-       auth_data = ah_tmp_auth(work_iph, hdr_len);
-       icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
+       auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len);
+       seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
+       icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
        req = ah_tmp_req(ahash, icv);
        sg = ah_req_sg(ahash, req);
+       seqhisg = sg + nfrags;
 
        memcpy(work_iph, ip6h, hdr_len);
        memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
@@ -572,10 +600,16 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
        ip6h->flow_lbl[2] = 0;
        ip6h->hop_limit   = 0;
 
-       sg_init_table(sg, nfrags);
-       skb_to_sgvec(skb, sg, 0, skb->len);
+       sg_init_table(sg, nfrags + sglists);
+       skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+
+       if (x->props.flags & XFRM_STATE_ESN) {
+               /* Attach seqhi sg right after packet payload */
+               *seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
+               sg_set_buf(seqhisg, seqhi, seqhi_len);
+       }
 
-       ahash_request_set_crypt(req, sg, icv, skb->len);
+       ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
        ahash_request_set_callback(req, 0, ah6_input_done, skb);
 
        AH_SKB_CB(skb)->tmp = work_iph;
@@ -609,8 +643,8 @@ out:
        return err;
 }
 
-static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                   u8 type, u8 code, int offset, __be32 info)
+static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                  u8 type, u8 code, int offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
        struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
@@ -619,17 +653,19 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        if (type != ICMPV6_PKT_TOOBIG &&
            type != NDISC_REDIRECT)
-               return;
+               return 0;
 
        x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6);
        if (!x)
-               return;
+               return 0;
 
        if (type == NDISC_REDIRECT)
                ip6_redirect(skb, net, skb->dev->ifindex, 0);
        else
                ip6_update_pmtu(skb, net, info, 0, 0);
        xfrm_state_put(x);
+
+       return 0;
 }
 
 static int ah6_init_state(struct xfrm_state *x)
@@ -714,6 +750,11 @@ static void ah6_destroy(struct xfrm_state *x)
        kfree(ahp);
 }
 
+static int ah6_rcv_cb(struct sk_buff *skb, int err)
+{
+       return 0;
+}
+
 static const struct xfrm_type ah6_type =
 {
        .description    = "AH6",
@@ -727,10 +768,11 @@ static const struct xfrm_type ah6_type =
        .hdr_offset     = xfrm6_find_1stfragopt,
 };
 
-static const struct inet6_protocol ah6_protocol = {
+static struct xfrm6_protocol ah6_protocol = {
        .handler        =       xfrm6_rcv,
+       .cb_handler     =       ah6_rcv_cb,
        .err_handler    =       ah6_err,
-       .flags          =       INET6_PROTO_NOPOLICY,
+       .priority       =       0,
 };
 
 static int __init ah6_init(void)
@@ -740,7 +782,7 @@ static int __init ah6_init(void)
                return -EAGAIN;
        }
 
-       if (inet6_add_protocol(&ah6_protocol, IPPROTO_AH) < 0) {
+       if (xfrm6_protocol_register(&ah6_protocol, IPPROTO_AH) < 0) {
                pr_info("%s: can't add protocol\n", __func__);
                xfrm_unregister_type(&ah6_type, AF_INET6);
                return -EAGAIN;
@@ -751,7 +793,7 @@ static int __init ah6_init(void)
 
 static void __exit ah6_fini(void)
 {
-       if (inet6_del_protocol(&ah6_protocol, IPPROTO_AH) < 0)
+       if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0)
                pr_info("%s: can't remove protocol\n", __func__);
 
        if (xfrm_unregister_type(&ah6_type, AF_INET6) < 0)
index 6eef8a7e35f2c54514e6bbb8871d18ff18ae691e..d15da1377149d3a0fdf846a7a07364e6d1251845 100644 (file)
@@ -421,8 +421,8 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
                 net_adj) & ~(blksize - 1)) + net_adj - 2;
 }
 
-static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
-                    u8 type, u8 code, int offset, __be32 info)
+static int esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                   u8 type, u8 code, int offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
        const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
@@ -431,18 +431,20 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        if (type != ICMPV6_PKT_TOOBIG &&
            type != NDISC_REDIRECT)
-               return;
+               return 0;
 
        x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
                              esph->spi, IPPROTO_ESP, AF_INET6);
        if (!x)
-               return;
+               return 0;
 
        if (type == NDISC_REDIRECT)
                ip6_redirect(skb, net, skb->dev->ifindex, 0);
        else
                ip6_update_pmtu(skb, net, info, 0, 0);
        xfrm_state_put(x);
+
+       return 0;
 }
 
 static void esp6_destroy(struct xfrm_state *x)
@@ -614,6 +616,11 @@ error:
        return err;
 }
 
+static int esp6_rcv_cb(struct sk_buff *skb, int err)
+{
+       return 0;
+}
+
 static const struct xfrm_type esp6_type =
 {
        .description    = "ESP6",
@@ -628,10 +635,11 @@ static const struct xfrm_type esp6_type =
        .hdr_offset     = xfrm6_find_1stfragopt,
 };
 
-static const struct inet6_protocol esp6_protocol = {
-       .handler        =       xfrm6_rcv,
+static struct xfrm6_protocol esp6_protocol = {
+       .handler        =       xfrm6_rcv,
+       .cb_handler     =       esp6_rcv_cb,
        .err_handler    =       esp6_err,
-       .flags          =       INET6_PROTO_NOPOLICY,
+       .priority       =       0,
 };
 
 static int __init esp6_init(void)
@@ -640,7 +648,7 @@ static int __init esp6_init(void)
                pr_info("%s: can't add xfrm type\n", __func__);
                return -EAGAIN;
        }
-       if (inet6_add_protocol(&esp6_protocol, IPPROTO_ESP) < 0) {
+       if (xfrm6_protocol_register(&esp6_protocol, IPPROTO_ESP) < 0) {
                pr_info("%s: can't add protocol\n", __func__);
                xfrm_unregister_type(&esp6_type, AF_INET6);
                return -EAGAIN;
@@ -651,7 +659,7 @@ static int __init esp6_init(void)
 
 static void __exit esp6_fini(void)
 {
-       if (inet6_del_protocol(&esp6_protocol, IPPROTO_ESP) < 0)
+       if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0)
                pr_info("%s: can't remove protocol\n", __func__);
        if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0)
                pr_info("%s: can't remove xfrm type\n", __func__);
index 140748debc4ade194e5e179636e94264da7e65a1..8af3eb57f4380fd7de7497ff98f40c88f2040e50 100644 (file)
@@ -212,7 +212,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                found = (nexthdr == target);
 
                if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) {
-                       if (target < 0)
+                       if (target < 0 || found)
                                break;
                        return -ENOENT;
                }
index cf77f3abfd061280f6a211deb4a24bcd247c944a..447a7fbd1bb6f28dc78203ef4f4254705dc68c99 100644 (file)
@@ -25,11 +25,11 @@ int __init ipv6_exthdrs_offload_init(void)
        int ret;
 
        ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
-       if (!ret)
+       if (ret)
                goto out;
 
        ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
-       if (!ret)
+       if (ret)
                goto out_rt;
 
 out:
index f81f59686f21b222047793f0c72c99ce3ceaa82d..f2610e15766027ce3a7408862d03f4c427c555ea 100644 (file)
@@ -414,7 +414,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
        addr_type = ipv6_addr_type(&hdr->daddr);
 
        if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) ||
-           ipv6_anycast_destination(skb))
+           ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr))
                saddr = &hdr->daddr;
 
        /*
index 72d198b8e4d2966d81fc5c183b12333e49e56d3f..ee7a97f510cbd9f94fa24eafa43ddba201c75f3e 100644 (file)
@@ -79,7 +79,9 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
                /* RFC 2460 section 8.1 says that we SHOULD log
                   this error. Well, it is reasonable.
                 */
-               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
+               LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n",
+                              &ipv6_hdr(skb)->saddr, ntohs(uh->source),
+                              &ipv6_hdr(skb)->daddr, ntohs(uh->dest));
                return 1;
        }
        if (skb->ip_summed == CHECKSUM_COMPLETE &&
index 075602fc6b6a915f15a7039cf1daaa640e02ce82..34e0ded5c14b028ebbb1bb03c1b30e8f25f98811 100644 (file)
@@ -9,14 +9,12 @@
  *      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.
- */
-
-/*
- *     Changes:
- *     Yuji SEKIYA @USAGI:     Support default route on router node;
- *                             remove ip6_null_entry from the top of
- *                             routing table.
- *     Ville Nuorvala:         Fixed routing subtrees.
+ *
+ *     Changes:
+ *     Yuji SEKIYA @USAGI:     Support default route on router node;
+ *                             remove ip6_null_entry from the top of
+ *                             routing table.
+ *     Ville Nuorvala:         Fixed routing subtrees.
  */
 
 #define pr_fmt(fmt) "IPv6: " fmt
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
-static struct kmem_cache * fib6_node_kmem __read_mostly;
+static struct kmem_cache *fib6_node_kmem __read_mostly;
 
-enum fib_walk_state_t
-{
+enum fib_walk_state_t {
 #ifdef CONFIG_IPV6_SUBTREES
        FWS_S,
 #endif
@@ -59,8 +56,7 @@ enum fib_walk_state_t
        FWS_U
 };
 
-struct fib6_cleaner_t
-{
+struct fib6_cleaner_t {
        struct fib6_walker_t w;
        struct net *net;
        int (*func)(struct rt6_info *, void *arg);
@@ -138,7 +134,7 @@ static __inline__ __be32 addr_bit_set(const void *token, int fn_bit)
        const __be32 *addr = token;
        /*
         * Here,
-        *      1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)
+        *      1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)
         * is optimized version of
         *      htonl(1 << ((~fn_bit)&0x1F))
         * See include/asm-generic/bitops/le.h.
@@ -147,7 +143,7 @@ static __inline__ __be32 addr_bit_set(const void *token, int fn_bit)
               addr[fn_bit >> 5];
 }
 
-static __inline__ struct fib6_node * node_alloc(void)
+static __inline__ struct fib6_node *node_alloc(void)
 {
        struct fib6_node *fn;
 
@@ -156,7 +152,7 @@ static __inline__ struct fib6_node * node_alloc(void)
        return fn;
 }
 
-static __inline__ void node_free(struct fib6_node * fn)
+static __inline__ void node_free(struct fib6_node *fn)
 {
        kmem_cache_free(fib6_node_kmem, fn);
 }
@@ -292,7 +288,7 @@ static int fib6_dump_node(struct fib6_walker_t *w)
 
 static void fib6_dump_end(struct netlink_callback *cb)
 {
-       struct fib6_walker_t *w = (void*)cb->args[2];
+       struct fib6_walker_t *w = (void *)cb->args[2];
 
        if (w) {
                if (cb->args[4]) {
@@ -302,7 +298,7 @@ static void fib6_dump_end(struct netlink_callback *cb)
                cb->args[2] = 0;
                kfree(w);
        }
-       cb->done = (void*)cb->args[3];
+       cb->done = (void *)cb->args[3];
        cb->args[1] = 3;
 }
 
@@ -485,7 +481,7 @@ static struct fib6_node *fib6_add_1(struct fib6_node *root,
                fn->fn_sernum = sernum;
                dir = addr_bit_set(addr, fn->fn_bit);
                pn = fn;
-               fn = dir ? fn->right: fn->left;
+               fn = dir ? fn->right : fn->left;
        } while (fn);
 
        if (!allow_create) {
@@ -638,12 +634,41 @@ static inline bool rt6_qualify_for_ecmp(struct rt6_info *rt)
               RTF_GATEWAY;
 }
 
+static int fib6_commit_metrics(struct dst_entry *dst,
+                              struct nlattr *mx, int mx_len)
+{
+       struct nlattr *nla;
+       int remaining;
+       u32 *mp;
+
+       if (dst->flags & DST_HOST) {
+               mp = dst_metrics_write_ptr(dst);
+       } else {
+               mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
+               if (!mp)
+                       return -ENOMEM;
+               dst_init_metrics(dst, mp, 0);
+       }
+
+       nla_for_each_attr(nla, mx, mx_len, remaining) {
+               int type = nla_type(nla);
+
+               if (type) {
+                       if (type > RTAX_MAX)
+                               return -EINVAL;
+
+                       mp[type - 1] = nla_get_u32(nla);
+               }
+       }
+       return 0;
+}
+
 /*
  *     Insert routing information in a node.
  */
 
 static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
-                           struct nl_info *info)
+                           struct nl_info *info, struct nlattr *mx, int mx_len)
 {
        struct rt6_info *iter = NULL;
        struct rt6_info **ins;
@@ -653,6 +678,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                   (info->nlh->nlmsg_flags & NLM_F_CREATE));
        int found = 0;
        bool rt_can_ecmp = rt6_qualify_for_ecmp(rt);
+       int err;
 
        ins = &fn->leaf;
 
@@ -751,6 +777,11 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
                        pr_warn("NLM_F_CREATE should be set when creating new route\n");
 
 add:
+               if (mx) {
+                       err = fib6_commit_metrics(&rt->dst, mx, mx_len);
+                       if (err)
+                               return err;
+               }
                rt->dst.rt6_next = iter;
                *ins = rt;
                rt->rt6i_node = fn;
@@ -770,6 +801,11 @@ add:
                        pr_warn("NLM_F_REPLACE set, but no existing node found!\n");
                        return -ENOENT;
                }
+               if (mx) {
+                       err = fib6_commit_metrics(&rt->dst, mx, mx_len);
+                       if (err)
+                               return err;
+               }
                *ins = rt;
                rt->rt6i_node = fn;
                rt->dst.rt6_next = iter->dst.rt6_next;
@@ -806,7 +842,8 @@ void fib6_force_start_gc(struct net *net)
  *     with source addr info in sub-trees
  */
 
-int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
+int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info,
+            struct nlattr *mx, int mx_len)
 {
        struct fib6_node *fn, *pn = NULL;
        int err = -ENOMEM;
@@ -900,7 +937,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
        }
 #endif
 
-       err = fib6_add_rt2node(fn, rt, info);
+       err = fib6_add_rt2node(fn, rt, info, mx, mx_len);
        if (!err) {
                fib6_start_gc(info->nl_net, rt);
                if (!(rt->rt6i_flags & RTF_CACHE))
@@ -955,8 +992,8 @@ struct lookup_args {
        const struct in6_addr   *addr;          /* search key                   */
 };
 
-static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
-                                       struct lookup_args *args)
+static struct fib6_node *fib6_lookup_1(struct fib6_node *root,
+                                      struct lookup_args *args)
 {
        struct fib6_node *fn;
        __be32 dir;
@@ -1018,8 +1055,8 @@ backtrack:
        return NULL;
 }
 
-struct fib6_node * fib6_lookup(struct fib6_node *root, const struct in6_addr *daddr,
-                              const struct in6_addr *saddr)
+struct fib6_node *fib6_lookup(struct fib6_node *root, const struct in6_addr *daddr,
+                             const struct in6_addr *saddr)
 {
        struct fib6_node *fn;
        struct lookup_args args[] = {
@@ -1051,9 +1088,9 @@ struct fib6_node * fib6_lookup(struct fib6_node *root, const struct in6_addr *da
  */
 
 
-static struct fib6_node * fib6_locate_1(struct fib6_node *root,
-                                       const struct in6_addr *addr,
-                                       int plen, int offset)
+static struct fib6_node *fib6_locate_1(struct fib6_node *root,
+                                      const struct in6_addr *addr,
+                                      int plen, int offset)
 {
        struct fib6_node *fn;
 
@@ -1081,9 +1118,9 @@ static struct fib6_node * fib6_locate_1(struct fib6_node *root,
        return NULL;
 }
 
-struct fib6_node * fib6_locate(struct fib6_node *root,
-                              const struct in6_addr *daddr, int dst_len,
-                              const struct in6_addr *saddr, int src_len)
+struct fib6_node *fib6_locate(struct fib6_node *root,
+                             const struct in6_addr *daddr, int dst_len,
+                             const struct in6_addr *saddr, int src_len)
 {
        struct fib6_node *fn;
 
@@ -1151,8 +1188,10 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
 
                children = 0;
                child = NULL;
-               if (fn->right) child = fn->right, children |= 1;
-               if (fn->left) child = fn->left, children |= 2;
+               if (fn->right)
+                       child = fn->right, children |= 1;
+               if (fn->left)
+                       child = fn->left, children |= 2;
 
                if (children == 3 || FIB6_SUBTREE(fn)
 #ifdef CONFIG_IPV6_SUBTREES
@@ -1180,8 +1219,10 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                } else {
                        WARN_ON(fn->fn_flags & RTN_ROOT);
 #endif
-                       if (pn->right == fn) pn->right = child;
-                       else if (pn->left == fn) pn->left = child;
+                       if (pn->right == fn)
+                               pn->right = child;
+                       else if (pn->left == fn)
+                               pn->left = child;
 #if RT6_DEBUG >= 2
                        else
                                WARN_ON(1);
@@ -1213,10 +1254,10 @@ static struct fib6_node *fib6_repair_tree(struct net *net,
                                        w->node = child;
                                        if (children&2) {
                                                RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
-                                               w->state = w->state>=FWS_R ? FWS_U : FWS_INIT;
+                                               w->state = w->state >= FWS_R ? FWS_U : FWS_INIT;
                                        } else {
                                                RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state);
-                                               w->state = w->state>=FWS_C ? FWS_U : FWS_INIT;
+                                               w->state = w->state >= FWS_C ? FWS_U : FWS_INIT;
                                        }
                                }
                        }
@@ -1314,7 +1355,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
        struct rt6_info **rtp;
 
 #if RT6_DEBUG >= 2
-       if (rt->dst.obsolete>0) {
+       if (rt->dst.obsolete > 0) {
                WARN_ON(fn != NULL);
                return -ENOENT;
        }
@@ -1707,7 +1748,7 @@ out_rt6_stats:
        kfree(net->ipv6.rt6_stats);
 out_timer:
        return -ENOMEM;
- }
+}
 
 static void fib6_net_exit(struct net *net)
 {
index dfa41bb4e0dc0a97a9de933716ef9dbbabe5475d..0961b5ef866d04803cf91243aec32bb9e2ea8cf7 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/socket.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
-#include <linux/if_arp.h>
 #include <linux/in6.h>
-#include <linux/route.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <net/sock.h>
 
 #include <net/ipv6.h>
-#include <net/ndisc.h>
-#include <net/protocol.h>
-#include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <net/rawv6.h>
-#include <net/icmp.h>
 #include <net/transp_v6.h>
 
 #include <asm/uaccess.h>
index f3ffb43f59c08634187f939db338413dd9a5514f..c98338b81d30779f9410ea413eb359d72a7dd76e 100644 (file)
@@ -1454,7 +1454,6 @@ static void ip6gre_netlink_parms(struct nlattr *data[],
 static int ip6gre_tap_init(struct net_device *dev)
 {
        struct ip6_tnl *tunnel;
-       int i;
 
        tunnel = netdev_priv(dev);
 
@@ -1464,16 +1463,10 @@ static int ip6gre_tap_init(struct net_device *dev)
 
        ip6gre_tnl_link_config(tunnel, 1);
 
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *ip6gre_tap_stats;
-               ip6gre_tap_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&ip6gre_tap_stats->syncp);
-       }
-
        return 0;
 }
 
index 1e8683b135bb7b503d9ab97d5c3c165af2453fa1..59f95affceb0773d052184bdf5fec9f276433d63 100644 (file)
@@ -89,7 +89,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        unsigned int unfrag_ip6hlen;
        u8 *prevhdr;
        int offset = 0;
-       bool tunnel;
+       bool encap, udpfrag;
        int nhoff;
 
        if (unlikely(skb_shinfo(skb)->gso_type &
@@ -110,8 +110,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
                goto out;
 
-       tunnel = SKB_GSO_CB(skb)->encap_level > 0;
-       if (tunnel)
+       encap = SKB_GSO_CB(skb)->encap_level > 0;
+       if (encap)
                features = skb->dev->hw_enc_features & netif_skb_features(skb);
        SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h);
 
@@ -121,6 +121,12 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
 
        proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
 
+       if (skb->encapsulation &&
+           skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP))
+               udpfrag = proto == IPPROTO_UDP && encap;
+       else
+               udpfrag = proto == IPPROTO_UDP && !skb->encapsulation;
+
        ops = rcu_dereference(inet6_offloads[proto]);
        if (likely(ops && ops->callbacks.gso_segment)) {
                skb_reset_transport_header(skb);
@@ -133,13 +139,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
        for (skb = segs; skb; skb = skb->next) {
                ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff);
                ipv6h->payload_len = htons(skb->len - nhoff - sizeof(*ipv6h));
-               if (tunnel) {
-                       skb_reset_inner_headers(skb);
-                       skb->encapsulation = 1;
-               }
                skb->network_header = (u8 *)ipv6h - skb->head;
 
-               if (!tunnel && proto == IPPROTO_UDP) {
+               if (udpfrag) {
                        unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
                        fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
                        fptr->frag_off = htons(offset);
@@ -148,6 +150,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
                        offset += (ntohs(ipv6h->payload_len) -
                                   sizeof(struct frag_hdr));
                }
+               if (encap)
+                       skb_reset_inner_headers(skb);
        }
 
 out:
index ef02b26ccf812e57e794e9b151746600bcb9a8f0..6184dfa4e4d7b4f2080f2b007b743f43768fc212 100644 (file)
@@ -342,6 +342,20 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
        return mtu;
 }
 
+static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
+{
+       if (skb->len <= mtu || skb->local_df)
+               return false;
+
+       if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)
+               return true;
+
+       if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu)
+               return false;
+
+       return true;
+}
+
 int ip6_forward(struct sk_buff *skb)
 {
        struct dst_entry *dst = skb_dst(skb);
@@ -353,6 +367,9 @@ int ip6_forward(struct sk_buff *skb)
        if (net->ipv6.devconf_all->forwarding == 0)
                goto error;
 
+       if (skb->pkt_type != PACKET_HOST)
+               goto drop;
+
        if (skb_warn_if_lro(skb))
                goto drop;
 
@@ -362,9 +379,6 @@ int ip6_forward(struct sk_buff *skb)
                goto drop;
        }
 
-       if (skb->pkt_type != PACKET_HOST)
-               goto drop;
-
        skb_forward_csum(skb);
 
        /*
@@ -466,8 +480,7 @@ int ip6_forward(struct sk_buff *skb)
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
 
-       if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
-           (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
+       if (ip6_pkt_too_big(skb, mtu)) {
                /* Again, force OUTPUT device used as source address */
                skb->dev = dst->dev;
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -517,9 +530,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
        to->tc_index = from->tc_index;
 #endif
        nf_copy(to, from);
-#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
-       to->nf_trace = from->nf_trace;
-#endif
        skb_copy_secmark(to, from);
 }
 
@@ -1091,21 +1101,19 @@ static void ip6_append_data_mtu(unsigned int *mtu,
                                unsigned int fragheaderlen,
                                struct sk_buff *skb,
                                struct rt6_info *rt,
-                               bool pmtuprobe)
+                               unsigned int orig_mtu)
 {
        if (!(rt->dst.flags & DST_XFRM_TUNNEL)) {
                if (skb == NULL) {
                        /* first fragment, reserve header_len */
-                       *mtu = *mtu - rt->dst.header_len;
+                       *mtu = orig_mtu - rt->dst.header_len;
 
                } else {
                        /*
                         * this fragment is not first, the headers
                         * space is regarded as data space.
                         */
-                       *mtu = min(*mtu, pmtuprobe ?
-                                  rt->dst.dev->mtu :
-                                  dst_mtu(rt->dst.path));
+                       *mtu = orig_mtu;
                }
                *maxfraglen = ((*mtu - fragheaderlen) & ~7)
                              + fragheaderlen - sizeof(struct frag_hdr);
@@ -1122,7 +1130,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
        struct ipv6_pinfo *np = inet6_sk(sk);
        struct inet_cork *cork;
        struct sk_buff *skb, *skb_prev = NULL;
-       unsigned int maxfraglen, fragheaderlen, mtu;
+       unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
        int exthdrlen;
        int dst_exthdrlen;
        int hh_len;
@@ -1204,6 +1212,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                dst_exthdrlen = 0;
                mtu = cork->fragsize;
        }
+       orig_mtu = mtu;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
 
@@ -1221,8 +1230,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                              sizeof(struct frag_hdr) : 0) +
                             rt->rt6i_nfheader_len;
 
-               maxnonfragsize = (np->pmtudisc >= IPV6_PMTUDISC_DO) ?
-                                mtu : sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
+               if (ip6_sk_local_df(sk))
+                       maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN;
+               else
+                       maxnonfragsize = mtu;
 
                /* dontfrag active */
                if ((cork->length + length > mtu - headersize) && dontfrag &&
@@ -1301,8 +1312,7 @@ alloc_new_skb:
                        if (skb == NULL || skb_prev == NULL)
                                ip6_append_data_mtu(&mtu, &maxfraglen,
                                                    fragheaderlen, skb, rt,
-                                                   np->pmtudisc >=
-                                                   IPV6_PMTUDISC_PROBE);
+                                                   orig_mtu);
 
                        skb_prev = skb;
 
@@ -1530,8 +1540,7 @@ int ip6_push_pending_frames(struct sock *sk)
        }
 
        /* Allow local fragmentation. */
-       if (np->pmtudisc < IPV6_PMTUDISC_DO)
-               skb->local_df = 1;
+       skb->local_df = ip6_sk_local_df(sk);
 
        *final_dst = fl6->daddr;
        __skb_pull(skb, skb_network_header_len(skb));
index 5db8d310f9c07adc656dff9e3e909f611dbc1b1b..e1df691d78befcb2bb041244ed3370b44667b40d 100644 (file)
@@ -108,12 +108,12 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
                                                   per_cpu_ptr(dev->tstats, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
+                       start = u64_stats_fetch_begin_irq(&tstats->syncp);
                        tmp.rx_packets = tstats->rx_packets;
                        tmp.rx_bytes = tstats->rx_bytes;
                        tmp.tx_packets = tstats->tx_packets;
                        tmp.tx_bytes =  tstats->tx_bytes;
-               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
 
                sum.rx_packets += tmp.rx_packets;
                sum.rx_bytes   += tmp.rx_bytes;
@@ -1502,19 +1502,12 @@ static inline int
 ip6_tnl_dev_init_gen(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
-       int i;
 
        t->dev = dev;
        t->net = dev_net(dev);
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
-
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *ip6_tnl_stats;
-               ip6_tnl_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&ip6_tnl_stats->syncp);
-       }
        return 0;
 }
 
index 2d19272b8ceea6ade3b935904a7e7903d20a2a2a..b7c0f827140b402685cc29049cb56646471c2cf2 100644 (file)
@@ -278,7 +278,6 @@ static void vti6_dev_uninit(struct net_device *dev)
                RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
        else
                vti6_tnl_unlink(ip6n, t);
-       ip6_tnl_dst_reset(t);
        dev_put(dev);
 }
 
@@ -288,11 +287,8 @@ static int vti6_rcv(struct sk_buff *skb)
        const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
 
        rcu_read_lock();
-
        if ((t = vti6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr,
                                 &ipv6h->daddr)) != NULL) {
-               struct pcpu_sw_netstats *tstats;
-
                if (t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) {
                        rcu_read_unlock();
                        goto discard;
@@ -309,27 +305,58 @@ static int vti6_rcv(struct sk_buff *skb)
                        goto discard;
                }
 
-               tstats = this_cpu_ptr(t->dev->tstats);
-               u64_stats_update_begin(&tstats->syncp);
-               tstats->rx_packets++;
-               tstats->rx_bytes += skb->len;
-               u64_stats_update_end(&tstats->syncp);
-
-               skb->mark = 0;
-               secpath_reset(skb);
-               skb->dev = t->dev;
+               XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t;
+               skb->mark = be32_to_cpu(t->parms.i_key);
 
                rcu_read_unlock();
-               return 0;
+
+               return xfrm6_rcv(skb);
        }
        rcu_read_unlock();
-       return 1;
-
+       return -EINVAL;
 discard:
        kfree_skb(skb);
        return 0;
 }
 
+static int vti6_rcv_cb(struct sk_buff *skb, int err)
+{
+       unsigned short family;
+       struct net_device *dev;
+       struct pcpu_sw_netstats *tstats;
+       struct xfrm_state *x;
+       struct ip6_tnl *t = XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6;
+
+       if (!t)
+               return 1;
+
+       dev = t->dev;
+
+       if (err) {
+               dev->stats.rx_errors++;
+               dev->stats.rx_dropped++;
+
+               return 0;
+       }
+
+       x = xfrm_input_state(skb);
+       family = x->inner_mode->afinfo->family;
+
+       if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family))
+               return -EPERM;
+
+       skb_scrub_packet(skb, !net_eq(t->net, dev_net(skb->dev)));
+       skb->dev = dev;
+
+       tstats = this_cpu_ptr(dev->tstats);
+       u64_stats_update_begin(&tstats->syncp);
+       tstats->rx_packets++;
+       tstats->rx_bytes += skb->len;
+       u64_stats_update_end(&tstats->syncp);
+
+       return 0;
+}
+
 /**
  * vti6_addr_conflict - compare packet addresses to tunnel's own
  *   @t: the outgoing tunnel device
@@ -349,44 +376,56 @@ vti6_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
        return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
 }
 
+static bool vti6_state_check(const struct xfrm_state *x,
+                            const struct in6_addr *dst,
+                            const struct in6_addr *src)
+{
+       xfrm_address_t *daddr = (xfrm_address_t *)dst;
+       xfrm_address_t *saddr = (xfrm_address_t *)src;
+
+       /* if there is no transform then this tunnel is not functional.
+        * Or if the xfrm is not mode tunnel.
+        */
+       if (!x || x->props.mode != XFRM_MODE_TUNNEL ||
+           x->props.family != AF_INET6)
+               return false;
+
+       if (ipv6_addr_any(dst))
+               return xfrm_addr_equal(saddr, &x->props.saddr, AF_INET6);
+
+       if (!xfrm_state_addr_check(x, daddr, saddr, AF_INET6))
+               return false;
+
+       return true;
+}
+
 /**
  * vti6_xmit - send a packet
  *   @skb: the outgoing socket buffer
  *   @dev: the outgoing tunnel device
+ *   @fl: the flow informations for the xfrm_lookup
  **/
-static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
+static int
+vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
 {
-       struct net *net = dev_net(dev);
        struct ip6_tnl *t = netdev_priv(dev);
        struct net_device_stats *stats = &t->dev->stats;
-       struct dst_entry *dst = NULL, *ndst = NULL;
-       struct flowi6 fl6;
-       struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+       struct dst_entry *dst = skb_dst(skb);
        struct net_device *tdev;
        int err = -1;
 
-       if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
-           !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
-               return err;
-
-       dst = ip6_tnl_dst_check(t);
-       if (!dst) {
-               memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
-
-               ndst = ip6_route_output(net, NULL, &fl6);
+       if (!dst)
+               goto tx_err_link_failure;
 
-               if (ndst->error)
-                       goto tx_err_link_failure;
-               ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(&fl6), NULL, 0);
-               if (IS_ERR(ndst)) {
-                       err = PTR_ERR(ndst);
-                       ndst = NULL;
-                       goto tx_err_link_failure;
-               }
-               dst = ndst;
+       dst_hold(dst);
+       dst = xfrm_lookup(t->net, dst, fl, NULL, 0);
+       if (IS_ERR(dst)) {
+               err = PTR_ERR(dst);
+               dst = NULL;
+               goto tx_err_link_failure;
        }
 
-       if (!dst->xfrm || dst->xfrm->props.mode != XFRM_MODE_TUNNEL)
+       if (!vti6_state_check(dst->xfrm, &t->parms.raddr, &t->parms.laddr))
                goto tx_err_link_failure;
 
        tdev = dst->dev;
@@ -398,14 +437,21 @@ static int vti6_xmit(struct sk_buff *skb, struct net_device *dev)
                goto tx_err_dst_release;
        }
 
+       skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
+       skb_dst_set(skb, dst);
+       skb->dev = skb_dst(skb)->dev;
 
-       skb_dst_drop(skb);
-       skb_dst_set_noref(skb, dst);
+       err = dst_output(skb);
+       if (net_xmit_eval(err) == 0) {
+               struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
 
-       ip6tunnel_xmit(skb, dev);
-       if (ndst) {
-               dev->mtu = dst_mtu(ndst);
-               ip6_tnl_dst_store(t, ndst);
+               u64_stats_update_begin(&tstats->syncp);
+               tstats->tx_bytes += skb->len;
+               tstats->tx_packets++;
+               u64_stats_update_end(&tstats->syncp);
+       } else {
+               stats->tx_errors++;
+               stats->tx_aborted_errors++;
        }
 
        return 0;
@@ -413,7 +459,7 @@ tx_err_link_failure:
        stats->tx_carrier_errors++;
        dst_link_failure(skb);
 tx_err_dst_release:
-       dst_release(ndst);
+       dst_release(dst);
        return err;
 }
 
@@ -422,16 +468,33 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
        struct net_device_stats *stats = &t->dev->stats;
+       struct ipv6hdr *ipv6h;
+       struct flowi fl;
        int ret;
 
+       memset(&fl, 0, sizeof(fl));
+       skb->mark = be32_to_cpu(t->parms.o_key);
+
        switch (skb->protocol) {
        case htons(ETH_P_IPV6):
-               ret = vti6_xmit(skb, dev);
+               ipv6h = ipv6_hdr(skb);
+
+               if ((t->parms.proto != IPPROTO_IPV6 && t->parms.proto != 0) ||
+                   !ip6_tnl_xmit_ctl(t) || vti6_addr_conflict(t, ipv6h))
+                       goto tx_err;
+
+               xfrm_decode_session(skb, &fl, AF_INET6);
+               memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+               break;
+       case htons(ETH_P_IP):
+               xfrm_decode_session(skb, &fl, AF_INET);
+               memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
                break;
        default:
                goto tx_err;
        }
 
+       ret = vti6_xmit(skb, dev, &fl);
        if (ret < 0)
                goto tx_err;
 
@@ -444,24 +507,66 @@ tx_err:
        return NETDEV_TX_OK;
 }
 
+static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                   u8 type, u8 code, int offset, __be32 info)
+{
+       __be32 spi;
+       struct xfrm_state *x;
+       struct ip6_tnl *t;
+       struct ip_esp_hdr *esph;
+       struct ip_auth_hdr *ah;
+       struct ip_comp_hdr *ipch;
+       struct net *net = dev_net(skb->dev);
+       const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
+       int protocol = iph->nexthdr;
+
+       t = vti6_tnl_lookup(dev_net(skb->dev), &iph->daddr, &iph->saddr);
+       if (!t)
+               return -1;
+
+       switch (protocol) {
+       case IPPROTO_ESP:
+               esph = (struct ip_esp_hdr *)(skb->data + offset);
+               spi = esph->spi;
+               break;
+       case IPPROTO_AH:
+               ah = (struct ip_auth_hdr *)(skb->data + offset);
+               spi = ah->spi;
+               break;
+       case IPPROTO_COMP:
+               ipch = (struct ip_comp_hdr *)(skb->data + offset);
+               spi = htonl(ntohs(ipch->cpi));
+               break;
+       default:
+               return 0;
+       }
+
+       if (type != ICMPV6_PKT_TOOBIG &&
+           type != NDISC_REDIRECT)
+               return 0;
+
+       x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
+                             spi, protocol, AF_INET6);
+       if (!x)
+               return 0;
+
+       if (type == NDISC_REDIRECT)
+               ip6_redirect(skb, net, skb->dev->ifindex, 0);
+       else
+               ip6_update_pmtu(skb, net, info, 0, 0);
+       xfrm_state_put(x);
+
+       return 0;
+}
+
 static void vti6_link_config(struct ip6_tnl *t)
 {
-       struct dst_entry *dst;
        struct net_device *dev = t->dev;
        struct __ip6_tnl_parm *p = &t->parms;
-       struct flowi6 *fl6 = &t->fl.u.ip6;
 
        memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
        memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
 
-       /* Set up flowi template */
-       fl6->saddr = p->laddr;
-       fl6->daddr = p->raddr;
-       fl6->flowi6_oif = p->link;
-       fl6->flowi6_mark = be32_to_cpu(p->i_key);
-       fl6->flowi6_proto = p->proto;
-       fl6->flowlabel = 0;
-
        p->flags &= ~(IP6_TNL_F_CAP_XMIT | IP6_TNL_F_CAP_RCV |
                      IP6_TNL_F_CAP_PER_PACKET);
        p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
@@ -472,28 +577,6 @@ static void vti6_link_config(struct ip6_tnl *t)
                dev->flags &= ~IFF_POINTOPOINT;
 
        dev->iflink = p->link;
-
-       if (p->flags & IP6_TNL_F_CAP_XMIT) {
-
-               dst = ip6_route_output(dev_net(dev), NULL, fl6);
-               if (dst->error)
-                       return;
-
-               dst = xfrm_lookup(dev_net(dev), dst, flowi6_to_flowi(fl6),
-                                 NULL, 0);
-               if (IS_ERR(dst))
-                       return;
-
-               if (dst->dev) {
-                       dev->hard_header_len = dst->dev->hard_header_len;
-
-                       dev->mtu = dst_mtu(dst);
-
-                       if (dev->mtu < IPV6_MIN_MTU)
-                               dev->mtu = IPV6_MIN_MTU;
-               }
-               dst_release(dst);
-       }
 }
 
 /**
@@ -720,7 +803,6 @@ static void vti6_dev_setup(struct net_device *dev)
        t = netdev_priv(dev);
        dev->flags |= IFF_NOARP;
        dev->addr_len = sizeof(struct in6_addr);
-       dev->features |= NETIF_F_NETNS_LOCAL;
        dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
 }
 
@@ -731,18 +813,12 @@ static void vti6_dev_setup(struct net_device *dev)
 static inline int vti6_dev_init_gen(struct net_device *dev)
 {
        struct ip6_tnl *t = netdev_priv(dev);
-       int i;
 
        t->dev = dev;
        t->net = dev_net(dev);
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *stats;
-               stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&stats->syncp);
-       }
        return 0;
 }
 
@@ -914,11 +990,6 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = {
        .fill_info      = vti6_fill_info,
 };
 
-static struct xfrm_tunnel_notifier vti6_handler __read_mostly = {
-       .handler        = vti6_rcv,
-       .priority       =       1,
-};
-
 static void __net_exit vti6_destroy_tunnels(struct vti6_net *ip6n)
 {
        int h;
@@ -990,6 +1061,27 @@ static struct pernet_operations vti6_net_ops = {
        .size = sizeof(struct vti6_net),
 };
 
+static struct xfrm6_protocol vti_esp6_protocol __read_mostly = {
+       .handler        =       vti6_rcv,
+       .cb_handler     =       vti6_rcv_cb,
+       .err_handler    =       vti6_err,
+       .priority       =       100,
+};
+
+static struct xfrm6_protocol vti_ah6_protocol __read_mostly = {
+       .handler        =       vti6_rcv,
+       .cb_handler     =       vti6_rcv_cb,
+       .err_handler    =       vti6_err,
+       .priority       =       100,
+};
+
+static struct xfrm6_protocol vti_ipcomp6_protocol __read_mostly = {
+       .handler        =       vti6_rcv,
+       .cb_handler     =       vti6_rcv_cb,
+       .err_handler    =       vti6_err,
+       .priority       =       100,
+};
+
 /**
  * vti6_tunnel_init - register protocol and reserve needed resources
  *
@@ -1003,11 +1095,33 @@ static int __init vti6_tunnel_init(void)
        if (err < 0)
                goto out_pernet;
 
-       err = xfrm6_mode_tunnel_input_register(&vti6_handler);
+       err = xfrm6_protocol_register(&vti_esp6_protocol, IPPROTO_ESP);
        if (err < 0) {
-               pr_err("%s: can't register vti6\n", __func__);
+               unregister_pernet_device(&vti6_net_ops);
+               pr_err("%s: can't register vti6 protocol\n", __func__);
+
                goto out;
        }
+
+       err = xfrm6_protocol_register(&vti_ah6_protocol, IPPROTO_AH);
+       if (err < 0) {
+               xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
+               unregister_pernet_device(&vti6_net_ops);
+               pr_err("%s: can't register vti6 protocol\n", __func__);
+
+               goto out;
+       }
+
+       err = xfrm6_protocol_register(&vti_ipcomp6_protocol, IPPROTO_COMP);
+       if (err < 0) {
+               xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
+               xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
+               unregister_pernet_device(&vti6_net_ops);
+               pr_err("%s: can't register vti6 protocol\n", __func__);
+
+               goto out;
+       }
+
        err = rtnl_link_register(&vti6_link_ops);
        if (err < 0)
                goto rtnl_link_failed;
@@ -1015,7 +1129,9 @@ static int __init vti6_tunnel_init(void)
        return 0;
 
 rtnl_link_failed:
-       xfrm6_mode_tunnel_input_deregister(&vti6_handler);
+       xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP);
+       xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH);
+       xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP);
 out:
        unregister_pernet_device(&vti6_net_ops);
 out_pernet:
@@ -1028,8 +1144,12 @@ out_pernet:
 static void __exit vti6_tunnel_cleanup(void)
 {
        rtnl_link_unregister(&vti6_link_ops);
-       if (xfrm6_mode_tunnel_input_deregister(&vti6_handler))
-               pr_info("%s: can't deregister vti6\n", __func__);
+       if (xfrm6_protocol_deregister(&vti_ipcomp6_protocol, IPPROTO_COMP))
+               pr_info("%s: can't deregister protocol\n", __func__);
+       if (xfrm6_protocol_deregister(&vti_ah6_protocol, IPPROTO_AH))
+               pr_info("%s: can't deregister protocol\n", __func__);
+       if (xfrm6_protocol_deregister(&vti_esp6_protocol, IPPROTO_ESP))
+               pr_info("%s: can't deregister protocol\n", __func__);
 
        unregister_pernet_device(&vti6_net_ops);
 }
index 0eb4038a4d63434738e938113b37bfe6611e07c3..8737400af0a095cac6666112cb8dcd4d60518823 100644 (file)
@@ -2349,13 +2349,14 @@ int ip6mr_get_route(struct net *net,
 }
 
 static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
-                            u32 portid, u32 seq, struct mfc6_cache *c, int cmd)
+                            u32 portid, u32 seq, struct mfc6_cache *c, int cmd,
+                            int flags)
 {
        struct nlmsghdr *nlh;
        struct rtmsg *rtm;
        int err;
 
-       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), NLM_F_MULTI);
+       nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rtm), flags);
        if (nlh == NULL)
                return -EMSGSIZE;
 
@@ -2423,7 +2424,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
        if (skb == NULL)
                goto errout;
 
-       err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd);
+       err = ip6mr_fill_mroute(mrt, skb, 0, 0, mfc, cmd, 0);
        if (err < 0)
                goto errout;
 
@@ -2462,7 +2463,8 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
                                if (ip6mr_fill_mroute(mrt, skb,
                                                      NETLINK_CB(cb->skb).portid,
                                                      cb->nlh->nlmsg_seq,
-                                                     mfc, RTM_NEWROUTE) < 0)
+                                                     mfc, RTM_NEWROUTE,
+                                                     NLM_F_MULTI) < 0)
                                        goto done;
 next_entry:
                                e++;
@@ -2476,7 +2478,8 @@ next_entry:
                        if (ip6mr_fill_mroute(mrt, skb,
                                              NETLINK_CB(cb->skb).portid,
                                              cb->nlh->nlmsg_seq,
-                                             mfc, RTM_NEWROUTE) < 0) {
+                                             mfc, RTM_NEWROUTE,
+                                             NLM_F_MULTI) < 0) {
                                spin_unlock_bh(&mfc_unres_lock);
                                goto done;
                        }
index da9becb42e8127283f59c70731dc2890701f769e..d1c793cffcb5f44aba0f922f2ebdd3105d51b49f 100644 (file)
@@ -53,7 +53,7 @@
 #include <linux/icmpv6.h>
 #include <linux/mutex.h>
 
-static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+static int ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                                u8 type, u8 code, int offset, __be32 info)
 {
        struct net *net = dev_net(skb->dev);
@@ -65,19 +65,21 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
        if (type != ICMPV6_PKT_TOOBIG &&
            type != NDISC_REDIRECT)
-               return;
+               return 0;
 
        spi = htonl(ntohs(ipcomph->cpi));
        x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
                              spi, IPPROTO_COMP, AF_INET6);
        if (!x)
-               return;
+               return 0;
 
        if (type == NDISC_REDIRECT)
                ip6_redirect(skb, net, skb->dev->ifindex, 0);
        else
                ip6_update_pmtu(skb, net, info, 0, 0);
        xfrm_state_put(x);
+
+       return 0;
 }
 
 static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
@@ -174,6 +176,11 @@ out:
        return err;
 }
 
+static int ipcomp6_rcv_cb(struct sk_buff *skb, int err)
+{
+       return 0;
+}
+
 static const struct xfrm_type ipcomp6_type =
 {
        .description    = "IPCOMP6",
@@ -186,11 +193,12 @@ static const struct xfrm_type ipcomp6_type =
        .hdr_offset     = xfrm6_find_1stfragopt,
 };
 
-static const struct inet6_protocol ipcomp6_protocol =
+static struct xfrm6_protocol ipcomp6_protocol =
 {
        .handler        = xfrm6_rcv,
+       .cb_handler     = ipcomp6_rcv_cb,
        .err_handler    = ipcomp6_err,
-       .flags          = INET6_PROTO_NOPOLICY,
+       .priority       = 0,
 };
 
 static int __init ipcomp6_init(void)
@@ -199,7 +207,7 @@ static int __init ipcomp6_init(void)
                pr_info("%s: can't add xfrm type\n", __func__);
                return -EAGAIN;
        }
-       if (inet6_add_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) {
+       if (xfrm6_protocol_register(&ipcomp6_protocol, IPPROTO_COMP) < 0) {
                pr_info("%s: can't add protocol\n", __func__);
                xfrm_unregister_type(&ipcomp6_type, AF_INET6);
                return -EAGAIN;
@@ -209,7 +217,7 @@ static int __init ipcomp6_init(void)
 
 static void __exit ipcomp6_fini(void)
 {
-       if (inet6_del_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0)
+       if (xfrm6_protocol_deregister(&ipcomp6_protocol, IPPROTO_COMP) < 0)
                pr_info("%s: can't remove protocol\n", __func__);
        if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0)
                pr_info("%s: can't remove xfrm type\n", __func__);
index 0a00f449de5e0484686f008e792b27efd67d2356..edb58aff4ae70ac864f3f2b559815064f4db87f6 100644 (file)
@@ -722,7 +722,7 @@ done:
        case IPV6_MTU_DISCOVER:
                if (optlen < sizeof(int))
                        goto e_inval;
-               if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE)
+               if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT)
                        goto e_inval;
                np->pmtudisc = val;
                retv = 0;
index 35750df744dc9ce92c3b98dcfd5dab27dcf73e85..4bff1f297e39a4affcf82e6b7aca2e6078b4dc50 100644 (file)
@@ -50,6 +50,11 @@ config NFT_CHAIN_NAT_IPV6
          packet transformations such as the source, destination address and
          source and destination ports.
 
+config NFT_REJECT_IPV6
+       depends on NF_TABLES_IPV6
+       default NFT_REJECT
+       tristate
+
 config IP6_NF_IPTABLES
        tristate "IP6 tables support (required for filtering)"
        depends on INET && IPV6
index d1b4928f34f7ba3f80200ec0b9db67c12d47715b..70d3dd66f2cdbf1408d328fd06104671446d5bc9 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
 obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
 obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
+obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
 
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
diff --git a/net/ipv6/netfilter/nft_reject_ipv6.c b/net/ipv6/netfilter/nft_reject_ipv6.c
new file mode 100644 (file)
index 0000000..0bc19fa
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 Eric Leblond <eric@regit.org>
+ *
+ * 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.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nft_reject.h>
+#include <net/netfilter/ipv6/nf_reject.h>
+
+void nft_reject_ipv6_eval(const struct nft_expr *expr,
+                         struct nft_data data[NFT_REG_MAX + 1],
+                         const struct nft_pktinfo *pkt)
+{
+       struct nft_reject *priv = nft_expr_priv(expr);
+       struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
+
+       switch (priv->type) {
+       case NFT_REJECT_ICMP_UNREACH:
+               nf_send_unreach6(net, pkt->skb, priv->icmp_code,
+                                pkt->ops->hooknum);
+               break;
+       case NFT_REJECT_TCP_RST:
+               nf_send_reset6(net, pkt->skb, pkt->ops->hooknum);
+               break;
+       }
+
+       data[NFT_REG_VERDICT].verdict = NF_DROP;
+}
+EXPORT_SYMBOL_GPL(nft_reject_ipv6_eval);
+
+static struct nft_expr_type nft_reject_ipv6_type;
+static const struct nft_expr_ops nft_reject_ipv6_ops = {
+       .type           = &nft_reject_ipv6_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
+       .eval           = nft_reject_ipv6_eval,
+       .init           = nft_reject_init,
+       .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_ipv6_type __read_mostly = {
+       .family         = NFPROTO_IPV6,
+       .name           = "reject",
+       .ops            = &nft_reject_ipv6_ops,
+       .policy         = nft_reject_policy,
+       .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
+};
+
+static int __init nft_reject_ipv6_module_init(void)
+{
+       return nft_register_expr(&nft_reject_ipv6_type);
+}
+
+static void __exit nft_reject_ipv6_module_exit(void)
+{
+       nft_unregister_expr(&nft_reject_ipv6_type);
+}
+
+module_init(nft_reject_ipv6_module_init);
+module_exit(nft_reject_ipv6_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "reject");
index 827f795209cf9d607c5a63c188a369bb6c1ad684..d1b35d377e62de73c0fade1d6464e7a3358ba15a 100644 (file)
@@ -13,7 +13,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
        int old, new;
 
 #if IS_ENABLED(CONFIG_IPV6)
-       if (rt && !(rt->dst.flags & DST_NOPEER)) {
+       if (rt) {
                struct inet_peer *peer;
                struct net *net;
 
index fb9beb78f00b23fc307384bf6aef21adf2ab6895..587bbdcb22b4c04c0186932d463bce29ca32b38e 100644 (file)
@@ -135,6 +135,7 @@ int ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        fl6.flowi6_proto = IPPROTO_ICMPV6;
        fl6.saddr = np->saddr;
        fl6.daddr = *daddr;
+       fl6.flowi6_mark = sk->sk_mark;
        fl6.fl6_icmp_type = user_icmph.icmp6_type;
        fl6.fl6_icmp_code = user_icmph.icmp6_code;
        security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
index 11dac21e658690cdf01d7eb41c7e653d142ad9d4..b93ae6a6a31c2b3bb882f01180aa32c38df2c853 100644 (file)
@@ -149,7 +149,8 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old)
                unsigned long prev, new;
 
                p = peer->metrics;
-               if (inet_metrics_new(peer))
+               if (inet_metrics_new(peer) ||
+                   (old & DST_METRICS_FORCE_OVERWRITE))
                        memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
 
                new = (unsigned long) p;
@@ -857,14 +858,15 @@ EXPORT_SYMBOL(rt6_lookup);
    be destroyed.
  */
 
-static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
+static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info,
+                       struct nlattr *mx, int mx_len)
 {
        int err;
        struct fib6_table *table;
 
        table = rt->rt6i_table;
        write_lock_bh(&table->tb6_lock);
-       err = fib6_add(&table->tb6_root, rt, info);
+       err = fib6_add(&table->tb6_root, rt, info, mx, mx_len);
        write_unlock_bh(&table->tb6_lock);
 
        return err;
@@ -875,7 +877,7 @@ int ip6_ins_rt(struct rt6_info *rt)
        struct nl_info info = {
                .nl_net = dev_net(rt->dst.dev),
        };
-       return __ip6_ins_rt(rt, &info);
+       return __ip6_ins_rt(rt, &info, NULL, 0);
 }
 
 static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort,
@@ -1513,7 +1515,7 @@ int ip6_route_add(struct fib6_config *cfg)
        if (!table)
                goto out;
 
-       rt = ip6_dst_alloc(net, NULL, DST_NOCOUNT, table);
+       rt = ip6_dst_alloc(net, NULL, (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT, table);
 
        if (!rt) {
                err = -ENOMEM;
@@ -1543,17 +1545,11 @@ int ip6_route_add(struct fib6_config *cfg)
 
        ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
        rt->rt6i_dst.plen = cfg->fc_dst_len;
-       if (rt->rt6i_dst.plen == 128)
-              rt->dst.flags |= DST_HOST;
-
-       if (!(rt->dst.flags & DST_HOST) && cfg->fc_mx) {
-               u32 *metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
-               if (!metrics) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-               dst_init_metrics(&rt->dst, metrics, 0);
+       if (rt->rt6i_dst.plen == 128) {
+               rt->dst.flags |= DST_HOST;
+               dst_metrics_set_force_overwrite(&rt->dst);
        }
+
 #ifdef CONFIG_IPV6_SUBTREES
        ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len);
        rt->rt6i_src.plen = cfg->fc_src_len;
@@ -1672,31 +1668,13 @@ int ip6_route_add(struct fib6_config *cfg)
        rt->rt6i_flags = cfg->fc_flags;
 
 install_route:
-       if (cfg->fc_mx) {
-               struct nlattr *nla;
-               int remaining;
-
-               nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) {
-                       int type = nla_type(nla);
-
-                       if (type) {
-                               if (type > RTAX_MAX) {
-                                       err = -EINVAL;
-                                       goto out;
-                               }
-
-                               dst_metric_set(&rt->dst, type, nla_get_u32(nla));
-                       }
-               }
-       }
-
        rt->dst.dev = dev;
        rt->rt6i_idev = idev;
        rt->rt6i_table = table;
 
        cfg->fc_nlinfo.nl_net = dev_net(dev);
 
-       return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
+       return __ip6_ins_rt(rt, &cfg->fc_nlinfo, cfg->fc_mx, cfg->fc_mx_len);
 
 out:
        if (dev)
index 3dfbcf1dcb1cbdb38a2a0b17a328bb424b139eb0..1693c8d885f081e153e115bec78cb2f29a79a6ff 100644 (file)
@@ -475,6 +475,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
                ipip6_tunnel_unlink(sitn, tunnel);
                ipip6_tunnel_del_prl(tunnel, NULL);
        }
+       ip_tunnel_dst_reset_all(tunnel);
        dev_put(dev);
 }
 
@@ -1082,6 +1083,7 @@ static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p)
                t->parms.link = p->link;
                ipip6_tunnel_bind_dev(t->dev);
        }
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(t->dev);
 }
 
@@ -1112,6 +1114,7 @@ static int ipip6_tunnel_update_6rd(struct ip_tunnel *t,
        t->ip6rd.relay_prefix = relay_prefix;
        t->ip6rd.prefixlen = ip6rd->prefixlen;
        t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen;
+       ip_tunnel_dst_reset_all(t);
        netdev_state_change(t->dev);
        return 0;
 }
@@ -1271,6 +1274,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
                        err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL);
                        break;
                }
+               ip_tunnel_dst_reset_all(t);
                netdev_state_change(dev);
                break;
 
@@ -1326,6 +1330,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
 
 static void ipip6_dev_free(struct net_device *dev)
 {
+       struct ip_tunnel *tunnel = netdev_priv(dev);
+
+       free_percpu(tunnel->dst_cache);
        free_percpu(dev->tstats);
        free_netdev(dev);
 }
@@ -1356,7 +1363,6 @@ 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 i;
 
        tunnel->dev = dev;
        tunnel->net = dev_net(dev);
@@ -1365,14 +1371,14 @@ static int ipip6_tunnel_init(struct net_device *dev)
        memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4);
 
        ipip6_tunnel_bind_dev(dev);
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *ipip6_tunnel_stats;
-               ipip6_tunnel_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&ipip6_tunnel_stats->syncp);
+       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+       if (!tunnel->dst_cache) {
+               free_percpu(dev->tstats);
+               return -ENOMEM;
        }
 
        return 0;
@@ -1384,7 +1390,6 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        struct iphdr *iph = &tunnel->parms.iph;
        struct net *net = dev_net(dev);
        struct sit_net *sitn = net_generic(net, sit_net_id);
-       int i;
 
        tunnel->dev = dev;
        tunnel->net = dev_net(dev);
@@ -1395,14 +1400,14 @@ static int __net_init ipip6_fb_tunnel_init(struct net_device *dev)
        iph->ihl                = 5;
        iph->ttl                = 64;
 
-       dev->tstats = alloc_percpu(struct pcpu_sw_netstats);
+       dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!dev->tstats)
                return -ENOMEM;
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *ipip6_fb_stats;
-               ipip6_fb_stats = per_cpu_ptr(dev->tstats, i);
-               u64_stats_init(&ipip6_fb_stats->syncp);
+       tunnel->dst_cache = alloc_percpu(struct ip_tunnel_dst);
+       if (!tunnel->dst_cache) {
+               free_percpu(dev->tstats);
+               return -ENOMEM;
        }
 
        dev_hold(dev);
index 889079b2ea852f237dea495cc66a63c968037b6d..3277680186b4894a62f3791f3fcca9aa7ed99a23 100644 (file)
@@ -501,8 +501,10 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)
        int res;
 
        res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0);
-       if (!res)
+       if (!res) {
                TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNRETRANS);
+       }
        return res;
 }
 
index e7359f9eaa8d4dd14b706afc9c7241c85e52d056..b261ee8b83fc87ddabcb447d1235ea8b67429de2 100644 (file)
@@ -113,7 +113,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen);
                fptr->nexthdr = nexthdr;
                fptr->reserved = 0;
-               ipv6_select_ident(fptr, (struct rt6_info *)skb_dst(skb));
+               fptr->identification = skb_shinfo(skb)->ip6_frag_id;
 
                /* Fragment the skb. ipv6 header and the remaining fields of the
                 * fragment header are updated in ipv6_gso_segment()
index cb04f7a16b5e102f2944be051d61511d5645d3f7..901ef6f8addc0cf730909d2656513372cd6cf80f 100644 (file)
 #include <net/ipv6.h>
 #include <net/xfrm.h>
 
-/* Informational hook. The decap is still done here. */
-static struct xfrm_tunnel_notifier __rcu *rcv_notify_handlers __read_mostly;
-static DEFINE_MUTEX(xfrm6_mode_tunnel_input_mutex);
-
-int xfrm6_mode_tunnel_input_register(struct xfrm_tunnel_notifier *handler)
-{
-       struct xfrm_tunnel_notifier __rcu **pprev;
-       struct xfrm_tunnel_notifier *t;
-       int ret = -EEXIST;
-       int priority = handler->priority;
-
-       mutex_lock(&xfrm6_mode_tunnel_input_mutex);
-
-       for (pprev = &rcv_notify_handlers;
-            (t = rcu_dereference_protected(*pprev,
-            lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL;
-            pprev = &t->next) {
-               if (t->priority > priority)
-                       break;
-               if (t->priority == priority)
-                       goto err;
-
-       }
-
-       handler->next = *pprev;
-       rcu_assign_pointer(*pprev, handler);
-
-       ret = 0;
-
-err:
-       mutex_unlock(&xfrm6_mode_tunnel_input_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_register);
-
-int xfrm6_mode_tunnel_input_deregister(struct xfrm_tunnel_notifier *handler)
-{
-       struct xfrm_tunnel_notifier __rcu **pprev;
-       struct xfrm_tunnel_notifier *t;
-       int ret = -ENOENT;
-
-       mutex_lock(&xfrm6_mode_tunnel_input_mutex);
-       for (pprev = &rcv_notify_handlers;
-            (t = rcu_dereference_protected(*pprev,
-            lockdep_is_held(&xfrm6_mode_tunnel_input_mutex))) != NULL;
-            pprev = &t->next) {
-               if (t == handler) {
-                       *pprev = handler->next;
-                       ret = 0;
-                       break;
-               }
-       }
-       mutex_unlock(&xfrm6_mode_tunnel_input_mutex);
-       synchronize_net();
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(xfrm6_mode_tunnel_input_deregister);
-
 static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
 {
        const struct ipv6hdr *outer_iph = ipv6_hdr(skb);
@@ -130,7 +71,6 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 
 static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 {
-       struct xfrm_tunnel_notifier *handler;
        int err = -EINVAL;
 
        if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
@@ -138,9 +78,6 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
                goto out;
 
-       for_each_input_rcu(rcv_notify_handlers, handler)
-               handler->handler(skb);
-
        err = skb_unclone(skb, GFP_ATOMIC);
        if (err)
                goto out;
index 5f8e128c512d664080251bf6958c89021a1110c1..2a0bbda2c76a99dfa687313d230595c251103b45 100644 (file)
@@ -389,11 +389,17 @@ int __init xfrm6_init(void)
        if (ret)
                goto out_policy;
 
+       ret = xfrm6_protocol_init();
+       if (ret)
+               goto out_state;
+
 #ifdef CONFIG_SYSCTL
        register_pernet_subsys(&xfrm6_net_ops);
 #endif
 out:
        return ret;
+out_state:
+       xfrm6_state_fini();
 out_policy:
        xfrm6_policy_fini();
        goto out;
@@ -404,6 +410,7 @@ void xfrm6_fini(void)
 #ifdef CONFIG_SYSCTL
        unregister_pernet_subsys(&xfrm6_net_ops);
 #endif
+       xfrm6_protocol_fini();
        xfrm6_policy_fini();
        xfrm6_state_fini();
        dst_entries_destroy(&xfrm6_dst_ops);
diff --git a/net/ipv6/xfrm6_protocol.c b/net/ipv6/xfrm6_protocol.c
new file mode 100644 (file)
index 0000000..6ab989c
--- /dev/null
@@ -0,0 +1,270 @@
+/* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6.
+ *
+ * Copyright (C) 2013 secunet Security Networks AG
+ *
+ * Author:
+ * Steffen Klassert <steffen.klassert@secunet.com>
+ *
+ * Based on:
+ * net/ipv4/xfrm4_protocol.c
+ *
+ *     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/init.h>
+#include <linux/mutex.h>
+#include <linux/skbuff.h>
+#include <linux/icmpv6.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly;
+static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly;
+static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly;
+static DEFINE_MUTEX(xfrm6_protocol_mutex);
+
+static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol)
+{
+       switch (protocol) {
+       case IPPROTO_ESP:
+               return &esp6_handlers;
+       case IPPROTO_AH:
+               return &ah6_handlers;
+       case IPPROTO_COMP:
+               return &ipcomp6_handlers;
+       }
+
+       return NULL;
+}
+
+#define for_each_protocol_rcu(head, handler)           \
+       for (handler = rcu_dereference(head);           \
+            handler != NULL;                           \
+            handler = rcu_dereference(handler->next))  \
+
+int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
+{
+       int ret;
+       struct xfrm6_protocol *handler;
+
+       for_each_protocol_rcu(*proto_handlers(protocol), handler)
+               if ((ret = handler->cb_handler(skb, err)) <= 0)
+                       return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(xfrm6_rcv_cb);
+
+static int xfrm6_esp_rcv(struct sk_buff *skb)
+{
+       int ret;
+       struct xfrm6_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
+
+       for_each_protocol_rcu(esp6_handlers, handler)
+               if ((ret = handler->handler(skb)) != -EINVAL)
+                       return ret;
+
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static void xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                         u8 type, u8 code, int offset, __be32 info)
+{
+       struct xfrm6_protocol *handler;
+
+       for_each_protocol_rcu(esp6_handlers, handler)
+               if (!handler->err_handler(skb, opt, type, code, offset, info))
+                       break;
+}
+
+static int xfrm6_ah_rcv(struct sk_buff *skb)
+{
+       int ret;
+       struct xfrm6_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
+
+       for_each_protocol_rcu(ah6_handlers, handler)
+               if ((ret = handler->handler(skb)) != -EINVAL)
+                       return ret;
+
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static void xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                        u8 type, u8 code, int offset, __be32 info)
+{
+       struct xfrm6_protocol *handler;
+
+       for_each_protocol_rcu(ah6_handlers, handler)
+               if (!handler->err_handler(skb, opt, type, code, offset, info))
+                       break;
+}
+
+static int xfrm6_ipcomp_rcv(struct sk_buff *skb)
+{
+       int ret;
+       struct xfrm6_protocol *handler;
+
+       XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL;
+
+       for_each_protocol_rcu(ipcomp6_handlers, handler)
+               if ((ret = handler->handler(skb)) != -EINVAL)
+                       return ret;
+
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
+
+       kfree_skb(skb);
+       return 0;
+}
+
+static void xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+                            u8 type, u8 code, int offset, __be32 info)
+{
+       struct xfrm6_protocol *handler;
+
+       for_each_protocol_rcu(ipcomp6_handlers, handler)
+               if (!handler->err_handler(skb, opt, type, code, offset, info))
+                       break;
+}
+
+static const struct inet6_protocol esp6_protocol = {
+       .handler        =       xfrm6_esp_rcv,
+       .err_handler    =       xfrm6_esp_err,
+       .flags          =       INET6_PROTO_NOPOLICY,
+};
+
+static const struct inet6_protocol ah6_protocol = {
+       .handler        =       xfrm6_ah_rcv,
+       .err_handler    =       xfrm6_ah_err,
+       .flags          =       INET6_PROTO_NOPOLICY,
+};
+
+static const struct inet6_protocol ipcomp6_protocol = {
+       .handler        =       xfrm6_ipcomp_rcv,
+       .err_handler    =       xfrm6_ipcomp_err,
+       .flags          =       INET6_PROTO_NOPOLICY,
+};
+
+static struct xfrm_input_afinfo xfrm6_input_afinfo = {
+       .family         =       AF_INET6,
+       .owner          =       THIS_MODULE,
+       .callback       =       xfrm6_rcv_cb,
+};
+
+static inline const struct inet6_protocol *netproto(unsigned char protocol)
+{
+       switch (protocol) {
+       case IPPROTO_ESP:
+               return &esp6_protocol;
+       case IPPROTO_AH:
+               return &ah6_protocol;
+       case IPPROTO_COMP:
+               return &ipcomp6_protocol;
+       }
+
+       return NULL;
+}
+
+int xfrm6_protocol_register(struct xfrm6_protocol *handler,
+                           unsigned char protocol)
+{
+       struct xfrm6_protocol __rcu **pprev;
+       struct xfrm6_protocol *t;
+       bool add_netproto = false;
+
+       int ret = -EEXIST;
+       int priority = handler->priority;
+
+       mutex_lock(&xfrm6_protocol_mutex);
+
+       if (!rcu_dereference_protected(*proto_handlers(protocol),
+                                      lockdep_is_held(&xfrm6_protocol_mutex)))
+               add_netproto = true;
+
+       for (pprev = proto_handlers(protocol);
+            (t = rcu_dereference_protected(*pprev,
+                       lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t->priority < priority)
+                       break;
+               if (t->priority == priority)
+                       goto err;
+       }
+
+       handler->next = *pprev;
+       rcu_assign_pointer(*pprev, handler);
+
+       ret = 0;
+
+err:
+       mutex_unlock(&xfrm6_protocol_mutex);
+
+       if (add_netproto) {
+               if (inet6_add_protocol(netproto(protocol), protocol)) {
+                       pr_err("%s: can't add protocol\n", __func__);
+                       ret = -EAGAIN;
+               }
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(xfrm6_protocol_register);
+
+int xfrm6_protocol_deregister(struct xfrm6_protocol *handler,
+                             unsigned char protocol)
+{
+       struct xfrm6_protocol __rcu **pprev;
+       struct xfrm6_protocol *t;
+       int ret = -ENOENT;
+
+       mutex_lock(&xfrm6_protocol_mutex);
+
+       for (pprev = proto_handlers(protocol);
+            (t = rcu_dereference_protected(*pprev,
+                       lockdep_is_held(&xfrm6_protocol_mutex))) != NULL;
+            pprev = &t->next) {
+               if (t == handler) {
+                       *pprev = handler->next;
+                       ret = 0;
+                       break;
+               }
+       }
+
+       if (!rcu_dereference_protected(*proto_handlers(protocol),
+                                      lockdep_is_held(&xfrm6_protocol_mutex))) {
+               if (inet6_del_protocol(netproto(protocol), protocol) < 0) {
+                       pr_err("%s: can't remove protocol\n", __func__);
+                       ret = -EAGAIN;
+               }
+       }
+
+       mutex_unlock(&xfrm6_protocol_mutex);
+
+       synchronize_net();
+
+       return ret;
+}
+EXPORT_SYMBOL(xfrm6_protocol_deregister);
+
+int __init xfrm6_protocol_init(void)
+{
+       return xfrm_input_register_afinfo(&xfrm6_input_afinfo);
+}
+
+void xfrm6_protocol_fini(void)
+{
+       xfrm_input_unregister_afinfo(&xfrm6_input_afinfo);
+}
index 994e28bfb32e14ba9e4ab833c5491683824a149e..41e4e93cb3aae37df41ff419ef34be9c2255b5cc 100644 (file)
 #include <net/p8022.h>
 #include <net/psnap.h>
 #include <net/sock.h>
+#include <net/datalink.h>
 #include <net/tcp_states.h>
+#include <net/net_namespace.h>
 
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_SYSCTL
-extern void ipx_register_sysctl(void);
-extern void ipx_unregister_sysctl(void);
-#else
-#define ipx_register_sysctl()
-#define ipx_unregister_sysctl()
-#endif
-
 /* Configuration Variables */
 static unsigned char ipxcfg_max_hops = 16;
 static char ipxcfg_auto_select_primary;
@@ -84,15 +78,6 @@ DEFINE_SPINLOCK(ipx_interfaces_lock);
 struct ipx_interface *ipx_primary_net;
 struct ipx_interface *ipx_internal_net;
 
-extern int ipxrtr_add_route(__be32 network, struct ipx_interface *intrfc,
-                           unsigned char *node);
-extern void ipxrtr_del_routes(struct ipx_interface *intrfc);
-extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
-                              struct iovec *iov, size_t len, int noblock);
-extern int ipxrtr_route_skb(struct sk_buff *skb);
-extern struct ipx_route *ipxrtr_lookup(__be32 net);
-extern int ipxrtr_ioctl(unsigned int cmd, void __user *arg);
-
 struct ipx_interface *ipx_interfaces_head(void)
 {
        struct ipx_interface *rc = NULL;
@@ -1383,6 +1368,7 @@ static int ipx_release(struct socket *sock)
                goto out;
 
        lock_sock(sk);
+       sk->sk_shutdown = SHUTDOWN_MASK;
        if (!sock_flag(sk, SOCK_DEAD))
                sk->sk_state_change(sk);
 
@@ -1806,8 +1792,11 @@ static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
                                flags & MSG_DONTWAIT, &rc);
-       if (!skb)
+       if (!skb) {
+               if (rc == -EAGAIN && (sk->sk_shutdown & RCV_SHUTDOWN))
+                       rc = 0;
                goto out;
+       }
 
        ipx     = ipx_hdr(skb);
        copied  = ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr);
@@ -1937,6 +1926,26 @@ static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long
 }
 #endif
 
+static int ipx_shutdown(struct socket *sock, int mode)
+{
+       struct sock *sk = sock->sk;
+
+       if (mode < SHUT_RD || mode > SHUT_RDWR)
+               return -EINVAL;
+       /* This maps:
+        * SHUT_RD   (0) -> RCV_SHUTDOWN  (1)
+        * SHUT_WR   (1) -> SEND_SHUTDOWN (2)
+        * SHUT_RDWR (2) -> SHUTDOWN_MASK (3)
+        */
+       ++mode;
+
+       lock_sock(sk);
+       sk->sk_shutdown |= mode;
+       release_sock(sk);
+       sk->sk_state_change(sk);
+
+       return 0;
+}
 
 /*
  * Socket family declarations
@@ -1963,7 +1972,7 @@ static const struct proto_ops ipx_dgram_ops = {
        .compat_ioctl   = ipx_compat_ioctl,
 #endif
        .listen         = sock_no_listen,
-       .shutdown       = sock_no_shutdown, /* FIXME: support shutdown */
+       .shutdown       = ipx_shutdown,
        .setsockopt     = ipx_setsockopt,
        .getsockopt     = ipx_getsockopt,
        .sendmsg        = ipx_sendmsg,
@@ -1986,9 +1995,6 @@ static struct notifier_block ipx_dev_notifier = {
        .notifier_call  = ipxitf_device_event,
 };
 
-extern struct datalink_proto *make_EII_client(void);
-extern void destroy_EII_client(struct datalink_proto *);
-
 static const unsigned char ipx_8022_type = 0xE0;
 static const unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
 static const char ipx_EII_err_msg[] __initconst =
index 30f4519b092f546aad806520280bec883165a9c2..c1f03185c5e115ffe359e39a0bfb17efe8d4c38a 100644 (file)
@@ -20,15 +20,11 @@ DEFINE_RWLOCK(ipx_routes_lock);
 
 extern struct ipx_interface *ipx_internal_net;
 
-extern __be16 ipx_cksum(struct ipxhdr *packet, int length);
 extern struct ipx_interface *ipxitf_find_using_net(__be32 net);
 extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
                               struct sk_buff *skb, int copy);
 extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
                               struct sk_buff *skb, int copy);
-extern int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb,
-                      char *node);
-extern struct ipx_interface *ipxitf_find_using_net(__be32 net);
 
 struct ipx_route *ipxrtr_lookup(__be32 net)
 {
index c4b7218058b648856066bb24dacf38d54d16defc..a5e03119107a5563be4a4307fa56885d8e3952ff 100644 (file)
@@ -1382,6 +1382,7 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (sk->sk_type == SOCK_STREAM) {
                        if (copied < rlen) {
                                IUCV_SKB_CB(skb)->offset = offset + copied;
+                               skb_queue_head(&sk->sk_receive_queue, skb);
                                goto done;
                        }
                }
index 1a04c13293628eb420088717dce841266328b09f..e72589a8400dbf7e35a68468149bc7ce601b48be 100644 (file)
@@ -365,6 +365,7 @@ static const u8 sadb_ext_min_len[] = {
        [SADB_X_EXT_NAT_T_OA]           = (u8) sizeof(struct sadb_address),
        [SADB_X_EXT_SEC_CTX]            = (u8) sizeof(struct sadb_x_sec_ctx),
        [SADB_X_EXT_KMADDRESS]          = (u8) sizeof(struct sadb_x_kmaddress),
+       [SADB_X_EXT_FILTER]             = (u8) sizeof(struct sadb_x_filter),
 };
 
 /* Verify sadb_address_{len,prefixlen} against sa_family.  */
@@ -433,12 +434,13 @@ static inline int verify_sec_ctx_len(const void *p)
        return 0;
 }
 
-static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx)
+static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx,
+                                                                    gfp_t gfp)
 {
        struct xfrm_user_sec_ctx *uctx = NULL;
        int ctx_size = sec_ctx->sadb_x_ctx_len;
 
-       uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL);
+       uctx = kmalloc((sizeof(*uctx)+ctx_size), gfp);
 
        if (!uctx)
                return NULL;
@@ -1124,7 +1126,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net,
 
        sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
        if (sec_ctx != NULL) {
-               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
 
                if (!uctx)
                        goto out;
@@ -1798,6 +1800,7 @@ static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
 static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs)
 {
        u8 proto;
+       struct xfrm_address_filter *filter = NULL;
        struct pfkey_sock *pfk = pfkey_sk(sk);
 
        if (pfk->dump.dump != NULL)
@@ -1807,11 +1810,27 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms
        if (proto == 0)
                return -EINVAL;
 
+       if (ext_hdrs[SADB_X_EXT_FILTER - 1]) {
+               struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1];
+
+               filter = kmalloc(sizeof(*filter), GFP_KERNEL);
+               if (filter == NULL)
+                       return -ENOMEM;
+
+               memcpy(&filter->saddr, &xfilter->sadb_x_filter_saddr,
+                      sizeof(xfrm_address_t));
+               memcpy(&filter->daddr, &xfilter->sadb_x_filter_daddr,
+                      sizeof(xfrm_address_t));
+               filter->family = xfilter->sadb_x_filter_family;
+               filter->splen = xfilter->sadb_x_filter_splen;
+               filter->dplen = xfilter->sadb_x_filter_dplen;
+       }
+
        pfk->dump.msg_version = hdr->sadb_msg_version;
        pfk->dump.msg_portid = hdr->sadb_msg_pid;
        pfk->dump.dump = pfkey_dump_sa;
        pfk->dump.done = pfkey_dump_sa_done;
-       xfrm_state_walk_init(&pfk->dump.u.state, proto);
+       xfrm_state_walk_init(&pfk->dump.u.state, proto, filter);
 
        return pfkey_do_dump(pfk);
 }
@@ -2231,14 +2250,14 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_
 
        sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
        if (sec_ctx != NULL) {
-               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
 
                if (!uctx) {
                        err = -ENOBUFS;
                        goto out;
                }
 
-               err = security_xfrm_policy_alloc(&xp->security, uctx);
+               err = security_xfrm_policy_alloc(&xp->security, uctx, GFP_KERNEL);
                kfree(uctx);
 
                if (err)
@@ -2335,12 +2354,12 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
 
        sec_ctx = ext_hdrs[SADB_X_EXT_SEC_CTX - 1];
        if (sec_ctx != NULL) {
-               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
+               struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_KERNEL);
 
                if (!uctx)
                        return -ENOMEM;
 
-               err = security_xfrm_policy_alloc(&pol_ctx, uctx);
+               err = security_xfrm_policy_alloc(&pol_ctx, uctx, GFP_KERNEL);
                kfree(uctx);
                if (err)
                        return err;
@@ -3059,6 +3078,24 @@ static u32 get_acqseq(void)
        return res;
 }
 
+static bool pfkey_is_alive(const struct km_event *c)
+{
+       struct netns_pfkey *net_pfkey = net_generic(c->net, pfkey_net_id);
+       struct sock *sk;
+       bool is_alive = false;
+
+       rcu_read_lock();
+       sk_for_each_rcu(sk, &net_pfkey->table) {
+               if (pfkey_sk(sk)->registered) {
+                       is_alive = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return is_alive;
+}
+
 static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp)
 {
        struct sk_buff *skb;
@@ -3239,8 +3276,8 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
                }
                if ((*dir = verify_sec_ctx_len(p)))
                        goto out;
-               uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);
-               *dir = security_xfrm_policy_alloc(&xp->security, uctx);
+               uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_ATOMIC);
+               *dir = security_xfrm_policy_alloc(&xp->security, uctx, GFP_ATOMIC);
                kfree(uctx);
 
                if (*dir)
@@ -3784,6 +3821,7 @@ static struct xfrm_mgr pfkeyv2_mgr =
        .new_mapping    = pfkey_send_new_mapping,
        .notify_policy  = pfkey_send_policy_notify,
        .migrate        = pfkey_send_migrate,
+       .is_alive       = pfkey_is_alive,
 };
 
 static int __net_init pfkey_net_init(struct net *net)
index 735d0f60c83a126683b599d1e967eb9ca18b0471..ab48d4192edd37270c8e666e1bd9be781d249fd1 100644 (file)
@@ -112,7 +112,6 @@ struct l2tp_net {
        spinlock_t l2tp_session_hlist_lock;
 };
 
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 
 static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
@@ -1131,7 +1130,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        /* Queue the packet to IP for output */
        skb->local_df = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-       if (skb->sk->sk_family == PF_INET6 && !tunnel->v4mapped)
+       if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped)
                error = inet6_csk_xmit(skb, NULL);
        else
 #endif
@@ -1151,23 +1150,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        return 0;
 }
 
-/* Automatically called when the skb is freed.
- */
-static void l2tp_sock_wfree(struct sk_buff *skb)
-{
-       sock_put(skb->sk);
-}
-
-/* For data skbs that we transmit, we associate with the tunnel socket
- * but don't do accounting.
- */
-static inline void l2tp_skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
-{
-       sock_hold(sk);
-       skb->sk = sk;
-       skb->destructor = l2tp_sock_wfree;
-}
-
 #if IS_ENABLED(CONFIG_IPV6)
 static void l2tp_xmit_ipv6_csum(struct sock *sk, struct sk_buff *skb,
                                int udp_len)
@@ -1221,7 +1203,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
                return NET_XMIT_DROP;
        }
 
-       skb_orphan(skb);
        /* Setup L2TP header */
        session->build_header(session, __skb_push(skb, hdr_len));
 
@@ -1287,8 +1268,6 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
                break;
        }
 
-       l2tp_skb_set_owner_w(skb, sk);
-
        l2tp_xmit_core(session, skb, fl, data_len);
 out_unlock:
        bh_unlock_sock(sk);
@@ -1809,8 +1788,6 @@ void l2tp_session_free(struct l2tp_session *session)
        }
 
        kfree(session);
-
-       return;
 }
 EXPORT_SYMBOL_GPL(l2tp_session_free);
 
@@ -1863,7 +1840,7 @@ EXPORT_SYMBOL_GPL(l2tp_session_delete);
 /* We come here whenever a session's send_seq, cookie_len or
  * l2specific_len parameters are set.
  */
-static void l2tp_session_set_header_len(struct l2tp_session *session, int version)
+void l2tp_session_set_header_len(struct l2tp_session *session, int version)
 {
        if (version == L2TP_HDR_VER_2) {
                session->hdr_len = 6;
@@ -1876,6 +1853,7 @@ static void l2tp_session_set_header_len(struct l2tp_session *session, int versio
        }
 
 }
+EXPORT_SYMBOL_GPL(l2tp_session_set_header_len);
 
 struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg)
 {
index 1f01ba3435bcf0889a79e510567f19f248b7eef5..3f93ccd6ba9768fe171f4e35e79d613226c1dbc7 100644 (file)
@@ -263,6 +263,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                      int length, int (*payload_hook)(struct sk_buff *skb));
 int l2tp_session_queue_purge(struct l2tp_session *session);
 int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
+void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 
 int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb,
                  int hdr_len);
index 4cfd722e91536c1de137ec64f1e33bbc7fc5e1ea..bd7387adea9eff25ce7ffd0683589dcdcc020ad0 100644 (file)
@@ -578,8 +578,10 @@ static int l2tp_nl_cmd_session_modify(struct sk_buff *skb, struct genl_info *inf
        if (info->attrs[L2TP_ATTR_RECV_SEQ])
                session->recv_seq = nla_get_u8(info->attrs[L2TP_ATTR_RECV_SEQ]);
 
-       if (info->attrs[L2TP_ATTR_SEND_SEQ])
+       if (info->attrs[L2TP_ATTR_SEND_SEQ]) {
                session->send_seq = nla_get_u8(info->attrs[L2TP_ATTR_SEND_SEQ]);
+               l2tp_session_set_header_len(session, session->tunnel->version);
+       }
 
        if (info->attrs[L2TP_ATTR_LNS_MODE])
                session->lns_mode = nla_get_u8(info->attrs[L2TP_ATTR_LNS_MODE]);
index be5fadf3473946a3b7ef886eeadcb2d219e867aa..d276e2d4a5894c38c6489eb2f814542a181f6d75 100644 (file)
@@ -254,12 +254,14 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
                po = pppox_sk(sk);
                ppp_input(&po->chan, skb);
        } else {
-               l2tp_info(session, PPPOL2TP_MSG_DATA, "%s: socket not bound\n",
-                         session->name);
+               l2tp_dbg(session, PPPOL2TP_MSG_DATA,
+                        "%s: recv %d byte data frame, passing to L2TP socket\n",
+                        session->name, data_len);
 
-               /* Not bound. Nothing we can do, so discard. */
-               atomic_long_inc(&session->stats.rx_errors);
-               kfree_skb(skb);
+               if (sock_queue_rcv_skb(sk, skb) < 0) {
+                       atomic_long_inc(&session->stats.rx_errors);
+                       kfree_skb(skb);
+               }
        }
 
        return;
@@ -454,13 +456,11 @@ static void pppol2tp_session_close(struct l2tp_session *session)
 
        BUG_ON(session->magic != L2TP_SESSION_MAGIC);
 
-
        if (sock) {
                inet_shutdown(sock, 2);
                /* Don't let the session go away before our socket does */
                l2tp_session_inc_refcount(session);
        }
-       return;
 }
 
 /* Really kill the session socket. (Called from sock_put() if
@@ -474,7 +474,6 @@ static void pppol2tp_session_destruct(struct sock *sk)
                BUG_ON(session->magic != L2TP_SESSION_MAGIC);
                l2tp_session_dec_refcount(session);
        }
-       return;
 }
 
 /* Called when the PPPoX socket (session) is closed.
@@ -1312,6 +1311,7 @@ static int pppol2tp_session_setsockopt(struct sock *sk,
                        po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
                                PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
                }
+               l2tp_session_set_header_len(session, session->tunnel->version);
                l2tp_info(session, PPPOL2TP_MSG_CONTROL,
                          "%s: set send_seq=%d\n",
                          session->name, session->send_seq);
index 42c659229a090a7c86f6ad42a33df11afd40b6c8..bd1fd8ea5105fead274e09b7bcd093ba97081a97 100644 (file)
@@ -100,6 +100,12 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
                }
                max_bw = max(max_bw, width);
        }
+
+       /* use the configured bandwidth in case of monitor interface */
+       sdata = rcu_dereference(local->monitor_sdata);
+       if (sdata && rcu_access_pointer(sdata->vif.chanctx_conf) == conf)
+               max_bw = max(max_bw, conf->def.width);
+
        rcu_read_unlock();
 
        return max_bw;
index be198f42f1f7ce6b8f47aedef24032fe0f04c4fe..b8d331e7d883d50fd4fc3adf12c2869ac3beedb7 100644 (file)
@@ -1054,7 +1054,8 @@ static void ieee80211_uninit(struct net_device *dev)
 
 static u16 ieee80211_netdev_select_queue(struct net_device *dev,
                                         struct sk_buff *skb,
-                                        void *accel_priv)
+                                        void *accel_priv,
+                                        select_queue_fallback_t fallback)
 {
        return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
 }
@@ -1072,7 +1073,8 @@ static const struct net_device_ops ieee80211_dataif_ops = {
 
 static u16 ieee80211_monitor_select_queue(struct net_device *dev,
                                          struct sk_buff *skb,
-                                         void *accel_priv)
+                                         void *accel_priv,
+                                         select_queue_fallback_t fallback)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
index 2802f9d9279de1527927a88bc731489cc22613c7..ad8b377b4b9f6cfa5d5e222a3c0aff169f4d72d1 100644 (file)
@@ -36,6 +36,7 @@ static struct sk_buff *mps_qos_null_get(struct sta_info *sta)
                                      sdata->vif.addr);
        nullfunc->frame_control = fc;
        nullfunc->duration_id = 0;
+       nullfunc->seq_ctrl = 0;
        /* no address resolution for this frame -> set addr 1 immediately */
        memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
        memset(skb_put(skb, 2), 0, 2); /* append QoS control field */
index a023b432143b6f4b9db102b7a86c8ca417e1b3d2..137a192e64bc3c2aa61cc9c5912a89bd3008cbe3 100644 (file)
@@ -1206,6 +1206,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
        memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
        memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
        memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+       nullfunc->seq_ctrl = 0;
 
        skb->priority = tid;
        skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
index 57cf5d1a2e4a4e3de3c6b839cacb5bdf8baf1367..15d62df521825c8581fc25ec25a9caebc8902a72 100644 (file)
@@ -1,2 +1,4 @@
 obj-$(CONFIG_MAC802154)        += mac802154.o
 mac802154-objs         := ieee802154_dev.o rx.o tx.o mac_cmd.o mib.o monitor.o wpan.o
+
+ccflags-y += -D__CHECK_ENDIAN__
index 52ae6646a41140e065920ee80c4df626c6a58594..10cdb091b775602a1807816256a22f734c0dfb8e 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/netlink.h>
 #include <linux/nl802154.h>
 #include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
 #include <net/route.h>
 #include <net/wpan-phy.h>
 
@@ -46,7 +47,9 @@ int mac802154_slave_open(struct net_device *dev)
        }
 
        if (ipriv->ops->ieee_addr) {
-               res = ipriv->ops->ieee_addr(&ipriv->hw, dev->dev_addr);
+               __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+
+               res = ipriv->ops->ieee_addr(&ipriv->hw, addr);
                WARN_ON(res);
                if (res)
                        goto err;
@@ -165,6 +168,67 @@ err:
        return ERR_PTR(err);
 }
 
+static int mac802154_set_txpower(struct wpan_phy *phy, int db)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_txpower)
+               return -ENOTSUPP;
+
+       return priv->ops->set_txpower(&priv->hw, db);
+}
+
+static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_lbt)
+               return -ENOTSUPP;
+
+       return priv->ops->set_lbt(&priv->hw, on);
+}
+
+static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_cca_mode)
+               return -ENOTSUPP;
+
+       return priv->ops->set_cca_mode(&priv->hw, mode);
+}
+
+static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_cca_ed_level)
+               return -ENOTSUPP;
+
+       return priv->ops->set_cca_ed_level(&priv->hw, level);
+}
+
+static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be,
+                                    u8 max_be, u8 retries)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_csma_params)
+               return -ENOTSUPP;
+
+       return priv->ops->set_csma_params(&priv->hw, min_be, max_be, retries);
+}
+
+static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_frame_retries)
+               return -ENOTSUPP;
+
+       return priv->ops->set_frame_retries(&priv->hw, retries);
+}
+
 struct ieee802154_dev *
 ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
 {
@@ -242,6 +306,12 @@ int ieee802154_register_device(struct ieee802154_dev *dev)
 
        priv->phy->add_iface = mac802154_add_iface;
        priv->phy->del_iface = mac802154_del_iface;
+       priv->phy->set_txpower = mac802154_set_txpower;
+       priv->phy->set_lbt = mac802154_set_lbt;
+       priv->phy->set_cca_mode = mac802154_set_cca_mode;
+       priv->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
+       priv->phy->set_csma_params = mac802154_set_csma_params;
+       priv->phy->set_frame_retries = mac802154_set_frame_retries;
 
        rc = wpan_phy_register(priv->phy);
        if (rc < 0)
index d48422e271109a47d2e7139cf33e2bc727c38f3d..4619486f1da21e728b609f94d785ce683426ccdf 100644 (file)
@@ -76,6 +76,7 @@ struct mac802154_sub_if_data {
 
        __le16 pan_id;
        __le16 short_addr;
+       __le64 extended_addr;
 
        u8 chan;
        u8 page;
@@ -106,11 +107,11 @@ netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
                         u8 page, u8 chan);
 
 /* MIB callbacks */
-void mac802154_dev_set_short_addr(struct net_device *dev, u16 val);
-u16 mac802154_dev_get_short_addr(const struct net_device *dev);
+void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val);
+__le16 mac802154_dev_get_short_addr(const struct net_device *dev);
 void mac802154_dev_set_ieee_addr(struct net_device *dev);
-u16 mac802154_dev_get_pan_id(const struct net_device *dev);
-void mac802154_dev_set_pan_id(struct net_device *dev, u16 val);
+__le16 mac802154_dev_get_pan_id(const struct net_device *dev);
+void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val);
 void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
 u8 mac802154_dev_get_dsn(const struct net_device *dev);
 
index a99910d4d52f8403a8c2141b473deba885b977ad..15bac3358889198e4b34800896bec9fc12163450 100644 (file)
@@ -40,7 +40,7 @@ static int mac802154_mlme_start_req(struct net_device *dev,
                                    u8 pan_coord, u8 blx,
                                    u8 coord_realign)
 {
-       BUG_ON(addr->addr_type != IEEE802154_ADDR_SHORT);
+       BUG_ON(addr->mode != IEEE802154_ADDR_SHORT);
 
        mac802154_dev_set_pan_id(dev, addr->pan_id);
        mac802154_dev_set_short_addr(dev, addr->short_addr);
index 8ded97cf1c33f4336b3a59761095eff575ba6287..153bd1ddbfbba782b4c2842d7559d8a8917bb474 100644 (file)
@@ -24,7 +24,9 @@
 #include <linux/if_arp.h>
 
 #include <net/mac802154.h>
+#include <net/ieee802154_netdev.h>
 #include <net/wpan-phy.h>
+#include <net/ieee802154_netdev.h>
 
 #include "mac802154.h"
 
@@ -62,8 +64,6 @@ static void hw_addr_notify(struct work_struct *work)
                pr_debug("failed changed mask %lx\n", nw->changed);
 
        kfree(nw);
-
-       return;
 }
 
 static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
@@ -79,11 +79,9 @@ static void set_hw_addr_filt(struct net_device *dev, unsigned long changed)
        work->dev = dev;
        work->changed = changed;
        queue_work(priv->hw->dev_workqueue, &work->work);
-
-       return;
 }
 
-void mac802154_dev_set_short_addr(struct net_device *dev, u16 val)
+void mac802154_dev_set_short_addr(struct net_device *dev, __le16 val)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
 
@@ -100,10 +98,10 @@ void mac802154_dev_set_short_addr(struct net_device *dev, u16 val)
        }
 }
 
-u16 mac802154_dev_get_short_addr(const struct net_device *dev)
+__le16 mac802154_dev_get_short_addr(const struct net_device *dev)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       u16 ret;
+       __le16 ret;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
@@ -119,19 +117,19 @@ void mac802154_dev_set_ieee_addr(struct net_device *dev)
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
        struct mac802154_priv *mac = priv->hw;
 
+       priv->extended_addr = ieee802154_devaddr_from_raw(dev->dev_addr);
+
        if (mac->ops->set_hw_addr_filt &&
-           memcmp(mac->hw.hw_filt.ieee_addr,
-                  dev->dev_addr, IEEE802154_ADDR_LEN)) {
-               memcpy(mac->hw.hw_filt.ieee_addr,
-                      dev->dev_addr, IEEE802154_ADDR_LEN);
+           mac->hw.hw_filt.ieee_addr != priv->extended_addr) {
+               mac->hw.hw_filt.ieee_addr = priv->extended_addr;
                set_hw_addr_filt(dev, IEEE802515_AFILT_IEEEADDR_CHANGED);
        }
 }
 
-u16 mac802154_dev_get_pan_id(const struct net_device *dev)
+__le16 mac802154_dev_get_pan_id(const struct net_device *dev)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       u16 ret;
+       __le16 ret;
 
        BUG_ON(dev->type != ARPHRD_IEEE802154);
 
@@ -142,7 +140,7 @@ u16 mac802154_dev_get_pan_id(const struct net_device *dev)
        return ret;
 }
 
-void mac802154_dev_set_pan_id(struct net_device *dev, u16 val)
+void mac802154_dev_set_pan_id(struct net_device *dev, __le16 val)
 {
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
 
index 38548ec2098fb1350b4f4278a1a161f7495a2eb7..03855b0677ccf8efcb0819591bae63bd8609c693 100644 (file)
@@ -80,7 +80,6 @@ mac802154_subif_rx(struct ieee802154_dev *hw, struct sk_buff *skb, u8 lqi)
        mac802154_wpans_rx(priv, skb);
 out:
        dev_kfree_skb(skb);
-       return;
 }
 
 static void mac802154_rx_worker(struct work_struct *work)
index 372d8a222b9184e2881d108a087cf9ebaad768e6..80cbee1a2f567aaf3521419bc13e9beab168bb59 100644 (file)
 
 #include "mac802154.h"
 
-static inline int mac802154_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 1)))
-               return -EINVAL;
-
-       *val = skb->data[0];
-       skb_pull(skb, 1);
-
-       return 0;
-}
-
-static inline int mac802154_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 2)))
-               return -EINVAL;
-
-       *val = skb->data[0] | (skb->data[1] << 8);
-       skb_pull(skb, 2);
-
-       return 0;
-}
-
-static inline void mac802154_haddr_copy_swap(u8 *dest, const u8 *src)
-{
-       int i;
-       for (i = 0; i < IEEE802154_ADDR_LEN; i++)
-               dest[IEEE802154_ADDR_LEN - i - 1] = src[i];
-}
-
 static int
 mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -76,19 +47,25 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
        switch (cmd) {
        case SIOCGIFADDR:
-               if (priv->pan_id == IEEE802154_PANID_BROADCAST ||
-                   priv->short_addr == IEEE802154_ADDR_BROADCAST) {
+       {
+               u16 pan_id, short_addr;
+
+               pan_id = le16_to_cpu(priv->pan_id);
+               short_addr = le16_to_cpu(priv->short_addr);
+               if (pan_id == IEEE802154_PANID_BROADCAST ||
+                   short_addr == IEEE802154_ADDR_BROADCAST) {
                        err = -EADDRNOTAVAIL;
                        break;
                }
 
                sa->family = AF_IEEE802154;
                sa->addr.addr_type = IEEE802154_ADDR_SHORT;
-               sa->addr.pan_id = priv->pan_id;
-               sa->addr.short_addr = priv->short_addr;
+               sa->addr.pan_id = pan_id;
+               sa->addr.short_addr = short_addr;
 
                err = 0;
                break;
+       }
        case SIOCSIFADDR:
                dev_warn(&dev->dev,
                         "Using DEBUGing ioctl SIOCSIFADDR isn't recommened!\n");
@@ -101,8 +78,8 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        break;
                }
 
-               priv->pan_id = sa->addr.pan_id;
-               priv->short_addr = sa->addr.short_addr;
+               priv->pan_id = cpu_to_le16(sa->addr.pan_id);
+               priv->short_addr = cpu_to_le16(sa->addr.short_addr);
 
                err = 0;
                break;
@@ -128,187 +105,70 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
 static int mac802154_header_create(struct sk_buff *skb,
                                   struct net_device *dev,
                                   unsigned short type,
-                                  const void *_daddr,
-                                  const void *_saddr,
+                                  const void *daddr,
+                                  const void *saddr,
                                   unsigned len)
 {
-       const struct ieee802154_addr *saddr = _saddr;
-       const struct ieee802154_addr *daddr = _daddr;
-       struct ieee802154_addr dev_addr;
+       struct ieee802154_hdr hdr;
        struct mac802154_sub_if_data *priv = netdev_priv(dev);
-       int pos = 2;
-       u8 head[MAC802154_FRAME_HARD_HEADER_LEN];
-       u16 fc;
+       int hlen;
 
        if (!daddr)
                return -EINVAL;
 
-       head[pos++] = mac_cb(skb)->seq; /* DSN/BSN */
-       fc = mac_cb_type(skb);
-       if (mac_cb_is_ackreq(skb))
-               fc |= IEEE802154_FC_ACK_REQ;
+       memset(&hdr.fc, 0, sizeof(hdr.fc));
+       hdr.fc.type = mac_cb_type(skb);
+       hdr.fc.security_enabled = mac_cb_is_secen(skb);
+       hdr.fc.ack_request = mac_cb_is_ackreq(skb);
 
        if (!saddr) {
                spin_lock_bh(&priv->mib_lock);
 
-               if (priv->short_addr == IEEE802154_ADDR_BROADCAST ||
-                   priv->short_addr == IEEE802154_ADDR_UNDEF ||
-                   priv->pan_id == IEEE802154_PANID_BROADCAST) {
-                       dev_addr.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(dev_addr.hwaddr, dev->dev_addr,
-                              IEEE802154_ADDR_LEN);
+               if (priv->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
+                   priv->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+                   priv->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+                       hdr.source.mode = IEEE802154_ADDR_LONG;
+                       hdr.source.extended_addr = priv->extended_addr;
                } else {
-                       dev_addr.addr_type = IEEE802154_ADDR_SHORT;
-                       dev_addr.short_addr = priv->short_addr;
+                       hdr.source.mode = IEEE802154_ADDR_SHORT;
+                       hdr.source.short_addr = priv->short_addr;
                }
 
-               dev_addr.pan_id = priv->pan_id;
-               saddr = &dev_addr;
+               hdr.source.pan_id = priv->pan_id;
 
                spin_unlock_bh(&priv->mib_lock);
+       } else {
+               hdr.source = *(const struct ieee802154_addr *)saddr;
        }
 
-       if (daddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (daddr->addr_type << IEEE802154_FC_DAMODE_SHIFT);
-
-               head[pos++] = daddr->pan_id & 0xff;
-               head[pos++] = daddr->pan_id >> 8;
-
-               if (daddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = daddr->short_addr & 0xff;
-                       head[pos++] = daddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, daddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
-
-       if (saddr->addr_type != IEEE802154_ADDR_NONE) {
-               fc |= (saddr->addr_type << IEEE802154_FC_SAMODE_SHIFT);
-
-               if ((saddr->pan_id == daddr->pan_id) &&
-                   (saddr->pan_id != IEEE802154_PANID_BROADCAST)) {
-                       /* PANID compression/intra PAN */
-                       fc |= IEEE802154_FC_INTRA_PAN;
-               } else {
-                       head[pos++] = saddr->pan_id & 0xff;
-                       head[pos++] = saddr->pan_id >> 8;
-               }
-
-               if (saddr->addr_type == IEEE802154_ADDR_SHORT) {
-                       head[pos++] = saddr->short_addr & 0xff;
-                       head[pos++] = saddr->short_addr >> 8;
-               } else {
-                       mac802154_haddr_copy_swap(head + pos, saddr->hwaddr);
-                       pos += IEEE802154_ADDR_LEN;
-               }
-       }
+       hdr.dest = *(const struct ieee802154_addr *)daddr;
 
-       head[0] = fc;
-       head[1] = fc >> 8;
+       hlen = ieee802154_hdr_push(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
 
-       memcpy(skb_push(skb, pos), head, pos);
        skb_reset_mac_header(skb);
-       skb->mac_len = pos;
+       skb->mac_len = hlen;
+
+       if (hlen + len + 2 > dev->mtu)
+               return -EMSGSIZE;
 
-       return pos;
+       return hlen;
 }
 
 static int
 mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-       const u8 *hdr = skb_mac_header(skb);
-       const u8 *tail = skb_tail_pointer(skb);
+       struct ieee802154_hdr hdr;
        struct ieee802154_addr *addr = (struct ieee802154_addr *)haddr;
-       u16 fc;
-       int da_type;
-
-       if (hdr + 3 > tail)
-               goto malformed;
-
-       fc = hdr[0] | (hdr[1] << 8);
-
-       hdr += 3;
-
-       da_type = IEEE802154_FC_DAMODE(fc);
-       addr->addr_type = IEEE802154_FC_SAMODE(fc);
-
-       switch (da_type) {
-       case IEEE802154_ADDR_NONE:
-               if (fc & IEEE802154_FC_INTRA_PAN)
-                       goto malformed;
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (fc & IEEE802154_FC_INTRA_PAN) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + IEEE802154_ADDR_LEN > tail)
-                       goto malformed;
-
-               hdr += IEEE802154_ADDR_LEN;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (fc & IEEE802154_FC_INTRA_PAN) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + 2 > tail)
-                       goto malformed;
-
-               hdr += 2;
-               break;
-       default:
-               goto malformed;
 
+       if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) {
+               pr_debug("malformed packet\n");
+               return 0;
        }
 
-       switch (addr->addr_type) {
-       case IEEE802154_ADDR_NONE:
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (!(fc & IEEE802154_FC_INTRA_PAN)) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + IEEE802154_ADDR_LEN > tail)
-                       goto malformed;
-
-               mac802154_haddr_copy_swap(addr->hwaddr, hdr);
-               hdr += IEEE802154_ADDR_LEN;
-               break;
-       case IEEE802154_ADDR_SHORT:
-               if (!(fc & IEEE802154_FC_INTRA_PAN)) {
-                       if (hdr + 2 > tail)
-                               goto malformed;
-                       addr->pan_id = hdr[0] | (hdr[1] << 8);
-                       hdr += 2;
-               }
-
-               if (hdr + 2 > tail)
-                       goto malformed;
-
-               addr->short_addr = hdr[0] | (hdr[1] << 8);
-               hdr += 2;
-               break;
-       default:
-               goto malformed;
-       }
-
-       return sizeof(struct ieee802154_addr);
-
-malformed:
-       pr_debug("malformed packet\n");
-       return 0;
+       *addr = hdr.source;
+       return sizeof(*addr);
 }
 
 static netdev_tx_t
@@ -382,8 +242,8 @@ void mac802154_wpan_setup(struct net_device *dev)
        get_random_bytes(&priv->bsn, 1);
        get_random_bytes(&priv->dsn, 1);
 
-       priv->pan_id = IEEE802154_PANID_BROADCAST;
-       priv->short_addr = IEEE802154_ADDR_BROADCAST;
+       priv->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+       priv->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
 }
 
 static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
@@ -394,13 +254,18 @@ static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
 static int
 mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
 {
+       __le16 span, sshort;
+
        pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
 
        spin_lock_bh(&sdata->mib_lock);
 
-       switch (mac_cb(skb)->da.addr_type) {
+       span = sdata->pan_id;
+       sshort = sdata->short_addr;
+
+       switch (mac_cb(skb)->dest.mode) {
        case IEEE802154_ADDR_NONE:
-               if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE)
+               if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
                        /* FIXME: check if we are PAN coordinator */
                        skb->pkt_type = PACKET_OTHERHOST;
                else
@@ -408,23 +273,22 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
                        skb->pkt_type = PACKET_HOST;
                break;
        case IEEE802154_ADDR_LONG:
-               if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
-                   mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+               if (mac_cb(skb)->dest.pan_id != span &&
+                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
                        skb->pkt_type = PACKET_OTHERHOST;
-               else if (!memcmp(mac_cb(skb)->da.hwaddr, sdata->dev->dev_addr,
-                                IEEE802154_ADDR_LEN))
+               else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
                        skb->pkt_type = PACKET_HOST;
                else
                        skb->pkt_type = PACKET_OTHERHOST;
                break;
        case IEEE802154_ADDR_SHORT:
-               if (mac_cb(skb)->da.pan_id != sdata->pan_id &&
-                   mac_cb(skb)->da.pan_id != IEEE802154_PANID_BROADCAST)
+               if (mac_cb(skb)->dest.pan_id != span &&
+                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
                        skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->da.short_addr == sdata->short_addr)
+               else if (mac_cb(skb)->dest.short_addr == sshort)
                        skb->pkt_type = PACKET_HOST;
-               else if (mac_cb(skb)->da.short_addr ==
-                                       IEEE802154_ADDR_BROADCAST)
+               else if (mac_cb(skb)->dest.short_addr ==
+                         cpu_to_le16(IEEE802154_ADDR_BROADCAST))
                        skb->pkt_type = PACKET_BROADCAST;
                else
                        skb->pkt_type = PACKET_OTHERHOST;
@@ -451,88 +315,82 @@ mac802154_subif_frame(struct mac802154_sub_if_data *sdata, struct sk_buff *skb)
        }
 }
 
-static int mac802154_parse_frame_start(struct sk_buff *skb)
+static void mac802154_print_addr(const char *name,
+                                const struct ieee802154_addr *addr)
 {
-       u8 *head = skb->data;
-       u16 fc;
+       if (addr->mode == IEEE802154_ADDR_NONE)
+               pr_debug("%s not present\n", name);
 
-       if (mac802154_fetch_skb_u16(skb, &fc) ||
-           mac802154_fetch_skb_u8(skb, &(mac_cb(skb)->seq)))
-               goto err;
+       pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
+       if (addr->mode == IEEE802154_ADDR_SHORT) {
+               pr_debug("%s is short: %04x\n", name,
+                        le16_to_cpu(addr->short_addr));
+       } else {
+               u64 hw = swab64((__force u64) addr->extended_addr);
 
-       pr_debug("fc: %04x dsn: %02x\n", fc, head[2]);
-
-       mac_cb(skb)->flags = IEEE802154_FC_TYPE(fc);
-       mac_cb(skb)->sa.addr_type = IEEE802154_FC_SAMODE(fc);
-       mac_cb(skb)->da.addr_type = IEEE802154_FC_DAMODE(fc);
+               pr_debug("%s is hardware: %8phC\n", name, &hw);
+       }
+}
 
-       if (fc & IEEE802154_FC_INTRA_PAN)
-               mac_cb(skb)->flags |= MAC_CB_FLAG_INTRAPAN;
+static int mac802154_parse_frame_start(struct sk_buff *skb)
+{
+       int hlen;
+       struct ieee802154_hdr hdr;
 
-       if (mac_cb(skb)->da.addr_type != IEEE802154_ADDR_NONE) {
-               if (mac802154_fetch_skb_u16(skb, &(mac_cb(skb)->da.pan_id)))
-                       goto err;
+       hlen = ieee802154_hdr_pull(skb, &hdr);
+       if (hlen < 0)
+               return -EINVAL;
 
-               /* source PAN id compression */
-               if (mac_cb_is_intrapan(skb))
-                       mac_cb(skb)->sa.pan_id = mac_cb(skb)->da.pan_id;
+       skb->mac_len = hlen;
 
-               pr_debug("dest PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
+       pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr.fc),
+                hdr.seq);
 
-               if (mac_cb(skb)->da.addr_type == IEEE802154_ADDR_SHORT) {
-                       u16 *da = &(mac_cb(skb)->da.short_addr);
+       mac_cb(skb)->flags = hdr.fc.type;
 
-                       if (mac802154_fetch_skb_u16(skb, da))
-                               goto err;
+       if (hdr.fc.ack_request)
+               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
+       if (hdr.fc.security_enabled)
+               mac_cb(skb)->flags |= MAC_CB_FLAG_SECEN;
 
-                       pr_debug("destination address is short: %04x\n",
-                                mac_cb(skb)->da.short_addr);
-               } else {
-                       if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
-                               goto err;
+       mac802154_print_addr("destination", &hdr.dest);
+       mac802154_print_addr("source", &hdr.source);
 
-                       mac802154_haddr_copy_swap(mac_cb(skb)->da.hwaddr,
-                                                 skb->data);
-                       skb_pull(skb, IEEE802154_ADDR_LEN);
+       mac_cb(skb)->source = hdr.source;
+       mac_cb(skb)->dest = hdr.dest;
 
-                       pr_debug("destination address is hardware\n");
-               }
-       }
+       if (hdr.fc.security_enabled) {
+               u64 key;
 
-       if (mac_cb(skb)->sa.addr_type != IEEE802154_ADDR_NONE) {
-               /* non PAN-compression, fetch source address id */
-               if (!(mac_cb_is_intrapan(skb))) {
-                       u16 *sa_pan = &(mac_cb(skb)->sa.pan_id);
+               pr_debug("seclevel %i\n", hdr.sec.level);
 
-                       if (mac802154_fetch_skb_u16(skb, sa_pan))
-                               goto err;
-               }
-
-               pr_debug("source PAN addr: %04x\n", mac_cb(skb)->da.pan_id);
-
-               if (mac_cb(skb)->sa.addr_type == IEEE802154_ADDR_SHORT) {
-                       u16 *sa = &(mac_cb(skb)->sa.short_addr);
-
-                       if (mac802154_fetch_skb_u16(skb, sa))
-                               goto err;
+               switch (hdr.sec.key_id_mode) {
+               case IEEE802154_SCF_KEY_IMPLICIT:
+                       pr_debug("implicit key\n");
+                       break;
 
-                       pr_debug("source address is short: %04x\n",
-                                mac_cb(skb)->sa.short_addr);
-               } else {
-                       if (!pskb_may_pull(skb, IEEE802154_ADDR_LEN))
-                               goto err;
+               case IEEE802154_SCF_KEY_INDEX:
+                       pr_debug("key %02x\n", hdr.sec.key_id);
+                       break;
 
-                       mac802154_haddr_copy_swap(mac_cb(skb)->sa.hwaddr,
-                                                 skb->data);
-                       skb_pull(skb, IEEE802154_ADDR_LEN);
+               case IEEE802154_SCF_KEY_SHORT_INDEX:
+                       pr_debug("key %04x:%04x %02x\n",
+                                le32_to_cpu(hdr.sec.short_src) >> 16,
+                                le32_to_cpu(hdr.sec.short_src) & 0xffff,
+                                hdr.sec.key_id);
+                       break;
 
-                       pr_debug("source address is hardware\n");
+               case IEEE802154_SCF_KEY_HW_INDEX:
+                       key = swab64((__force u64) hdr.sec.extended_src);
+                       pr_debug("key source %8phC %02x\n", &key,
+                                hdr.sec.key_id);
+                       break;
                }
+
+               return -EINVAL;
        }
 
        return 0;
-err:
-       return -EINVAL;
 }
 
 void mac802154_wpans_rx(struct mac802154_priv *priv, struct sk_buff *skb)
index c37467562fd04ebd5bf7ac1a02bef56e3bd9017a..e9410d17619df52b76620e6a81a51e3c9a549f33 100644 (file)
@@ -513,7 +513,6 @@ config NFT_QUEUE
 
 config NFT_REJECT
        depends on NF_TABLES
-       depends on NF_TABLES_IPV6 || !NF_TABLES_IPV6
        default m if NETFILTER_ADVANCED=n
        tristate "Netfilter nf_tables reject support"
        help
@@ -521,6 +520,11 @@ config NFT_REJECT
          explicitly deny and notify via TCP reset/ICMP informational errors
          unallowed traffic.
 
+config NFT_REJECT_INET
+       depends on NF_TABLES_INET
+       default NFT_REJECT
+       tristate
+
 config NFT_COMPAT
        depends on NF_TABLES
        depends on NETFILTER_XTABLES
index ee9c4de5f8eded2b7e545eea47dfbd1f42edfafc..bffdad774da753131937d53ba1693af8f25b83a0 100644 (file)
@@ -79,6 +79,7 @@ obj-$(CONFIG_NFT_LIMIT)               += nft_limit.o
 obj-$(CONFIG_NFT_NAT)          += nft_nat.o
 obj-$(CONFIG_NFT_QUEUE)                += nft_queue.o
 obj-$(CONFIG_NFT_REJECT)       += nft_reject.o
+obj-$(CONFIG_NFT_REJECT_INET)  += nft_reject_inet.o
 obj-$(CONFIG_NFT_RBTREE)       += nft_rbtree.o
 obj-$(CONFIG_NFT_HASH)         += nft_hash.o
 obj-$(CONFIG_NFT_COUNTER)      += nft_counter.o
index 44cd4f58adf08b914b871d7399942fb58168a623..2f7f5c32c6f90a0eb376d7921aecf167564329ce 100644 (file)
@@ -61,6 +61,15 @@ config IP_SET_HASH_IP
 
          To compile it as a module, choose M here.  If unsure, say N.
 
+config IP_SET_HASH_IPMARK
+       tristate "hash:ip,mark set support"
+       depends on IP_SET
+       help
+         This option adds the hash:ip,mark set type support, by which one
+         can store IPv4/IPv6 address and mark pairs.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_SET_HASH_IPPORT
        tristate "hash:ip,port set support"
        depends on IP_SET
index 44b2d38476faeb75a95c5ac8348330a99aa866fd..231f10196cb906fd4cbbe5f58263c5a3ba97886a 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o
 
 # hash types
 obj-$(CONFIG_IP_SET_HASH_IP) += ip_set_hash_ip.o
+obj-$(CONFIG_IP_SET_HASH_IPMARK) += ip_set_hash_ipmark.o
 obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o
 obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o
 obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o
index de770ec39e5112e4cbf5b4b90629144bad1d957b..117208321f16997af9f24bee1f86519f8f8fa26e 100644 (file)
@@ -54,10 +54,10 @@ MODULE_DESCRIPTION("core IP set support");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
 
 /* When the nfnl mutex is held: */
-#define nfnl_dereference(p)            \
+#define ip_set_dereference(p)          \
        rcu_dereference_protected(p, 1)
-#define nfnl_set(inst, id)                     \
-       nfnl_dereference((inst)->ip_set_list)[id]
+#define ip_set(inst, id)               \
+       ip_set_dereference((inst)->ip_set_list)[id]
 
 /*
  * The set types are implemented in modules and registered set types
@@ -368,6 +368,8 @@ ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
 
        if (tb[IPSET_ATTR_CADT_FLAGS])
                cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+       if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
+               set->flags |= IPSET_CREATE_FLAG_FORCEADD;
        for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
                if (!add_extension(id, cadt_flags, tb))
                        continue;
@@ -510,7 +512,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
 
        if (opt->dim < set->type->dimension ||
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
-               return 0;
+               return -IPSET_ERR_TYPE_MISMATCH;
 
        write_lock_bh(&set->lock);
        ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
@@ -533,7 +535,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
 
        if (opt->dim < set->type->dimension ||
            !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
-               return 0;
+               return -IPSET_ERR_TYPE_MISMATCH;
 
        write_lock_bh(&set->lock);
        ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
@@ -640,7 +642,7 @@ ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)
                return IPSET_INVALID_ID;
 
        nfnl_lock(NFNL_SUBSYS_IPSET);
-       set = nfnl_set(inst, index);
+       set = ip_set(inst, index);
        if (set)
                __ip_set_get(set);
        else
@@ -666,7 +668,7 @@ ip_set_nfnl_put(struct net *net, ip_set_id_t index)
 
        nfnl_lock(NFNL_SUBSYS_IPSET);
        if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */
-               set = nfnl_set(inst, index);
+               set = ip_set(inst, index);
                if (set != NULL)
                        __ip_set_put(set);
        }
@@ -734,7 +736,7 @@ find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)
 
        *id = IPSET_INVALID_ID;
        for (i = 0; i < inst->ip_set_max; i++) {
-               set = nfnl_set(inst, i);
+               set = ip_set(inst, i);
                if (set != NULL && STREQ(set->name, name)) {
                        *id = i;
                        break;
@@ -760,7 +762,7 @@ find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
 
        *index = IPSET_INVALID_ID;
        for (i = 0;  i < inst->ip_set_max; i++) {
-               s = nfnl_set(inst, i);
+               s = ip_set(inst, i);
                if (s == NULL) {
                        if (*index == IPSET_INVALID_ID)
                                *index = i;
@@ -883,7 +885,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
                if (!list)
                        goto cleanup;
                /* nfnl mutex is held, both lists are valid */
-               tmp = nfnl_dereference(inst->ip_set_list);
+               tmp = ip_set_dereference(inst->ip_set_list);
                memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max);
                rcu_assign_pointer(inst->ip_set_list, list);
                /* Make sure all current packets have passed through */
@@ -900,7 +902,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
         * Finally! Add our shiny new set to the list, and be done.
         */
        pr_debug("create: '%s' created with index %u!\n", set->name, index);
-       nfnl_set(inst, index) = set;
+       ip_set(inst, index) = set;
 
        return ret;
 
@@ -925,10 +927,10 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
 static void
 ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)
 {
-       struct ip_set *set = nfnl_set(inst, index);
+       struct ip_set *set = ip_set(inst, index);
 
        pr_debug("set: %s\n",  set->name);
-       nfnl_set(inst, index) = NULL;
+       ip_set(inst, index) = NULL;
 
        /* Must call it without holding any lock */
        set->variant->destroy(set);
@@ -962,7 +964,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
        read_lock_bh(&ip_set_ref_lock);
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < inst->ip_set_max; i++) {
-                       s = nfnl_set(inst, i);
+                       s = ip_set(inst, i);
                        if (s != NULL && s->ref) {
                                ret = -IPSET_ERR_BUSY;
                                goto out;
@@ -970,7 +972,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
                }
                read_unlock_bh(&ip_set_ref_lock);
                for (i = 0; i < inst->ip_set_max; i++) {
-                       s = nfnl_set(inst, i);
+                       s = ip_set(inst, i);
                        if (s != NULL)
                                ip_set_destroy_set(inst, i);
                }
@@ -1020,7 +1022,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
 
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < inst->ip_set_max; i++) {
-                       s = nfnl_set(inst, i);
+                       s = ip_set(inst, i);
                        if (s != NULL)
                                ip_set_flush_set(s);
                }
@@ -1074,7 +1076,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
 
        name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
        for (i = 0; i < inst->ip_set_max; i++) {
-               s = nfnl_set(inst, i);
+               s = ip_set(inst, i);
                if (s != NULL && STREQ(s->name, name2)) {
                        ret = -IPSET_ERR_EXIST_SETNAME2;
                        goto out;
@@ -1134,8 +1136,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
 
        write_lock_bh(&ip_set_ref_lock);
        swap(from->ref, to->ref);
-       nfnl_set(inst, from_id) = to;
-       nfnl_set(inst, to_id) = from;
+       ip_set(inst, from_id) = to;
+       ip_set(inst, to_id) = from;
        write_unlock_bh(&ip_set_ref_lock);
 
        return 0;
@@ -1157,7 +1159,7 @@ ip_set_dump_done(struct netlink_callback *cb)
        struct ip_set_net *inst = (struct ip_set_net *)cb->args[IPSET_CB_NET];
        if (cb->args[IPSET_CB_ARG0]) {
                pr_debug("release set %s\n",
-                        nfnl_set(inst, cb->args[IPSET_CB_INDEX])->name);
+                        ip_set(inst, cb->args[IPSET_CB_INDEX])->name);
                __ip_set_put_byindex(inst,
                        (ip_set_id_t) cb->args[IPSET_CB_INDEX]);
        }
@@ -1254,7 +1256,7 @@ dump_last:
                 dump_type, dump_flags, cb->args[IPSET_CB_INDEX]);
        for (; cb->args[IPSET_CB_INDEX] < max; cb->args[IPSET_CB_INDEX]++) {
                index = (ip_set_id_t) cb->args[IPSET_CB_INDEX];
-               set = nfnl_set(inst, index);
+               set = ip_set(inst, index);
                if (set == NULL) {
                        if (dump_type == DUMP_ONE) {
                                ret = -ENOENT;
@@ -1332,7 +1334,7 @@ next_set:
 release_refcount:
        /* If there was an error or set is done, release set */
        if (ret || !cb->args[IPSET_CB_ARG0]) {
-               pr_debug("release set %s\n", nfnl_set(inst, index)->name);
+               pr_debug("release set %s\n", ip_set(inst, index)->name);
                __ip_set_put_byindex(inst, index);
                cb->args[IPSET_CB_ARG0] = 0;
        }
@@ -1887,7 +1889,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
                find_set_and_id(inst, req_get->set.name, &id);
                req_get->set.index = id;
                if (id != IPSET_INVALID_ID)
-                       req_get->family = nfnl_set(inst, id)->family;
+                       req_get->family = ip_set(inst, id)->family;
                nfnl_unlock(NFNL_SUBSYS_IPSET);
                goto copy;
        }
@@ -1901,7 +1903,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
                        goto done;
                }
                nfnl_lock(NFNL_SUBSYS_IPSET);
-               set = nfnl_set(inst, req_get->set.index);
+               set = ip_set(inst, req_get->set.index);
                strncpy(req_get->set.name, set ? set->name : "",
                        IPSET_MAXNAMELEN);
                nfnl_unlock(NFNL_SUBSYS_IPSET);
@@ -1945,7 +1947,6 @@ ip_set_net_init(struct net *net)
                return -ENOMEM;
        inst->is_deleted = 0;
        rcu_assign_pointer(inst->ip_set_list, list);
-       pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
        return 0;
 }
 
@@ -1960,7 +1961,7 @@ ip_set_net_exit(struct net *net)
        inst->is_deleted = 1; /* flag for ip_set_nfnl_put */
 
        for (i = 0; i < inst->ip_set_max; i++) {
-               set = nfnl_set(inst, i);
+               set = ip_set(inst, i);
                if (set != NULL)
                        ip_set_destroy_set(inst, i);
        }
@@ -1996,6 +1997,7 @@ ip_set_init(void)
                nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
                return ret;
        }
+       pr_info("ip_set: protocol %u\n", IPSET_PROTOCOL);
        return 0;
 }
 
index be6932ad3a8626d6c06e99091b32f540b7afd338..61c7fb052802e7c0cb291289ee29c484b4f84179 100644 (file)
@@ -263,6 +263,9 @@ struct htype {
        u32 maxelem;            /* max elements in the hash */
        u32 elements;           /* current element (vs timeout) */
        u32 initval;            /* random jhash init value */
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       u32 markmask;           /* markmask value for mark mask to store */
+#endif
        struct timer_list gc;   /* garbage collection when timeout enabled */
        struct mtype_elem next; /* temporary storage for uadd */
 #ifdef IP_SET_HASH_WITH_MULTI
@@ -453,6 +456,9 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
               a->timeout == b->timeout &&
 #ifdef IP_SET_HASH_WITH_NETMASK
               x->netmask == y->netmask &&
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+              x->markmask == y->markmask &&
 #endif
               a->extensions == b->extensions;
 }
@@ -627,6 +633,18 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
        bool flag_exist = flags & IPSET_FLAG_EXIST;
        u32 key, multi = 0;
 
+       if (h->elements >= h->maxelem && SET_WITH_FORCEADD(set)) {
+               rcu_read_lock_bh();
+               t = rcu_dereference_bh(h->table);
+               key = HKEY(value, h->initval, t->htable_bits);
+               n = hbucket(t,key);
+               if (n->pos) {
+                       /* Choosing the first entry in the array to replace */
+                       j = 0;
+                       goto reuse_slot;
+               }
+               rcu_read_unlock_bh();
+       }
        if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
                /* FIXME: when set is full, we slow down here */
                mtype_expire(set, h, NLEN(set->family), set->dsize);
@@ -907,6 +925,10 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
        if (h->netmask != HOST_MASK &&
            nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
                goto nla_put_failure;
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       if (nla_put_u32(skb, IPSET_ATTR_MARKMASK, h->markmask))
+               goto nla_put_failure;
 #endif
        if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
            nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
@@ -1016,6 +1038,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
                            struct nlattr *tb[], u32 flags)
 {
        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       u32 markmask;
+#endif
        u8 hbits;
 #ifdef IP_SET_HASH_WITH_NETMASK
        u8 netmask;
@@ -1026,6 +1051,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 
        if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
                return -IPSET_ERR_INVALID_FAMILY;
+
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       markmask = 0xffffffff;
+#endif
 #ifdef IP_SET_HASH_WITH_NETMASK
        netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
        pr_debug("Create set %s with family %s\n",
@@ -1034,6 +1063,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
 
        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
+#ifdef IP_SET_HASH_WITH_MARKMASK
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_MARKMASK) ||
+#endif
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
                return -IPSET_ERR_PROTOCOL;
@@ -1057,6 +1089,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
                        return -IPSET_ERR_INVALID_NETMASK;
        }
 #endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       if (tb[IPSET_ATTR_MARKMASK]) {
+               markmask = ntohl(nla_get_u32(tb[IPSET_ATTR_MARKMASK]));
+
+               if ((markmask > 4294967295u) || markmask == 0)
+                       return -IPSET_ERR_INVALID_MARKMASK;
+       }
+#endif
 
        hsize = sizeof(*h);
 #ifdef IP_SET_HASH_WITH_NETS
@@ -1070,6 +1110,9 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
        h->maxelem = maxelem;
 #ifdef IP_SET_HASH_WITH_NETMASK
        h->netmask = netmask;
+#endif
+#ifdef IP_SET_HASH_WITH_MARKMASK
+       h->markmask = markmask;
 #endif
        get_random_bytes(&h->initval, sizeof(h->initval));
        set->timeout = IPSET_NO_TIMEOUT;
index e65fc2423d56dd2b21cee513786eec41ceabefc9..dd40607f878e28e8c5c411a24fb8e36ef7db5d46 100644 (file)
@@ -25,7 +25,8 @@
 
 #define IPSET_TYPE_REV_MIN     0
 /*                             1          Counters support */
-#define IPSET_TYPE_REV_MAX     2       /* Comments support */
+/*                             2          Comments support */
+#define IPSET_TYPE_REV_MAX     3       /* Forceadd support */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c
new file mode 100644 (file)
index 0000000..4eff0a2
--- /dev/null
@@ -0,0 +1,321 @@
+/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2013 Smoothwall Ltd. <vytas.dauksa@smoothwall.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Kernel module implementing an IP set type: the hash:ip,mark type */
+
+#include <linux/jhash.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <net/netlink.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/ipset/pfxlen.h>
+#include <linux/netfilter/ipset/ip_set.h>
+#include <linux/netfilter/ipset/ip_set_hash.h>
+
+#define IPSET_TYPE_REV_MIN     0
+#define IPSET_TYPE_REV_MAX     1       /* Forceadd support */
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>");
+IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+MODULE_ALIAS("ip_set_hash:ip,mark");
+
+/* Type specific function prefix */
+#define HTYPE          hash_ipmark
+#define IP_SET_HASH_WITH_MARKMASK
+
+/* IPv4 variant */
+
+/* Member elements */
+struct hash_ipmark4_elem {
+       __be32 ip;
+       __u32 mark;
+};
+
+/* Common functions */
+
+static inline bool
+hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1,
+                       const struct hash_ipmark4_elem *ip2,
+                       u32 *multi)
+{
+       return ip1->ip == ip2->ip &&
+              ip1->mark == ip2->mark;
+}
+
+static bool
+hash_ipmark4_data_list(struct sk_buff *skb,
+                      const struct hash_ipmark4_elem *data)
+{
+       if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
+           nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
+               goto nla_put_failure;
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline void
+hash_ipmark4_data_next(struct hash_ipmark4_elem *next,
+                      const struct hash_ipmark4_elem *d)
+{
+       next->ip = d->ip;
+}
+
+#define MTYPE           hash_ipmark4
+#define PF              4
+#define HOST_MASK       32
+#define HKEY_DATALEN   sizeof(struct hash_ipmark4_elem)
+#include "ip_set_hash_gen.h"
+
+static int
+hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb,
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, struct ip_set_adt_opt *opt)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark4_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+
+       e.mark = skb->mark;
+       e.mark &= h->markmask;
+
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+       return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
+}
+
+static int
+hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[],
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark4_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+       u32 ip, ip_to = 0;
+       int ret;
+
+       if (unlikely(!tb[IPSET_ATTR_IP] ||
+                    !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_LINENO])
+               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
+       ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
+             ip_set_get_extensions(set, tb, &ext);
+       if (ret)
+               return ret;
+
+       e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK]));
+       e.mark &= h->markmask;
+
+       if (adt == IPSET_TEST ||
+           !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) {
+               ret = adtfn(set, &e, &ext, &ext, flags);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ip_to = ip = ntohl(e.ip);
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
+               if (ret)
+                       return ret;
+               if (ip > ip_to)
+                       swap(ip, ip_to);
+       } else if (tb[IPSET_ATTR_CIDR]) {
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+               if (!cidr || cidr > 32)
+                       return -IPSET_ERR_INVALID_CIDR;
+               ip_set_mask_from_to(ip, ip_to, cidr);
+       }
+
+       if (retried)
+               ip = ntohl(h->next.ip);
+       for (; !before(ip_to, ip); ip++) {
+               e.ip = htonl(ip);
+               ret = adtfn(set, &e, &ext, &ext, flags);
+
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
+}
+
+/* IPv6 variant */
+
+struct hash_ipmark6_elem {
+       union nf_inet_addr ip;
+       __u32 mark;
+};
+
+/* Common functions */
+
+static inline bool
+hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1,
+                       const struct hash_ipmark6_elem *ip2,
+                       u32 *multi)
+{
+       return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
+              ip1->mark == ip2->mark;
+}
+
+static bool
+hash_ipmark6_data_list(struct sk_buff *skb,
+                      const struct hash_ipmark6_elem *data)
+{
+       if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
+           nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark)))
+               goto nla_put_failure;
+       return 0;
+
+nla_put_failure:
+       return 1;
+}
+
+static inline void
+hash_ipmark6_data_next(struct hash_ipmark4_elem *next,
+                      const struct hash_ipmark6_elem *d)
+{
+}
+
+#undef MTYPE
+#undef PF
+#undef HOST_MASK
+#undef HKEY_DATALEN
+
+#define MTYPE          hash_ipmark6
+#define PF             6
+#define HOST_MASK      128
+#define HKEY_DATALEN   sizeof(struct hash_ipmark6_elem)
+#define        IP_SET_EMIT_CREATE
+#include "ip_set_hash_gen.h"
+
+
+static int
+hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb,
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, struct ip_set_adt_opt *opt)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark6_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+
+       e.mark = skb->mark;
+       e.mark &= h->markmask;
+
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+       return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
+}
+
+static int
+hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[],
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
+{
+       const struct hash_ipmark *h = set->data;
+       ipset_adtfn adtfn = set->variant->adt[adt];
+       struct hash_ipmark6_elem e = { };
+       struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+       int ret;
+
+       if (unlikely(!tb[IPSET_ATTR_IP] ||
+                    !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
+                    !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
+                    tb[IPSET_ATTR_IP_TO] ||
+                    tb[IPSET_ATTR_CIDR]))
+               return -IPSET_ERR_PROTOCOL;
+
+       if (tb[IPSET_ATTR_LINENO])
+               *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
+
+       ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
+             ip_set_get_extensions(set, tb, &ext);
+       if (ret)
+               return ret;
+
+       e.mark = ntohl(nla_get_u32(tb[IPSET_ATTR_MARK]));
+       e.mark &= h->markmask;
+
+       if (adt == IPSET_TEST) {
+               ret = adtfn(set, &e, &ext, &ext, flags);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ret = adtfn(set, &e, &ext, &ext, flags);
+       if (ret && !ip_set_eexist(ret, flags))
+               return ret;
+       else
+               ret = 0;
+
+       return ret;
+}
+
+static struct ip_set_type hash_ipmark_type __read_mostly = {
+       .name           = "hash:ip,mark",
+       .protocol       = IPSET_PROTOCOL,
+       .features       = IPSET_TYPE_IP | IPSET_TYPE_MARK,
+       .dimension      = IPSET_DIM_TWO,
+       .family         = NFPROTO_UNSPEC,
+       .revision_min   = IPSET_TYPE_REV_MIN,
+       .revision_max   = IPSET_TYPE_REV_MAX,
+       .create         = hash_ipmark_create,
+       .create_policy  = {
+               [IPSET_ATTR_MARKMASK]   = { .type = NLA_U32 },
+               [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
+               [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
+               [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
+               [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+       },
+       .adt_policy     = {
+               [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
+               [IPSET_ATTR_MARK]       = { .type = NLA_U32 },
+               [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
+               [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
+               [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
+               [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
+               [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
+               [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING },
+       },
+       .me             = THIS_MODULE,
+};
+
+static int __init
+hash_ipmark_init(void)
+{
+       return ip_set_type_register(&hash_ipmark_type);
+}
+
+static void __exit
+hash_ipmark_fini(void)
+{
+       ip_set_type_unregister(&hash_ipmark_type);
+}
+
+module_init(hash_ipmark_init);
+module_exit(hash_ipmark_fini);
index 525a595dd1fe4bf0efe6db7ca9cc06d995c66430..7597b82a8b033bd37c8a5f64dae02e8aa9137a19 100644 (file)
@@ -27,7 +27,8 @@
 #define IPSET_TYPE_REV_MIN     0
 /*                             1    SCTP and UDPLITE support added */
 /*                             2    Counters support added */
-#define IPSET_TYPE_REV_MAX     3 /* Comments support added */
+/*                             3    Comments support added */
+#define IPSET_TYPE_REV_MAX     4 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index f5636631466eb3ee98509e8b832e46da4ad9a417..672655ffd573404b2f2f5bf097b7a8d01f0c4c14 100644 (file)
@@ -27,7 +27,8 @@
 #define IPSET_TYPE_REV_MIN     0
 /*                             1    SCTP and UDPLITE support added */
 /*                             2    Counters support added */
-#define IPSET_TYPE_REV_MAX     3 /* Comments support added */
+/*                             3    Comments support added */
+#define IPSET_TYPE_REV_MAX     4 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 5d87fe8a41ffa4888a70b6d91897360e30c253bc..7308d84f9277813f16351b692f75218ff1a451b3 100644 (file)
@@ -29,7 +29,8 @@
 /*                             2    Range as input support for IPv4 added */
 /*                             3    nomatch flag support added */
 /*                             4    Counters support added */
-#define IPSET_TYPE_REV_MAX     5 /* Comments support added */
+/*                             5    Comments support added */
+#define IPSET_TYPE_REV_MAX     6 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 8295cf4f9fdcfdb3d3da4b72792add9fc83156ad..4c7d495783a3aefa9447d4b37114bd3715928b0a 100644 (file)
@@ -26,7 +26,8 @@
 /*                             1    Range as input support for IPv4 added */
 /*                             2    nomatch flag support added */
 /*                             3    Counters support added */
-#define IPSET_TYPE_REV_MAX     4 /* Comments support added */
+/*                             4    Comments support added */
+#define IPSET_TYPE_REV_MAX     5 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index b827a0f1f3510bc0fa4e6b0a498738806ac62e81..db2606805b3575b91a87cded299222c571fbf6ba 100644 (file)
@@ -27,7 +27,8 @@
 /*                             1    nomatch flag support added */
 /*                             2    /0 support added */
 /*                             3    Counters support added */
-#define IPSET_TYPE_REV_MAX     4 /* Comments support added */
+/*                             4    Comments support added */
+#define IPSET_TYPE_REV_MAX     5 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 6226803fc490ce33c53994c344a1c034b9b0cce9..3e99987e4bf248f6d6085118dba52a4c24ee108a 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/netfilter/ipset/ip_set_hash.h>
 
 #define IPSET_TYPE_REV_MIN     0
-#define IPSET_TYPE_REV_MAX     0
+#define IPSET_TYPE_REV_MAX     1       /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
@@ -112,10 +112,10 @@ hash_netnet4_data_list(struct sk_buff *skb,
            (flags &&
             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
                goto nla_put_failure;
-       return 0;
+       return false;
 
 nla_put_failure:
-       return 1;
+       return true;
 }
 
 static inline void
@@ -334,10 +334,10 @@ hash_netnet6_data_list(struct sk_buff *skb,
            (flags &&
             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
                goto nla_put_failure;
-       return 0;
+       return false;
 
 nla_put_failure:
-       return 1;
+       return true;
 }
 
 static inline void
index 7097fb0141bf6e1363ca0b0342451e66c34773b4..1c645fbd09c7d6bcb337b90977ae2536b2ec9ebd 100644 (file)
@@ -28,7 +28,8 @@
 /*                             2    Range as input support for IPv4 added */
 /*                             3    nomatch flag support added */
 /*                             4    Counters support added */
-#define IPSET_TYPE_REV_MAX     5 /* Comments support added */
+/*                             5    Comments support added */
+#define IPSET_TYPE_REV_MAX     6 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
index 703d1192a6a225214f1ffd28c6ab926110942c32..c0d2ba73f8b2394995bba3737a833cc47138d581 100644 (file)
@@ -25,7 +25,8 @@
 #include <linux/netfilter/ipset/ip_set_hash.h>
 
 #define IPSET_TYPE_REV_MIN     0
-#define IPSET_TYPE_REV_MAX     0 /* Comments support added */
+/*                             0    Comments support added */
+#define IPSET_TYPE_REV_MAX     1 /* Forceadd support added */
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
index 4f29fa97044b18523967cdc8b8c6ab272376a2fb..04d15fdc99eec407545c2c598c7a158de0daade9 100644 (file)
@@ -7,8 +7,8 @@
 
 #define E(a, b, c, d) \
        {.ip6 = { \
-               __constant_htonl(a), __constant_htonl(b), \
-               __constant_htonl(c), __constant_htonl(d), \
+               htonl(a), htonl(b), \
+               htonl(c), htonl(d), \
        } }
 
 /*
index 59a1a85bcb3eb888348cbc818789ebb16aa01cc9..a8eb0a89326ab504ec83421ea7b66aba3ab3a057 100644 (file)
@@ -871,11 +871,11 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
        cp->protocol       = p->protocol;
        ip_vs_addr_set(p->af, &cp->caddr, p->caddr);
        cp->cport          = p->cport;
-       ip_vs_addr_set(p->af, &cp->vaddr, p->vaddr);
-       cp->vport          = p->vport;
-       /* proto should only be IPPROTO_IP if d_addr is a fwmark */
+       /* proto should only be IPPROTO_IP if p->vaddr is a fwmark */
        ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
-                      &cp->daddr, daddr);
+                      &cp->vaddr, p->vaddr);
+       cp->vport          = p->vport;
+       ip_vs_addr_set(p->af, &cp->daddr, daddr);
        cp->dport          = dport;
        cp->flags          = flags;
        cp->fwmark         = fwmark;
index 35be035ee0cec79b5b797efb46c287661b8dbc93..c42e83d2751cdc2dd1324a3b9db3e36b615d2fb5 100644 (file)
@@ -2177,10 +2177,10 @@ static int ip_vs_stats_percpu_show(struct seq_file *seq, void *v)
                __u64 inbytes, outbytes;
 
                do {
-                       start = u64_stats_fetch_begin_bh(&u->syncp);
+                       start = u64_stats_fetch_begin_irq(&u->syncp);
                        inbytes = u->ustats.inbytes;
                        outbytes = u->ustats.outbytes;
-               } while (u64_stats_fetch_retry_bh(&u->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&u->syncp, start));
 
                seq_printf(seq, "%3X %8X %8X %8X %16LX %16LX\n",
                           i, u->ustats.conns, u->ustats.inpkts,
@@ -3580,7 +3580,7 @@ out:
 }
 
 
-static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
+static const struct genl_ops ip_vs_genl_ops[] = {
        {
                .cmd    = IPVS_CMD_NEW_SERVICE,
                .flags  = GENL_ADMIN_PERM,
index ca056a331e60b23f1b6e542fd640b2b996878335..547ff33c1efdb0cb92f3f8890640a77bba3a73b5 100644 (file)
@@ -238,7 +238,7 @@ static void ip_vs_lblc_flush(struct ip_vs_service *svc)
 
        spin_lock_bh(&svc->sched_lock);
        tbl->dead = 1;
-       for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0; i < IP_VS_LBLC_TAB_SIZE; i++) {
                hlist_for_each_entry_safe(en, next, &tbl->bucket[i], list) {
                        ip_vs_lblc_del(en);
                        atomic_dec(&tbl->entries);
@@ -265,7 +265,7 @@ static inline void ip_vs_lblc_full_check(struct ip_vs_service *svc)
        unsigned long now = jiffies;
        int i, j;
 
-       for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0, j = tbl->rover; i < IP_VS_LBLC_TAB_SIZE; i++) {
                j = (j + 1) & IP_VS_LBLC_TAB_MASK;
 
                spin_lock(&svc->sched_lock);
@@ -321,7 +321,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
        if (goal > tbl->max_size/2)
                goal = tbl->max_size/2;
 
-       for (i=0, j=tbl->rover; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0, j = tbl->rover; i < IP_VS_LBLC_TAB_SIZE; i++) {
                j = (j + 1) & IP_VS_LBLC_TAB_MASK;
 
                spin_lock(&svc->sched_lock);
@@ -340,7 +340,7 @@ static void ip_vs_lblc_check_expire(unsigned long data)
        tbl->rover = j;
 
   out:
-       mod_timer(&tbl->periodic_timer, jiffies+CHECK_EXPIRE_INTERVAL);
+       mod_timer(&tbl->periodic_timer, jiffies + CHECK_EXPIRE_INTERVAL);
 }
 
 
@@ -363,7 +363,7 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc)
        /*
         *    Initialize the hash buckets
         */
-       for (i=0; i<IP_VS_LBLC_TAB_SIZE; i++) {
+       for (i = 0; i < IP_VS_LBLC_TAB_SIZE; i++) {
                INIT_HLIST_HEAD(&tbl->bucket[i]);
        }
        tbl->max_size = IP_VS_LBLC_TAB_SIZE*16;
@@ -536,8 +536,7 @@ out:
 /*
  *      IPVS LBLC Scheduler structure
  */
-static struct ip_vs_scheduler ip_vs_lblc_scheduler =
-{
+static struct ip_vs_scheduler ip_vs_lblc_scheduler = {
        .name =                 "lblc",
        .refcnt =               ATOMIC_INIT(0),
        .module =               THIS_MODULE,
index 8824ed0ccc9cd544e4799484ea7158f1f8db9c67..6dba48efe01e83bebda511e56410b403a8d4b968 100644 (file)
@@ -60,8 +60,59 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
                                      const struct nlattr *attr) __read_mostly;
 EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
 
-DEFINE_SPINLOCK(nf_conntrack_lock);
-EXPORT_SYMBOL_GPL(nf_conntrack_lock);
+__cacheline_aligned_in_smp spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS];
+EXPORT_SYMBOL_GPL(nf_conntrack_locks);
+
+__cacheline_aligned_in_smp DEFINE_SPINLOCK(nf_conntrack_expect_lock);
+EXPORT_SYMBOL_GPL(nf_conntrack_expect_lock);
+
+static void nf_conntrack_double_unlock(unsigned int h1, unsigned int h2)
+{
+       h1 %= CONNTRACK_LOCKS;
+       h2 %= CONNTRACK_LOCKS;
+       spin_unlock(&nf_conntrack_locks[h1]);
+       if (h1 != h2)
+               spin_unlock(&nf_conntrack_locks[h2]);
+}
+
+/* return true if we need to recompute hashes (in case hash table was resized) */
+static bool nf_conntrack_double_lock(struct net *net, unsigned int h1,
+                                    unsigned int h2, unsigned int sequence)
+{
+       h1 %= CONNTRACK_LOCKS;
+       h2 %= CONNTRACK_LOCKS;
+       if (h1 <= h2) {
+               spin_lock(&nf_conntrack_locks[h1]);
+               if (h1 != h2)
+                       spin_lock_nested(&nf_conntrack_locks[h2],
+                                        SINGLE_DEPTH_NESTING);
+       } else {
+               spin_lock(&nf_conntrack_locks[h2]);
+               spin_lock_nested(&nf_conntrack_locks[h1],
+                                SINGLE_DEPTH_NESTING);
+       }
+       if (read_seqcount_retry(&net->ct.generation, sequence)) {
+               nf_conntrack_double_unlock(h1, h2);
+               return true;
+       }
+       return false;
+}
+
+static void nf_conntrack_all_lock(void)
+{
+       int i;
+
+       for (i = 0; i < CONNTRACK_LOCKS; i++)
+               spin_lock_nested(&nf_conntrack_locks[i], i);
+}
+
+static void nf_conntrack_all_unlock(void)
+{
+       int i;
+
+       for (i = 0; i < CONNTRACK_LOCKS; i++)
+               spin_unlock(&nf_conntrack_locks[i]);
+}
 
 unsigned int nf_conntrack_htable_size __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
@@ -192,6 +243,50 @@ clean_from_lists(struct nf_conn *ct)
        nf_ct_remove_expectations(ct);
 }
 
+/* must be called with local_bh_disable */
+static void nf_ct_add_to_dying_list(struct nf_conn *ct)
+{
+       struct ct_pcpu *pcpu;
+
+       /* add this conntrack to the (per cpu) dying list */
+       ct->cpu = smp_processor_id();
+       pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);
+
+       spin_lock(&pcpu->lock);
+       hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                            &pcpu->dying);
+       spin_unlock(&pcpu->lock);
+}
+
+/* must be called with local_bh_disable */
+static void nf_ct_add_to_unconfirmed_list(struct nf_conn *ct)
+{
+       struct ct_pcpu *pcpu;
+
+       /* add this conntrack to the (per cpu) unconfirmed list */
+       ct->cpu = smp_processor_id();
+       pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);
+
+       spin_lock(&pcpu->lock);
+       hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                            &pcpu->unconfirmed);
+       spin_unlock(&pcpu->lock);
+}
+
+/* must be called with local_bh_disable */
+static void nf_ct_del_from_dying_or_unconfirmed_list(struct nf_conn *ct)
+{
+       struct ct_pcpu *pcpu;
+
+       /* We overload first tuple to link into unconfirmed or dying list.*/
+       pcpu = per_cpu_ptr(nf_ct_net(ct)->ct.pcpu_lists, ct->cpu);
+
+       spin_lock(&pcpu->lock);
+       BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode));
+       hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
+       spin_unlock(&pcpu->lock);
+}
+
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
@@ -203,9 +298,6 @@ destroy_conntrack(struct nf_conntrack *nfct)
        NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
        NF_CT_ASSERT(!timer_pending(&ct->timeout));
 
-       /* To make sure we don't get any weird locking issues here:
-        * destroy_conntrack() MUST NOT be called with a write lock
-        * to nf_conntrack_lock!!! -HW */
        rcu_read_lock();
        l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
        if (l4proto && l4proto->destroy)
@@ -213,19 +305,18 @@ destroy_conntrack(struct nf_conntrack *nfct)
 
        rcu_read_unlock();
 
-       spin_lock_bh(&nf_conntrack_lock);
+       local_bh_disable();
        /* Expectations will have been removed in clean_from_lists,
         * except TFTP can create an expectation on the first packet,
         * before connection is in the list, so we need to clean here,
-        * too. */
+        * too.
+        */
        nf_ct_remove_expectations(ct);
 
-       /* We overload first tuple to link into unconfirmed or dying list.*/
-       BUG_ON(hlist_nulls_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode));
-       hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
+       nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
        NF_CT_STAT_INC(net, delete);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
 
        if (ct->master)
                nf_ct_put(ct->master);
@@ -237,17 +328,28 @@ destroy_conntrack(struct nf_conntrack *nfct)
 static void nf_ct_delete_from_lists(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
+       unsigned int hash, reply_hash;
+       u16 zone = nf_ct_zone(ct);
+       unsigned int sequence;
 
        nf_ct_helper_destroy(ct);
-       spin_lock_bh(&nf_conntrack_lock);
-       /* Inside lock so preempt is disabled on module removal path.
-        * Otherwise we can get spurious warnings. */
-       NF_CT_STAT_INC(net, delete_list);
+
+       local_bh_disable();
+       do {
+               sequence = read_seqcount_begin(&net->ct.generation);
+               hash = hash_conntrack(net, zone,
+                                     &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+               reply_hash = hash_conntrack(net, zone,
+                                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+       } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
+
        clean_from_lists(ct);
-       /* add this conntrack to the dying list */
-       hlist_nulls_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                            &net->ct.dying);
-       spin_unlock_bh(&nf_conntrack_lock);
+       nf_conntrack_double_unlock(hash, reply_hash);
+
+       nf_ct_add_to_dying_list(ct);
+
+       NF_CT_STAT_INC(net, delete_list);
+       local_bh_enable();
 }
 
 static void death_by_event(unsigned long ul_conntrack)
@@ -312,12 +414,25 @@ static void death_by_timeout(unsigned long ul_conntrack)
        nf_ct_delete((struct nf_conn *)ul_conntrack, 0, 0);
 }
 
+static inline bool
+nf_ct_key_equal(struct nf_conntrack_tuple_hash *h,
+                       const struct nf_conntrack_tuple *tuple,
+                       u16 zone)
+{
+       struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
+
+       /* A conntrack can be recreated with the equal tuple,
+        * so we need to check that the conntrack is confirmed
+        */
+       return nf_ct_tuple_equal(tuple, &h->tuple) &&
+               nf_ct_zone(ct) == zone &&
+               nf_ct_is_confirmed(ct);
+}
+
 /*
  * Warning :
  * - Caller must take a reference on returned object
  *   and recheck nf_ct_tuple_equal(tuple, &h->tuple)
- * OR
- * - Caller must lock nf_conntrack_lock before calling this function
  */
 static struct nf_conntrack_tuple_hash *
 ____nf_conntrack_find(struct net *net, u16 zone,
@@ -333,8 +448,7 @@ ____nf_conntrack_find(struct net *net, u16 zone,
        local_bh_disable();
 begin:
        hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) {
-               if (nf_ct_tuple_equal(tuple, &h->tuple) &&
-                   nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
+               if (nf_ct_key_equal(h, tuple, zone)) {
                        NF_CT_STAT_INC(net, found);
                        local_bh_enable();
                        return h;
@@ -372,8 +486,7 @@ begin:
                             !atomic_inc_not_zero(&ct->ct_general.use)))
                        h = NULL;
                else {
-                       if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
-                                    nf_ct_zone(ct) != zone)) {
+                       if (unlikely(!nf_ct_key_equal(h, tuple, zone))) {
                                nf_ct_put(ct);
                                goto begin;
                        }
@@ -395,32 +508,36 @@ EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
 
 static void __nf_conntrack_hash_insert(struct nf_conn *ct,
                                       unsigned int hash,
-                                      unsigned int repl_hash)
+                                      unsigned int reply_hash)
 {
        struct net *net = nf_ct_net(ct);
 
        hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
                           &net->ct.hash[hash]);
        hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode,
-                          &net->ct.hash[repl_hash]);
+                          &net->ct.hash[reply_hash]);
 }
 
 int
 nf_conntrack_hash_check_insert(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
-       unsigned int hash, repl_hash;
+       unsigned int hash, reply_hash;
        struct nf_conntrack_tuple_hash *h;
        struct hlist_nulls_node *n;
        u16 zone;
+       unsigned int sequence;
 
        zone = nf_ct_zone(ct);
-       hash = hash_conntrack(net, zone,
-                             &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
-       repl_hash = hash_conntrack(net, zone,
-                                  &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 
-       spin_lock_bh(&nf_conntrack_lock);
+       local_bh_disable();
+       do {
+               sequence = read_seqcount_begin(&net->ct.generation);
+               hash = hash_conntrack(net, zone,
+                                     &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+               reply_hash = hash_conntrack(net, zone,
+                                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+       } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
 
        /* See if there's one in the list already, including reverse */
        hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode)
@@ -428,32 +545,57 @@ nf_conntrack_hash_check_insert(struct nf_conn *ct)
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
-       hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
+       hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode)
                if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
 
        add_timer(&ct->timeout);
-       nf_conntrack_get(&ct->ct_general);
-       __nf_conntrack_hash_insert(ct, hash, repl_hash);
+       smp_wmb();
+       /* The caller holds a reference to this object */
+       atomic_set(&ct->ct_general.use, 2);
+       __nf_conntrack_hash_insert(ct, hash, reply_hash);
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert);
-       spin_unlock_bh(&nf_conntrack_lock);
-
+       local_bh_enable();
        return 0;
 
 out:
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert_failed);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
        return -EEXIST;
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_hash_check_insert);
 
+/* deletion from this larval template list happens via nf_ct_put() */
+void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl)
+{
+       struct ct_pcpu *pcpu;
+
+       __set_bit(IPS_TEMPLATE_BIT, &tmpl->status);
+       __set_bit(IPS_CONFIRMED_BIT, &tmpl->status);
+       nf_conntrack_get(&tmpl->ct_general);
+
+       /* add this conntrack to the (per cpu) tmpl list */
+       local_bh_disable();
+       tmpl->cpu = smp_processor_id();
+       pcpu = per_cpu_ptr(nf_ct_net(tmpl)->ct.pcpu_lists, tmpl->cpu);
+
+       spin_lock(&pcpu->lock);
+       /* Overload tuple linked list to put us in template list. */
+       hlist_nulls_add_head_rcu(&tmpl->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
+                                &pcpu->tmpl);
+       spin_unlock_bh(&pcpu->lock);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_tmpl_insert);
+
 /* Confirm a connection given skb; places it in hash table */
 int
 __nf_conntrack_confirm(struct sk_buff *skb)
 {
-       unsigned int hash, repl_hash;
+       unsigned int hash, reply_hash;
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
        struct nf_conn_help *help;
@@ -462,6 +604,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        enum ip_conntrack_info ctinfo;
        struct net *net;
        u16 zone;
+       unsigned int sequence;
 
        ct = nf_ct_get(skb, &ctinfo);
        net = nf_ct_net(ct);
@@ -474,31 +617,37 @@ __nf_conntrack_confirm(struct sk_buff *skb)
                return NF_ACCEPT;
 
        zone = nf_ct_zone(ct);
-       /* reuse the hash saved before */
-       hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev;
-       hash = hash_bucket(hash, net);
-       repl_hash = hash_conntrack(net, zone,
-                                  &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+       local_bh_disable();
+
+       do {
+               sequence = read_seqcount_begin(&net->ct.generation);
+               /* reuse the hash saved before */
+               hash = *(unsigned long *)&ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev;
+               hash = hash_bucket(hash, net);
+               reply_hash = hash_conntrack(net, zone,
+                                          &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+
+       } while (nf_conntrack_double_lock(net, hash, reply_hash, sequence));
 
        /* We're not in hash table, and we refuse to set up related
-          connections for unconfirmed conns.  But packet copies and
-          REJECT will give spurious warnings here. */
+        * connections for unconfirmed conns.  But packet copies and
+        * REJECT will give spurious warnings here.
+        */
        /* NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
 
        /* No external references means no one else could have
-          confirmed us. */
+        * confirmed us.
+        */
        NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
        pr_debug("Confirming conntrack %p\n", ct);
-
-       spin_lock_bh(&nf_conntrack_lock);
-
        /* We have to check the DYING flag inside the lock to prevent
           a race against nf_ct_get_next_corpse() possibly called from
           user context, else we insert an already 'dead' hash, blocking
           further use of that particular connection -JM */
 
        if (unlikely(nf_ct_is_dying(ct))) {
-               spin_unlock_bh(&nf_conntrack_lock);
+               nf_conntrack_double_unlock(hash, reply_hash);
+               local_bh_enable();
                return NF_ACCEPT;
        }
 
@@ -510,14 +659,13 @@ __nf_conntrack_confirm(struct sk_buff *skb)
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
-       hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
+       hlist_nulls_for_each_entry(h, n, &net->ct.hash[reply_hash], hnnode)
                if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
                                      &h->tuple) &&
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
 
-       /* Remove from unconfirmed list */
-       hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
+       nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
        /* Timer relative to confirmation time, not original
           setting time, otherwise we'd get timer wrap in
@@ -540,9 +688,10 @@ __nf_conntrack_confirm(struct sk_buff *skb)
         * guarantee that no other CPU can find the conntrack before the above
         * stores are visible.
         */
-       __nf_conntrack_hash_insert(ct, hash, repl_hash);
+       __nf_conntrack_hash_insert(ct, hash, reply_hash);
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
 
        help = nfct_help(ct);
        if (help && help->helper)
@@ -553,8 +702,9 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        return NF_ACCEPT;
 
 out:
+       nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert_failed);
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
        return NF_DROP;
 }
 EXPORT_SYMBOL_GPL(__nf_conntrack_confirm);
@@ -597,39 +747,48 @@ EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
 
 /* There's a small race here where we may free a just-assured
    connection.  Too bad: we're in trouble anyway. */
-static noinline int early_drop(struct net *net, unsigned int hash)
+static noinline int early_drop(struct net *net, unsigned int _hash)
 {
        /* Use oldest entry, which is roughly LRU */
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct = NULL, *tmp;
        struct hlist_nulls_node *n;
-       unsigned int i, cnt = 0;
+       unsigned int i = 0, cnt = 0;
        int dropped = 0;
+       unsigned int hash, sequence;
+       spinlock_t *lockp;
 
-       rcu_read_lock();
-       for (i = 0; i < net->ct.htable_size; i++) {
+       local_bh_disable();
+restart:
+       sequence = read_seqcount_begin(&net->ct.generation);
+       hash = hash_bucket(_hash, net);
+       for (; i < net->ct.htable_size; i++) {
+               lockp = &nf_conntrack_locks[hash % CONNTRACK_LOCKS];
+               spin_lock(lockp);
+               if (read_seqcount_retry(&net->ct.generation, sequence)) {
+                       spin_unlock(lockp);
+                       goto restart;
+               }
                hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
                                         hnnode) {
                        tmp = nf_ct_tuplehash_to_ctrack(h);
-                       if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
+                       if (!test_bit(IPS_ASSURED_BIT, &tmp->status) &&
+                           !nf_ct_is_dying(tmp) &&
+                           atomic_inc_not_zero(&tmp->ct_general.use)) {
                                ct = tmp;
+                               break;
+                       }
                        cnt++;
                }
 
-               if (ct != NULL) {
-                       if (likely(!nf_ct_is_dying(ct) &&
-                                  atomic_inc_not_zero(&ct->ct_general.use)))
-                               break;
-                       else
-                               ct = NULL;
-               }
+               hash = (hash + 1) % net->ct.htable_size;
+               spin_unlock(lockp);
 
-               if (cnt >= NF_CT_EVICTION_RANGE)
+               if (ct || cnt >= NF_CT_EVICTION_RANGE)
                        break;
 
-               hash = (hash + 1) % net->ct.htable_size;
        }
-       rcu_read_unlock();
+       local_bh_enable();
 
        if (!ct)
                return dropped;
@@ -678,7 +837,7 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
 
        if (nf_conntrack_max &&
            unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
-               if (!early_drop(net, hash_bucket(hash, net))) {
+               if (!early_drop(net, hash)) {
                        atomic_dec(&net->ct.count);
                        net_warn_ratelimited("nf_conntrack: table full, dropping packet\n");
                        return ERR_PTR(-ENOMEM);
@@ -720,11 +879,10 @@ __nf_conntrack_alloc(struct net *net, u16 zone,
                nf_ct_zone->id = zone;
        }
 #endif
-       /*
-        * changes to lookup keys must be done before setting refcnt to 1
+       /* Because we use RCU lookups, we set ct_general.use to zero before
+        * this is inserted in any list.
         */
-       smp_wmb();
-       atomic_set(&ct->ct_general.use, 1);
+       atomic_set(&ct->ct_general.use, 0);
        return ct;
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
@@ -748,6 +906,11 @@ void nf_conntrack_free(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
 
+       /* A freed object has refcnt == 0, that's
+        * the golden rule for SLAB_DESTROY_BY_RCU
+        */
+       NF_CT_ASSERT(atomic_read(&ct->ct_general.use) == 0);
+
        nf_ct_ext_destroy(ct);
        nf_ct_ext_free(ct);
        kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
@@ -771,7 +934,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        struct nf_conn_help *help;
        struct nf_conntrack_tuple repl_tuple;
        struct nf_conntrack_ecache *ecache;
-       struct nf_conntrack_expect *exp;
+       struct nf_conntrack_expect *exp = NULL;
        u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
        struct nf_conn_timeout *timeout_ext;
        unsigned int *timeouts;
@@ -815,39 +978,44 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
                                 ecache ? ecache->expmask : 0,
                             GFP_ATOMIC);
 
-       spin_lock_bh(&nf_conntrack_lock);
-       exp = nf_ct_find_expectation(net, zone, tuple);
-       if (exp) {
-               pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
-                        ct, exp);
-               /* Welcome, Mr. Bond.  We've been expecting you... */
-               __set_bit(IPS_EXPECTED_BIT, &ct->status);
-               ct->master = exp->master;
-               if (exp->helper) {
-                       help = nf_ct_helper_ext_add(ct, exp->helper,
-                                                   GFP_ATOMIC);
-                       if (help)
-                               rcu_assign_pointer(help->helper, exp->helper);
-               }
+       local_bh_disable();
+       if (net->ct.expect_count) {
+               spin_lock(&nf_conntrack_expect_lock);
+               exp = nf_ct_find_expectation(net, zone, tuple);
+               if (exp) {
+                       pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
+                                ct, exp);
+                       /* Welcome, Mr. Bond.  We've been expecting you... */
+                       __set_bit(IPS_EXPECTED_BIT, &ct->status);
+                       /* exp->master safe, refcnt bumped in nf_ct_find_expectation */
+                       ct->master = exp->master;
+                       if (exp->helper) {
+                               help = nf_ct_helper_ext_add(ct, exp->helper,
+                                                           GFP_ATOMIC);
+                               if (help)
+                                       rcu_assign_pointer(help->helper, exp->helper);
+                       }
 
 #ifdef CONFIG_NF_CONNTRACK_MARK
-               ct->mark = exp->master->mark;
+                       ct->mark = exp->master->mark;
 #endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
-               ct->secmark = exp->master->secmark;
+                       ct->secmark = exp->master->secmark;
 #endif
-               nf_conntrack_get(&ct->master->ct_general);
-               NF_CT_STAT_INC(net, expect_new);
-       } else {
+                       NF_CT_STAT_INC(net, expect_new);
+               }
+               spin_unlock(&nf_conntrack_expect_lock);
+       }
+       if (!exp) {
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
                NF_CT_STAT_INC(net, new);
        }
 
-       /* Overload tuple linked list to put us in unconfirmed list. */
-       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                      &net->ct.unconfirmed);
+       /* Now it is inserted into the unconfirmed list, bump refcount */
+       nf_conntrack_get(&ct->ct_general);
+       nf_ct_add_to_unconfirmed_list(ct);
 
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
 
        if (exp) {
                if (exp->expectfn)
@@ -1217,27 +1385,42 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
        struct hlist_nulls_node *n;
+       int cpu;
+       spinlock_t *lockp;
 
-       spin_lock_bh(&nf_conntrack_lock);
        for (; *bucket < net->ct.htable_size; (*bucket)++) {
-               hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) {
-                       if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
-                               continue;
+               lockp = &nf_conntrack_locks[*bucket % CONNTRACK_LOCKS];
+               local_bh_disable();
+               spin_lock(lockp);
+               if (*bucket < net->ct.htable_size) {
+                       hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) {
+                               if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
+                                       continue;
+                               ct = nf_ct_tuplehash_to_ctrack(h);
+                               if (iter(ct, data))
+                                       goto found;
+                       }
+               }
+               spin_unlock(lockp);
+               local_bh_enable();
+       }
+
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        if (iter(ct, data))
-                               goto found;
+                               set_bit(IPS_DYING_BIT, &ct->status);
                }
+               spin_unlock_bh(&pcpu->lock);
        }
-       hlist_nulls_for_each_entry(h, n, &net->ct.unconfirmed, hnnode) {
-               ct = nf_ct_tuplehash_to_ctrack(h);
-               if (iter(ct, data))
-                       set_bit(IPS_DYING_BIT, &ct->status);
-       }
-       spin_unlock_bh(&nf_conntrack_lock);
        return NULL;
 found:
        atomic_inc(&ct->ct_general.use);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock(lockp);
+       local_bh_enable();
        return ct;
 }
 
@@ -1286,14 +1469,19 @@ static void nf_ct_release_dying_list(struct net *net)
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
        struct hlist_nulls_node *n;
+       int cpu;
 
-       spin_lock_bh(&nf_conntrack_lock);
-       hlist_nulls_for_each_entry(h, n, &net->ct.dying, hnnode) {
-               ct = nf_ct_tuplehash_to_ctrack(h);
-               /* never fails to remove them, no listeners at this point */
-               nf_ct_kill(ct);
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
+                       ct = nf_ct_tuplehash_to_ctrack(h);
+                       /* never fails to remove them, no listeners at this point */
+                       nf_ct_kill(ct);
+               }
+               spin_unlock_bh(&pcpu->lock);
        }
-       spin_unlock_bh(&nf_conntrack_lock);
 }
 
 static int untrack_refs(void)
@@ -1380,6 +1568,7 @@ i_see_dead_people:
                kmem_cache_destroy(net->ct.nf_conntrack_cachep);
                kfree(net->ct.slabname);
                free_percpu(net->ct.stat);
+               free_percpu(net->ct.pcpu_lists);
        }
 }
 
@@ -1432,12 +1621,16 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
        if (!hash)
                return -ENOMEM;
 
+       local_bh_disable();
+       nf_conntrack_all_lock();
+       write_seqcount_begin(&init_net.ct.generation);
+
        /* Lookups in the old hash might happen in parallel, which means we
         * might get false negatives during connection lookup. New connections
         * created because of a false negative won't make it into the hash
-        * though since that required taking the lock.
+        * though since that required taking the locks.
         */
-       spin_lock_bh(&nf_conntrack_lock);
+
        for (i = 0; i < init_net.ct.htable_size; i++) {
                while (!hlist_nulls_empty(&init_net.ct.hash[i])) {
                        h = hlist_nulls_entry(init_net.ct.hash[i].first,
@@ -1454,7 +1647,10 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
 
        init_net.ct.htable_size = nf_conntrack_htable_size = hashsize;
        init_net.ct.hash = hash;
-       spin_unlock_bh(&nf_conntrack_lock);
+
+       write_seqcount_end(&init_net.ct.generation);
+       nf_conntrack_all_unlock();
+       local_bh_enable();
 
        nf_ct_free_hashtable(old_hash, old_size);
        return 0;
@@ -1476,7 +1672,10 @@ EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or);
 int nf_conntrack_init_start(void)
 {
        int max_factor = 8;
-       int ret, cpu;
+       int i, ret, cpu;
+
+       for (i = 0; i < CONNTRACK_LOCKS; i++)
+               spin_lock_init(&nf_conntrack_locks[i]);
 
        /* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
         * machine has 512 buckets. >= 1GB machines have 16384 buckets. */
@@ -1592,37 +1791,43 @@ void nf_conntrack_init_end(void)
 
 int nf_conntrack_init_net(struct net *net)
 {
-       int ret;
+       int ret = -ENOMEM;
+       int cpu;
 
        atomic_set(&net->ct.count, 0);
-       INIT_HLIST_NULLS_HEAD(&net->ct.unconfirmed, UNCONFIRMED_NULLS_VAL);
-       INIT_HLIST_NULLS_HEAD(&net->ct.dying, DYING_NULLS_VAL);
-       INIT_HLIST_NULLS_HEAD(&net->ct.tmpl, TEMPLATE_NULLS_VAL);
-       net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
-       if (!net->ct.stat) {
-               ret = -ENOMEM;
+
+       net->ct.pcpu_lists = alloc_percpu(struct ct_pcpu);
+       if (!net->ct.pcpu_lists)
                goto err_stat;
+
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_init(&pcpu->lock);
+               INIT_HLIST_NULLS_HEAD(&pcpu->unconfirmed, UNCONFIRMED_NULLS_VAL);
+               INIT_HLIST_NULLS_HEAD(&pcpu->dying, DYING_NULLS_VAL);
+               INIT_HLIST_NULLS_HEAD(&pcpu->tmpl, TEMPLATE_NULLS_VAL);
        }
 
+       net->ct.stat = alloc_percpu(struct ip_conntrack_stat);
+       if (!net->ct.stat)
+               goto err_pcpu_lists;
+
        net->ct.slabname = kasprintf(GFP_KERNEL, "nf_conntrack_%p", net);
-       if (!net->ct.slabname) {
-               ret = -ENOMEM;
+       if (!net->ct.slabname)
                goto err_slabname;
-       }
 
        net->ct.nf_conntrack_cachep = kmem_cache_create(net->ct.slabname,
                                                        sizeof(struct nf_conn), 0,
                                                        SLAB_DESTROY_BY_RCU, NULL);
        if (!net->ct.nf_conntrack_cachep) {
                printk(KERN_ERR "Unable to create nf_conn slab cache\n");
-               ret = -ENOMEM;
                goto err_cache;
        }
 
        net->ct.htable_size = nf_conntrack_htable_size;
        net->ct.hash = nf_ct_alloc_hashtable(&net->ct.htable_size, 1);
        if (!net->ct.hash) {
-               ret = -ENOMEM;
                printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
                goto err_hash;
        }
@@ -1664,6 +1869,8 @@ err_cache:
        kfree(net->ct.slabname);
 err_slabname:
        free_percpu(net->ct.stat);
+err_pcpu_lists:
+       free_percpu(net->ct.pcpu_lists);
 err_stat:
        return ret;
 }
index 4fd1ca94fd4a140b374385ded878af60b503b529..f87e8f68ad453e9baeec017cc74534e8ce85dfab 100644 (file)
@@ -66,9 +66,9 @@ static void nf_ct_expectation_timed_out(unsigned long ul_expect)
 {
        struct nf_conntrack_expect *exp = (void *)ul_expect;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        nf_ct_unlink_expect(exp);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        nf_ct_expect_put(exp);
 }
 
@@ -155,6 +155,18 @@ nf_ct_find_expectation(struct net *net, u16 zone,
        if (!nf_ct_is_confirmed(exp->master))
                return NULL;
 
+       /* Avoid race with other CPUs, that for exp->master ct, is
+        * about to invoke ->destroy(), or nf_ct_delete() via timeout
+        * or early_drop().
+        *
+        * The atomic_inc_not_zero() check tells:  If that fails, we
+        * know that the ct is being destroyed.  If it succeeds, we
+        * can be sure the ct cannot disappear underneath.
+        */
+       if (unlikely(nf_ct_is_dying(exp->master) ||
+                    !atomic_inc_not_zero(&exp->master->ct_general.use)))
+               return NULL;
+
        if (exp->flags & NF_CT_EXPECT_PERMANENT) {
                atomic_inc(&exp->use);
                return exp;
@@ -162,6 +174,8 @@ nf_ct_find_expectation(struct net *net, u16 zone,
                nf_ct_unlink_expect(exp);
                return exp;
        }
+       /* Undo exp->master refcnt increase, if del_timer() failed */
+       nf_ct_put(exp->master);
 
        return NULL;
 }
@@ -177,12 +191,14 @@ void nf_ct_remove_expectations(struct nf_conn *ct)
        if (!help)
                return;
 
+       spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
                if (del_timer(&exp->timeout)) {
                        nf_ct_unlink_expect(exp);
                        nf_ct_expect_put(exp);
                }
        }
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
 
@@ -217,12 +233,12 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
 /* Generally a bad idea to call this: could have matched already. */
 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
 {
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        if (del_timer(&exp->timeout)) {
                nf_ct_unlink_expect(exp);
                nf_ct_expect_put(exp);
        }
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
 
@@ -335,7 +351,7 @@ static int nf_ct_expect_insert(struct nf_conntrack_expect *exp)
        setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
                    (unsigned long)exp);
        helper = rcu_dereference_protected(master_help->helper,
-                                          lockdep_is_held(&nf_conntrack_lock));
+                                          lockdep_is_held(&nf_conntrack_expect_lock));
        if (helper) {
                exp->timeout.expires = jiffies +
                        helper->expect_policy[exp->class].timeout * HZ;
@@ -395,7 +411,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        }
        /* Will be over limit? */
        helper = rcu_dereference_protected(master_help->helper,
-                                          lockdep_is_held(&nf_conntrack_lock));
+                                          lockdep_is_held(&nf_conntrack_expect_lock));
        if (helper) {
                p = &helper->expect_policy[expect->class];
                if (p->max_expected &&
@@ -417,12 +433,12 @@ out:
        return ret;
 }
 
-int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, 
+int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
                                u32 portid, int report)
 {
        int ret;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        ret = __nf_ct_expect_check(expect);
        if (ret <= 0)
                goto out;
@@ -430,11 +446,11 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
        ret = nf_ct_expect_insert(expect);
        if (ret < 0)
                goto out;
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
        return ret;
 out:
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        return ret;
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
index 70866d192efc9351f2fcafe3ef23ce0c131fc0ba..3a3a60b126e0097f309badc40ebf8016b3773c98 100644 (file)
@@ -1476,7 +1476,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                nf_ct_refresh(ct, skb, info->timeout * HZ);
 
                /* Set expect timeout */
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3,
                                  info->sig_port[!dir]);
                if (exp) {
@@ -1486,7 +1486,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
                        nf_ct_dump_tuple(&exp->tuple);
                        set_expect_timeout(exp, info->timeout);
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
        }
 
        return 0;
index 974a2a4adefa739c729692e0df3ad3142f83d0d4..5b3eae7d4c9a51dd1bdd559fa5943125035d8490 100644 (file)
@@ -250,16 +250,14 @@ out:
 }
 EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
 
+/* appropiate ct lock protecting must be taken by caller */
 static inline int unhelp(struct nf_conntrack_tuple_hash *i,
                         const struct nf_conntrack_helper *me)
 {
        struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(i);
        struct nf_conn_help *help = nfct_help(ct);
 
-       if (help && rcu_dereference_protected(
-                       help->helper,
-                       lockdep_is_held(&nf_conntrack_lock)
-                       ) == me) {
+       if (help && rcu_dereference_raw(help->helper) == me) {
                nf_conntrack_event(IPCT_HELPER, ct);
                RCU_INIT_POINTER(help->helper, NULL);
        }
@@ -284,17 +282,17 @@ static LIST_HEAD(nf_ct_helper_expectfn_list);
 
 void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
 {
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
 
 void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
 {
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        list_del_rcu(&n->head);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
 
@@ -396,15 +394,17 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
        const struct hlist_node *next;
        const struct hlist_nulls_node *nn;
        unsigned int i;
+       int cpu;
 
        /* Get rid of expectations */
+       spin_lock_bh(&nf_conntrack_expect_lock);
        for (i = 0; i < nf_ct_expect_hsize; i++) {
                hlist_for_each_entry_safe(exp, next,
                                          &net->ct.expect_hash[i], hnode) {
                        struct nf_conn_help *help = nfct_help(exp->master);
                        if ((rcu_dereference_protected(
                                        help->helper,
-                                       lockdep_is_held(&nf_conntrack_lock)
+                                       lockdep_is_held(&nf_conntrack_expect_lock)
                                        ) == me || exp->helper == me) &&
                            del_timer(&exp->timeout)) {
                                nf_ct_unlink_expect(exp);
@@ -412,14 +412,27 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
                        }
                }
        }
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 
        /* Get rid of expecteds, set helpers to NULL. */
-       hlist_nulls_for_each_entry(h, nn, &net->ct.unconfirmed, hnnode)
-               unhelp(h, me);
-       for (i = 0; i < net->ct.htable_size; i++) {
-               hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode)
+       for_each_possible_cpu(cpu) {
+               struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+               spin_lock_bh(&pcpu->lock);
+               hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
                        unhelp(h, me);
+               spin_unlock_bh(&pcpu->lock);
+       }
+       local_bh_disable();
+       for (i = 0; i < net->ct.htable_size; i++) {
+               spin_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
+               if (i < net->ct.htable_size) {
+                       hlist_nulls_for_each_entry(h, nn, &net->ct.hash[i], hnnode)
+                               unhelp(h, me);
+               }
+               spin_unlock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
        }
+       local_bh_enable();
 }
 
 void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
@@ -437,10 +450,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
        synchronize_rcu();
 
        rtnl_lock();
-       spin_lock_bh(&nf_conntrack_lock);
        for_each_net(net)
                __nf_conntrack_helper_unregister(me, net);
-       spin_unlock_bh(&nf_conntrack_lock);
        rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
index bb322d0beb484f3c66a334a5e0b24651f2a1ffca..ccc46fa5edbce5e52710a22ae502e49a0f59e0a5 100644 (file)
@@ -764,14 +764,23 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
        int res;
+       spinlock_t *lockp;
+
 #ifdef CONFIG_NF_CONNTRACK_MARK
        const struct ctnetlink_dump_filter *filter = cb->data;
 #endif
 
-       spin_lock_bh(&nf_conntrack_lock);
        last = (struct nf_conn *)cb->args[1];
+
+       local_bh_disable();
        for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
 restart:
+               lockp = &nf_conntrack_locks[cb->args[0] % CONNTRACK_LOCKS];
+               spin_lock(lockp);
+               if (cb->args[0] >= net->ct.htable_size) {
+                       spin_unlock(lockp);
+                       goto out;
+               }
                hlist_nulls_for_each_entry(h, n, &net->ct.hash[cb->args[0]],
                                         hnnode) {
                        if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
@@ -803,16 +812,18 @@ restart:
                        if (res < 0) {
                                nf_conntrack_get(&ct->ct_general);
                                cb->args[1] = (unsigned long)ct;
+                               spin_unlock(lockp);
                                goto out;
                        }
                }
+               spin_unlock(lockp);
                if (cb->args[1]) {
                        cb->args[1] = 0;
                        goto restart;
                }
        }
 out:
-       spin_unlock_bh(&nf_conntrack_lock);
+       local_bh_enable();
        if (last)
                nf_ct_put(last);
 
@@ -966,7 +977,6 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
        return 0;
 }
 
-#define __CTA_LABELS_MAX_LENGTH ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
 static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_TUPLE_ORIG]        = { .type = NLA_NESTED },
        [CTA_TUPLE_REPLY]       = { .type = NLA_NESTED },
@@ -984,9 +994,9 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_ZONE]              = { .type = NLA_U16 },
        [CTA_MARK_MASK]         = { .type = NLA_U32 },
        [CTA_LABELS]            = { .type = NLA_BINARY,
-                                   .len = __CTA_LABELS_MAX_LENGTH },
+                                   .len = NF_CT_LABELS_MAX_SIZE },
        [CTA_LABELS_MASK]       = { .type = NLA_BINARY,
-                                   .len = __CTA_LABELS_MAX_LENGTH },
+                                   .len = NF_CT_LABELS_MAX_SIZE },
 };
 
 static int
@@ -1138,50 +1148,65 @@ static int ctnetlink_done_list(struct netlink_callback *cb)
 }
 
 static int
-ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb,
-                   struct hlist_nulls_head *list)
+ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying)
 {
-       struct nf_conn *ct, *last;
+       struct nf_conn *ct, *last = NULL;
        struct nf_conntrack_tuple_hash *h;
        struct hlist_nulls_node *n;
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
        u_int8_t l3proto = nfmsg->nfgen_family;
        int res;
+       int cpu;
+       struct hlist_nulls_head *list;
+       struct net *net = sock_net(skb->sk);
 
        if (cb->args[2])
                return 0;
 
-       spin_lock_bh(&nf_conntrack_lock);
-       last = (struct nf_conn *)cb->args[1];
-restart:
-       hlist_nulls_for_each_entry(h, n, list, hnnode) {
-               ct = nf_ct_tuplehash_to_ctrack(h);
-               if (l3proto && nf_ct_l3num(ct) != l3proto)
+       if (cb->args[0] == nr_cpu_ids)
+               return 0;
+
+       for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
+               struct ct_pcpu *pcpu;
+
+               if (!cpu_possible(cpu))
                        continue;
-               if (cb->args[1]) {
-                       if (ct != last)
+
+               pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+               spin_lock_bh(&pcpu->lock);
+               last = (struct nf_conn *)cb->args[1];
+               list = dying ? &pcpu->dying : &pcpu->unconfirmed;
+restart:
+               hlist_nulls_for_each_entry(h, n, list, hnnode) {
+                       ct = nf_ct_tuplehash_to_ctrack(h);
+                       if (l3proto && nf_ct_l3num(ct) != l3proto)
                                continue;
-                       cb->args[1] = 0;
-               }
-               rcu_read_lock();
-               res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
-                                         cb->nlh->nlmsg_seq,
-                                         NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
-                                         ct);
-               rcu_read_unlock();
-               if (res < 0) {
-                       nf_conntrack_get(&ct->ct_general);
-                       cb->args[1] = (unsigned long)ct;
-                       goto out;
+                       if (cb->args[1]) {
+                               if (ct != last)
+                                       continue;
+                               cb->args[1] = 0;
+                       }
+                       rcu_read_lock();
+                       res = ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
+                                                 cb->nlh->nlmsg_seq,
+                                                 NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
+                                                 ct);
+                       rcu_read_unlock();
+                       if (res < 0) {
+                               nf_conntrack_get(&ct->ct_general);
+                               cb->args[1] = (unsigned long)ct;
+                               spin_unlock_bh(&pcpu->lock);
+                               goto out;
+                       }
                }
+               if (cb->args[1]) {
+                       cb->args[1] = 0;
+                       goto restart;
+               } else
+                       cb->args[2] = 1;
+               spin_unlock_bh(&pcpu->lock);
        }
-       if (cb->args[1]) {
-               cb->args[1] = 0;
-               goto restart;
-       } else
-               cb->args[2] = 1;
 out:
-       spin_unlock_bh(&nf_conntrack_lock);
        if (last)
                nf_ct_put(last);
 
@@ -1191,9 +1216,7 @@ out:
 static int
 ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
-
-       return ctnetlink_dump_list(skb, cb, &net->ct.dying);
+       return ctnetlink_dump_list(skb, cb, true);
 }
 
 static int
@@ -1215,9 +1238,7 @@ ctnetlink_get_ct_dying(struct sock *ctnl, struct sk_buff *skb,
 static int
 ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct net *net = sock_net(skb->sk);
-
-       return ctnetlink_dump_list(skb, cb, &net->ct.unconfirmed);
+       return ctnetlink_dump_list(skb, cb, false);
 }
 
 static int
@@ -1310,27 +1331,22 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
 }
 
 static int
-ctnetlink_change_nat(struct nf_conn *ct, const struct nlattr * const cda[])
+ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[])
 {
 #ifdef CONFIG_NF_NAT_NEEDED
        int ret;
 
-       if (cda[CTA_NAT_DST]) {
-               ret = ctnetlink_parse_nat_setup(ct,
-                                               NF_NAT_MANIP_DST,
-                                               cda[CTA_NAT_DST]);
-               if (ret < 0)
-                       return ret;
-       }
-       if (cda[CTA_NAT_SRC]) {
-               ret = ctnetlink_parse_nat_setup(ct,
-                                               NF_NAT_MANIP_SRC,
-                                               cda[CTA_NAT_SRC]);
-               if (ret < 0)
-                       return ret;
-       }
-       return 0;
+       ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_DST,
+                                       cda[CTA_NAT_DST]);
+       if (ret < 0)
+               return ret;
+
+       ret = ctnetlink_parse_nat_setup(ct, NF_NAT_MANIP_SRC,
+                                       cda[CTA_NAT_SRC]);
+       return ret;
 #else
+       if (!cda[CTA_NAT_DST] && !cda[CTA_NAT_SRC])
+               return 0;
        return -EOPNOTSUPP;
 #endif
 }
@@ -1366,14 +1382,14 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
                                            nf_ct_protonum(ct));
        if (helper == NULL) {
 #ifdef CONFIG_MODULES
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
 
                if (request_module("nfct-helper-%s", helpname) < 0) {
-                       spin_lock_bh(&nf_conntrack_lock);
+                       spin_lock_bh(&nf_conntrack_expect_lock);
                        return -EOPNOTSUPP;
                }
 
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
                                                    nf_ct_protonum(ct));
                if (helper)
@@ -1659,11 +1675,9 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
                        goto err2;
        }
 
-       if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
-               err = ctnetlink_change_nat(ct, cda);
-               if (err < 0)
-                       goto err2;
-       }
+       err = ctnetlink_setup_nat(ct, cda);
+       if (err < 0)
+               goto err2;
 
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
@@ -1811,9 +1825,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
        err = -EEXIST;
        ct = nf_ct_tuplehash_to_ctrack(h);
        if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                err = ctnetlink_change_conntrack(ct, cda);
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
                if (err == 0) {
                        nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
                                                      (1 << IPCT_ASSURED) |
@@ -2142,9 +2156,9 @@ ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
        if (ret < 0)
                return ret;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 
        return ret;
 }
@@ -2699,13 +2713,13 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                }
 
                /* after list removal, usage count == 1 */
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                if (del_timer(&exp->timeout)) {
                        nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
                                                   nlmsg_report(nlh));
                        nf_ct_expect_put(exp);
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
                /* have to put what we 'get' above.
                 * after this line usage count == 0 */
                nf_ct_expect_put(exp);
@@ -2714,7 +2728,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                struct nf_conn_help *m_help;
 
                /* delete all expectations for this helper */
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, next,
                                                  &net->ct.expect_hash[i],
@@ -2729,10 +2743,10 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                                }
                        }
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
        } else {
                /* This basically means we have to flush everything*/
-               spin_lock_bh(&nf_conntrack_lock);
+               spin_lock_bh(&nf_conntrack_expect_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
                        hlist_for_each_entry_safe(exp, next,
                                                  &net->ct.expect_hash[i],
@@ -2745,7 +2759,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                                }
                        }
                }
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
        }
 
        return 0;
@@ -2971,11 +2985,11 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        exp = __nf_ct_expect_find(net, zone, &tuple);
 
        if (!exp) {
-               spin_unlock_bh(&nf_conntrack_lock);
+               spin_unlock_bh(&nf_conntrack_expect_lock);
                err = -ENOENT;
                if (nlh->nlmsg_flags & NLM_F_CREATE) {
                        err = ctnetlink_create_expect(net, zone, cda,
@@ -2989,7 +3003,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
        err = -EEXIST;
        if (!(nlh->nlmsg_flags & NLM_F_EXCL))
                err = ctnetlink_change_expect(exp, cda);
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 
        return err;
 }
index 466410eaa482c2a3940d3768351e92be17a644ef..4c3ba1c8d682d16abe0912f80525a84d184130db 100644 (file)
@@ -800,7 +800,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct,
        struct hlist_node *next;
        int found = 0;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
                if (exp->class != SIP_EXPECT_SIGNALLING ||
                    !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) ||
@@ -815,7 +815,7 @@ static int refresh_signalling_expectation(struct nf_conn *ct,
                found = 1;
                break;
        }
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
        return found;
 }
 
@@ -825,7 +825,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
        struct nf_conntrack_expect *exp;
        struct hlist_node *next;
 
-       spin_lock_bh(&nf_conntrack_lock);
+       spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
                if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media)
                        continue;
@@ -836,7 +836,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
                if (!media)
                        break;
        }
-       spin_unlock_bh(&nf_conntrack_lock);
+       spin_unlock_bh(&nf_conntrack_expect_lock);
 }
 
 static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
index d3f5cd6dd962b195ea85775cd0432cf204e697b2..52ca952b802c5e3ea41c83823b90f74365b8fc76 100644 (file)
@@ -432,15 +432,15 @@ nf_nat_setup_info(struct nf_conn *ct,
 }
 EXPORT_SYMBOL(nf_nat_setup_info);
 
-unsigned int
-nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+static unsigned int
+__nf_nat_alloc_null_binding(struct nf_conn *ct, enum nf_nat_manip_type manip)
 {
        /* Force range to this IP; let proto decide mapping for
         * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
         * Use reply in case it's already been mangled (eg local packet).
         */
        union nf_inet_addr ip =
-               (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
+               (manip == NF_NAT_MANIP_SRC ?
                ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
                ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
        struct nf_nat_range range = {
@@ -448,7 +448,13 @@ nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
                .min_addr       = ip,
                .max_addr       = ip,
        };
-       return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
+       return nf_nat_setup_info(ct, &range, manip);
+}
+
+unsigned int
+nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
+{
+       return __nf_nat_alloc_null_binding(ct, HOOK2MANIP(hooknum));
 }
 EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
 
@@ -702,9 +708,9 @@ static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
 
 static int
 nfnetlink_parse_nat(const struct nlattr *nat,
-                   const struct nf_conn *ct, struct nf_nat_range *range)
+                   const struct nf_conn *ct, struct nf_nat_range *range,
+                   const struct nf_nat_l3proto *l3proto)
 {
-       const struct nf_nat_l3proto *l3proto;
        struct nlattr *tb[CTA_NAT_MAX+1];
        int err;
 
@@ -714,38 +720,46 @@ nfnetlink_parse_nat(const struct nlattr *nat,
        if (err < 0)
                return err;
 
-       rcu_read_lock();
-       l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
-       if (l3proto == NULL) {
-               err = -EAGAIN;
-               goto out;
-       }
        err = l3proto->nlattr_to_range(tb, range);
        if (err < 0)
-               goto out;
+               return err;
 
        if (!tb[CTA_NAT_PROTO])
-               goto out;
+               return 0;
 
-       err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
-out:
-       rcu_read_unlock();
-       return err;
+       return nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
 }
 
+/* This function is called under rcu_read_lock() */
 static int
 nfnetlink_parse_nat_setup(struct nf_conn *ct,
                          enum nf_nat_manip_type manip,
                          const struct nlattr *attr)
 {
        struct nf_nat_range range;
+       const struct nf_nat_l3proto *l3proto;
        int err;
 
-       err = nfnetlink_parse_nat(attr, ct, &range);
+       /* Should not happen, restricted to creating new conntracks
+        * via ctnetlink.
+        */
+       if (WARN_ON_ONCE(nf_nat_initialized(ct, manip)))
+               return -EEXIST;
+
+       /* Make sure that L3 NAT is there by when we call nf_nat_setup_info to
+        * attach the null binding, otherwise this may oops.
+        */
+       l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
+       if (l3proto == NULL)
+               return -EAGAIN;
+
+       /* No NAT information has been passed, allocate the null-binding */
+       if (attr == NULL)
+               return __nf_nat_alloc_null_binding(ct, manip);
+
+       err = nfnetlink_parse_nat(attr, ct, &range, l3proto);
        if (err < 0)
                return err;
-       if (nf_nat_initialized(ct, manip))
-               return -EEXIST;
 
        return nf_nat_setup_info(ct, &range, manip);
 }
index 9858e3e51a3a049ce796b3ed625e3d3ad8bbe5cc..52e20c9a46a58be4328276964c1bb255c51a423c 100644 (file)
@@ -363,9 +363,8 @@ static int __net_init synproxy_net_init(struct net *net)
                goto err2;
        if (!nfct_synproxy_ext_add(ct))
                goto err2;
-       __set_bit(IPS_TEMPLATE_BIT, &ct->status);
-       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
 
+       nf_conntrack_tmpl_insert(net, ct);
        snet->tmpl = ct;
 
        snet->stats = alloc_percpu(struct synproxy_stats);
@@ -390,7 +389,7 @@ static void __net_exit synproxy_net_exit(struct net *net)
 {
        struct synproxy_net *snet = synproxy_pernet(net);
 
-       nf_conntrack_free(snet->tmpl);
+       nf_ct_put(snet->tmpl);
        synproxy_proc_exit(net);
        free_percpu(snet->stats);
 }
index 117bbaaddde636a7b5cbf754012ab2f696898e71..33045a56229769502532b38e7b4a1bc5d89c80d8 100644 (file)
@@ -794,9 +794,8 @@ nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
        stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
 
        if (chain->stats) {
-               /* nfnl_lock is held, add some nfnl function for this, later */
                struct nft_stats __percpu *oldstats =
-                       rcu_dereference_protected(chain->stats, 1);
+                               nft_dereference(chain->stats);
 
                rcu_assign_pointer(chain->stats, newstats);
                synchronize_rcu();
@@ -1008,10 +1007,8 @@ notify:
        return 0;
 }
 
-static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
+static void nf_tables_chain_destroy(struct nft_chain *chain)
 {
-       struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
-
        BUG_ON(chain->use > 0);
 
        if (chain->flags & NFT_BASE_CHAIN) {
@@ -1045,7 +1042,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
        if (IS_ERR(chain))
                return PTR_ERR(chain);
 
-       if (!list_empty(&chain->rules))
+       if (!list_empty(&chain->rules) || chain->use > 0)
                return -EBUSY;
 
        list_del(&chain->list);
@@ -1059,7 +1056,9 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
                               family);
 
        /* Make sure all rule references are gone before this is released */
-       call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
+       synchronize_rcu();
+
+       nf_tables_chain_destroy(chain);
        return 0;
 }
 
@@ -1114,35 +1113,45 @@ void nft_unregister_expr(struct nft_expr_type *type)
 }
 EXPORT_SYMBOL_GPL(nft_unregister_expr);
 
-static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
+static const struct nft_expr_type *__nft_expr_type_get(u8 family,
+                                                      struct nlattr *nla)
 {
        const struct nft_expr_type *type;
 
        list_for_each_entry(type, &nf_tables_expressions, list) {
-               if (!nla_strcmp(nla, type->name))
+               if (!nla_strcmp(nla, type->name) &&
+                   (!type->family || type->family == family))
                        return type;
        }
        return NULL;
 }
 
-static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
+static const struct nft_expr_type *nft_expr_type_get(u8 family,
+                                                    struct nlattr *nla)
 {
        const struct nft_expr_type *type;
 
        if (nla == NULL)
                return ERR_PTR(-EINVAL);
 
-       type = __nft_expr_type_get(nla);
+       type = __nft_expr_type_get(family, nla);
        if (type != NULL && try_module_get(type->owner))
                return type;
 
 #ifdef CONFIG_MODULES
        if (type == NULL) {
+               nfnl_unlock(NFNL_SUBSYS_NFTABLES);
+               request_module("nft-expr-%u-%.*s", family,
+                              nla_len(nla), (char *)nla_data(nla));
+               nfnl_lock(NFNL_SUBSYS_NFTABLES);
+               if (__nft_expr_type_get(family, nla))
+                       return ERR_PTR(-EAGAIN);
+
                nfnl_unlock(NFNL_SUBSYS_NFTABLES);
                request_module("nft-expr-%.*s",
                               nla_len(nla), (char *)nla_data(nla));
                nfnl_lock(NFNL_SUBSYS_NFTABLES);
-               if (__nft_expr_type_get(nla))
+               if (__nft_expr_type_get(family, nla))
                        return ERR_PTR(-EAGAIN);
        }
 #endif
@@ -1193,7 +1202,7 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
        if (err < 0)
                return err;
 
-       type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
+       type = nft_expr_type_get(ctx->afi->family, tb[NFTA_EXPR_NAME]);
        if (IS_ERR(type))
                return PTR_ERR(type);
 
@@ -1244,10 +1253,11 @@ err1:
        return err;
 }
 
-static void nf_tables_expr_destroy(struct nft_expr *expr)
+static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
+                                  struct nft_expr *expr)
 {
        if (expr->ops->destroy)
-               expr->ops->destroy(expr);
+               expr->ops->destroy(ctx, expr);
        module_put(expr->ops->type->owner);
 }
 
@@ -1286,6 +1296,8 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
        [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
        [NFTA_RULE_COMPAT]      = { .type = NLA_NESTED },
        [NFTA_RULE_POSITION]    = { .type = NLA_U64 },
+       [NFTA_RULE_USERDATA]    = { .type = NLA_BINARY,
+                                   .len = NFT_USERDATA_MAXLEN },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
@@ -1338,6 +1350,10 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
        }
        nla_nest_end(skb, list);
 
+       if (rule->ulen &&
+           nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule)))
+               goto nla_put_failure;
+
        return nlmsg_end(skb, nlh);
 
 nla_put_failure:
@@ -1521,9 +1537,9 @@ err:
        return err;
 }
 
-static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
+static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
+                                  struct nft_rule *rule)
 {
-       struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
        struct nft_expr *expr;
 
        /*
@@ -1532,23 +1548,18 @@ static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
         */
        expr = nft_expr_first(rule);
        while (expr->ops && expr != nft_expr_last(rule)) {
-               nf_tables_expr_destroy(expr);
+               nf_tables_expr_destroy(ctx, expr);
                expr = nft_expr_next(expr);
        }
        kfree(rule);
 }
 
-static void nf_tables_rule_destroy(struct nft_rule *rule)
-{
-       call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
-}
-
 #define NFT_RULE_MAXEXPRS      128
 
 static struct nft_expr_info *info;
 
 static struct nft_rule_trans *
-nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
+nf_tables_trans_add(struct nft_ctx *ctx, struct nft_rule *rule)
 {
        struct nft_rule_trans *rupd;
 
@@ -1556,11 +1567,8 @@ nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
        if (rupd == NULL)
               return NULL;
 
-       rupd->chain = ctx->chain;
-       rupd->table = ctx->table;
+       rupd->ctx = *ctx;
        rupd->rule = rule;
-       rupd->family = ctx->afi->family;
-       rupd->nlh = ctx->nlh;
        list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
 
        return rupd;
@@ -1580,7 +1588,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
        struct nft_expr *expr;
        struct nft_ctx ctx;
        struct nlattr *tmp;
-       unsigned int size, i, n;
+       unsigned int size, i, n, ulen = 0;
        int err, rem;
        bool create;
        u64 handle, pos_handle;
@@ -1646,8 +1654,11 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                }
        }
 
+       if (nla[NFTA_RULE_USERDATA])
+               ulen = nla_len(nla[NFTA_RULE_USERDATA]);
+
        err = -ENOMEM;
-       rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
+       rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL);
        if (rule == NULL)
                goto err1;
 
@@ -1655,6 +1666,10 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        rule->handle = handle;
        rule->dlen   = size;
+       rule->ulen   = ulen;
+
+       if (ulen)
+               nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen);
 
        expr = nft_expr_first(rule);
        for (i = 0; i < n; i++) {
@@ -1667,7 +1682,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
 
        if (nlh->nlmsg_flags & NLM_F_REPLACE) {
                if (nft_rule_is_active_next(net, old_rule)) {
-                       repl = nf_tables_trans_add(old_rule, &ctx);
+                       repl = nf_tables_trans_add(&ctx, old_rule);
                        if (repl == NULL) {
                                err = -ENOMEM;
                                goto err2;
@@ -1690,7 +1705,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
                        list_add_rcu(&rule->list, &chain->rules);
        }
 
-       if (nf_tables_trans_add(rule, &ctx) == NULL) {
+       if (nf_tables_trans_add(&ctx, rule) == NULL) {
                err = -ENOMEM;
                goto err3;
        }
@@ -1705,7 +1720,7 @@ err3:
                kfree(repl);
        }
 err2:
-       nf_tables_rule_destroy(rule);
+       nf_tables_rule_destroy(&ctx, rule);
 err1:
        for (i = 0; i < n; i++) {
                if (info[i].ops != NULL)
@@ -1719,7 +1734,7 @@ nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
 {
        /* You cannot delete the same rule twice */
        if (nft_rule_is_active_next(ctx->net, rule)) {
-               if (nf_tables_trans_add(rule, ctx) == NULL)
+               if (nf_tables_trans_add(ctx, rule) == NULL)
                        return -ENOMEM;
                nft_rule_disactivate_next(ctx->net, rule);
                return 0;
@@ -1809,29 +1824,36 @@ static int nf_tables_commit(struct sk_buff *skb)
        synchronize_rcu();
 
        list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
-               /* Delete this rule from the dirty list */
-               list_del(&rupd->list);
-
                /* This rule was inactive in the past and just became active.
                 * Clear the next bit of the genmask since its meaning has
                 * changed, now it is the future.
                 */
                if (nft_rule_is_active(net, rupd->rule)) {
                        nft_rule_clear(net, rupd->rule);
-                       nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
-                                             rupd->chain, rupd->rule,
-                                             NFT_MSG_NEWRULE, 0,
-                                             rupd->family);
+                       nf_tables_rule_notify(skb, rupd->ctx.nlh,
+                                             rupd->ctx.table, rupd->ctx.chain,
+                                             rupd->rule, NFT_MSG_NEWRULE, 0,
+                                             rupd->ctx.afi->family);
+                       list_del(&rupd->list);
                        kfree(rupd);
                        continue;
                }
 
                /* This rule is in the past, get rid of it */
                list_del_rcu(&rupd->rule->list);
-               nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
+               nf_tables_rule_notify(skb, rupd->ctx.nlh,
+                                     rupd->ctx.table, rupd->ctx.chain,
                                      rupd->rule, NFT_MSG_DELRULE, 0,
-                                     rupd->family);
-               nf_tables_rule_destroy(rupd->rule);
+                                     rupd->ctx.afi->family);
+       }
+
+       /* Make sure we don't see any packet traversing old rules */
+       synchronize_rcu();
+
+       /* Now we can safely release unused old rules */
+       list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
+               nf_tables_rule_destroy(&rupd->ctx, rupd->rule);
+               list_del(&rupd->list);
                kfree(rupd);
        }
 
@@ -1844,20 +1866,26 @@ static int nf_tables_abort(struct sk_buff *skb)
        struct nft_rule_trans *rupd, *tmp;
 
        list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
-               /* Delete all rules from the dirty list */
-               list_del(&rupd->list);
-
                if (!nft_rule_is_active_next(net, rupd->rule)) {
                        nft_rule_clear(net, rupd->rule);
+                       list_del(&rupd->list);
                        kfree(rupd);
                        continue;
                }
 
                /* This rule is inactive, get rid of it */
                list_del_rcu(&rupd->rule->list);
-               nf_tables_rule_destroy(rupd->rule);
+       }
+
+       /* Make sure we don't see any packet accessing aborted rules */
+       synchronize_rcu();
+
+       list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
+               nf_tables_rule_destroy(&rupd->ctx, rupd->rule);
+               list_del(&rupd->list);
                kfree(rupd);
        }
+
        return 0;
 }
 
@@ -1943,6 +1971,9 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
        }
 
        if (nla[NFTA_SET_TABLE] != NULL) {
+               if (afi == NULL)
+                       return -EAFNOSUPPORT;
+
                table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
                if (IS_ERR(table))
                        return PTR_ERR(table);
@@ -1989,13 +2020,13 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
 
                        if (!sscanf(i->name, name, &tmp))
                                continue;
-                       if (tmp < 0 || tmp > BITS_PER_LONG * PAGE_SIZE)
+                       if (tmp < 0 || tmp >= BITS_PER_BYTE * PAGE_SIZE)
                                continue;
 
                        set_bit(tmp, inuse);
                }
 
-               n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
+               n = find_first_zero_bit(inuse, BITS_PER_BYTE * PAGE_SIZE);
                free_page((unsigned long)inuse);
        }
 
@@ -2411,8 +2442,7 @@ err1:
 static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
 {
        list_del(&set->list);
-       if (!(set->flags & NFT_SET_ANONYMOUS))
-               nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
+       nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
 
        set->ops->destroy(set);
        module_put(set->ops->owner);
@@ -2428,6 +2458,8 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
        struct nft_ctx ctx;
        int err;
 
+       if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
+               return -EAFNOSUPPORT;
        if (nla[NFTA_SET_TABLE] == NULL)
                return -EINVAL;
 
@@ -2435,9 +2467,6 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
-               return -EAFNOSUPPORT;
-
        set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
        if (IS_ERR(set))
                return PTR_ERR(set);
@@ -2723,6 +2752,9 @@ static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
                if (nla[NFTA_SET_ELEM_DATA] == NULL &&
                    !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
                        return -EINVAL;
+               if (nla[NFTA_SET_ELEM_DATA] != NULL &&
+                   elem.flags & NFT_SET_ELEM_INTERVAL_END)
+                       return -EINVAL;
        } else {
                if (nla[NFTA_SET_ELEM_DATA] != NULL)
                        return -EINVAL;
@@ -2977,6 +3009,9 @@ static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
                                        const struct nft_set_iter *iter,
                                        const struct nft_set_elem *elem)
 {
+       if (elem->flags & NFT_SET_ELEM_INTERVAL_END)
+               return 0;
+
        switch (elem->data.verdict) {
        case NFT_JUMP:
        case NFT_GOTO:
@@ -3151,9 +3186,16 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
        data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
 
        switch (data->verdict) {
-       case NF_ACCEPT:
-       case NF_DROP:
-       case NF_QUEUE:
+       default:
+               switch (data->verdict & NF_VERDICT_MASK) {
+               case NF_ACCEPT:
+               case NF_DROP:
+               case NF_QUEUE:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               /* fall through */
        case NFT_CONTINUE:
        case NFT_BREAK:
        case NFT_RETURN:
@@ -3174,8 +3216,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
                data->chain = chain;
                desc->len = sizeof(data);
                break;
-       default:
-               return -EINVAL;
        }
 
        desc->type = NFT_DATA_VERDICT;
index 0d879fcb8763c043430d242d68524e0256c4411d..90998a6ff8b9c1f10712e07d9b753e7d7d1bb2fd 100644 (file)
@@ -103,9 +103,9 @@ static struct nf_loginfo trace_loginfo = {
        },
 };
 
-static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
-                                   const struct nft_chain *chain,
-                                   int rulenum, enum nft_trace type)
+static void nft_trace_packet(const struct nft_pktinfo *pkt,
+                            const struct nft_chain *chain,
+                            int rulenum, enum nft_trace type)
 {
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
index 046aa13b4fea6a570b990444b7ca4c6419824f8f..e8138da4c14f70f40449c72ec4dc4d31f2960b8e 100644 (file)
@@ -61,6 +61,14 @@ void nfnl_unlock(__u8 subsys_id)
 }
 EXPORT_SYMBOL_GPL(nfnl_unlock);
 
+#ifdef CONFIG_PROVE_LOCKING
+int lockdep_nfnl_is_held(u8 subsys_id)
+{
+       return lockdep_is_held(&table[subsys_id].mutex);
+}
+EXPORT_SYMBOL_GPL(lockdep_nfnl_is_held);
+#endif
+
 int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
 {
        nfnl_lock(n->subsys_id);
index a155d19a225edcfb4b1a550ebc898f40d51c564d..d292c8d286ebeac22f688d47df8b793e9c90cc6b 100644 (file)
@@ -28,8 +28,6 @@
 #include <linux/proc_fs.h>
 #include <linux/security.h>
 #include <linux/list.h>
-#include <linux/jhash.h>
-#include <linux/random.h>
 #include <linux/slab.h>
 #include <net/sock.h>
 #include <net/netfilter/nf_log.h>
@@ -75,7 +73,6 @@ struct nfulnl_instance {
 };
 
 #define INSTANCE_BUCKETS       16
-static unsigned int hash_init;
 
 static int nfnl_log_net_id __read_mostly;
 
@@ -1067,11 +1064,6 @@ static int __init nfnetlink_log_init(void)
 {
        int status = -ENOMEM;
 
-       /* it's not really all that important to have a random value, so
-        * we can do this from the init function, even if there hasn't
-        * been that much entropy yet */
-       get_random_bytes(&hash_init, sizeof(hash_init));
-
        netlink_register_notifier(&nfulnl_rtnl_notifier);
        status = nfnetlink_subsys_register(&nfulnl_subsys);
        if (status < 0) {
index f072fe803510320f7210c31b1a08ccddea5ae5b6..108120f216b17671351cb492c86cb0ae928504f6 100644 (file)
@@ -354,13 +354,16 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
 
        skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
                                  GFP_ATOMIC);
-       if (!skb)
+       if (!skb) {
+               skb_tx_error(entskb);
                return NULL;
+       }
 
        nlh = nlmsg_put(skb, 0, 0,
                        NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
                        sizeof(struct nfgenmsg), 0);
        if (!nlh) {
+               skb_tx_error(entskb);
                kfree_skb(skb);
                return NULL;
        }
@@ -488,13 +491,15 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
                nla->nla_type = NFQA_PAYLOAD;
                nla->nla_len = nla_attr_size(data_len);
 
-               skb_zerocopy(skb, entskb, data_len, hlen);
+               if (skb_zerocopy(skb, entskb, data_len, hlen))
+                       goto nla_put_failure;
        }
 
        nlh->nlmsg_len = skb->len;
        return skb;
 
 nla_put_failure:
+       skb_tx_error(entskb);
        kfree_skb(skb);
        net_err_ratelimited("nf_queue: error creating packet message\n");
        return NULL;
index 82cb8236f8a101d260a9f3cc6eb1c218e34163f3..8a779be832fba2d8a86181f8f8f68a445299d626 100644 (file)
@@ -192,7 +192,7 @@ err:
 }
 
 static void
-nft_target_destroy(const struct nft_expr *expr)
+nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 {
        struct xt_target *target = expr->ops->data;
 
@@ -379,7 +379,7 @@ err:
 }
 
 static void
-nft_match_destroy(const struct nft_expr *expr)
+nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 {
        struct xt_match *match = expr->ops->data;
 
index 917052e20602ea1b7cca286edfbe01e429703327..bd0d41e693416167b4f149f64117e440a5134496 100644 (file)
 #include <net/netfilter/nf_conntrack_tuple.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_labels.h>
 
 struct nft_ct {
        enum nft_ct_keys        key:8;
        enum ip_conntrack_dir   dir:8;
-       union{
+       union {
                enum nft_registers      dreg:8;
                enum nft_registers      sreg:8;
        };
-       uint8_t                 family;
 };
 
 static void nft_ct_get_eval(const struct nft_expr *expr,
@@ -97,6 +97,26 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                        goto err;
                strncpy((char *)dest->data, helper->name, sizeof(dest->data));
                return;
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       case NFT_CT_LABELS: {
+               struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+               unsigned int size;
+
+               if (!labels) {
+                       memset(dest->data, 0, sizeof(dest->data));
+                       return;
+               }
+
+               BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > sizeof(dest->data));
+               size = labels->words * sizeof(long);
+
+               memcpy(dest->data, labels->bits, size);
+               if (size < sizeof(dest->data))
+                       memset(((char *) dest->data) + size, 0,
+                              sizeof(dest->data) - size);
+               return;
+       }
+#endif
        }
 
        tuple = &ct->tuplehash[priv->dir].tuple;
@@ -220,12 +240,16 @@ static int nft_ct_init_validate_get(const struct nft_expr *expr,
 #endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
        case NFT_CT_SECMARK:
+#endif
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       case NFT_CT_LABELS:
 #endif
        case NFT_CT_EXPIRATION:
        case NFT_CT_HELPER:
                if (tb[NFTA_CT_DIRECTION] != NULL)
                        return -EINVAL;
                break;
+       case NFT_CT_L3PROTOCOL:
        case NFT_CT_PROTOCOL:
        case NFT_CT_SRC:
        case NFT_CT_DST:
@@ -291,16 +315,13 @@ static int nft_ct_init(const struct nft_ctx *ctx,
        if (err < 0)
                return err;
 
-       priv->family = ctx->afi->family;
-
        return 0;
 }
 
-static void nft_ct_destroy(const struct nft_expr *expr)
+static void nft_ct_destroy(const struct nft_ctx *ctx,
+                          const struct nft_expr *expr)
 {
-       struct nft_ct *priv = nft_expr_priv(expr);
-
-       nft_ct_l3proto_module_put(priv->family);
+       nft_ct_l3proto_module_put(ctx->afi->family);
 }
 
 static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
@@ -311,8 +332,19 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
                goto nla_put_failure;
-       if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
-               goto nla_put_failure;
+
+       switch (priv->key) {
+       case NFT_CT_PROTOCOL:
+       case NFT_CT_SRC:
+       case NFT_CT_DST:
+       case NFT_CT_PROTO_SRC:
+       case NFT_CT_PROTO_DST:
+               if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
+                       goto nla_put_failure;
+       default:
+               break;
+       }
+
        return 0;
 
 nla_put_failure:
index 3d3f8fce10a5136391e53bd75b13498a45e82e96..3b1ad876d6b028f987ccf8e78ceb9639d767e6bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2008-2014 Patrick McHardy <kaber@trash.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/list.h>
 #include <linux/jhash.h>
 #include <linux/netlink.h>
+#include <linux/vmalloc.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
 
+#define NFT_HASH_MIN_SIZE      4
+
 struct nft_hash {
-       struct hlist_head       *hash;
-       unsigned int            hsize;
+       struct nft_hash_table __rcu     *tbl;
+};
+
+struct nft_hash_table {
+       unsigned int                    size;
+       unsigned int                    elements;
+       struct nft_hash_elem __rcu      *buckets[];
 };
 
 struct nft_hash_elem {
-       struct hlist_node       hnode;
-       struct nft_data         key;
-       struct nft_data         data[];
+       struct nft_hash_elem __rcu      *next;
+       struct nft_data                 key;
+       struct nft_data                 data[];
 };
 
+#define nft_hash_for_each_entry(i, head) \
+       for (i = nft_dereference(head); i != NULL; i = nft_dereference(i->next))
+#define nft_hash_for_each_entry_rcu(i, head) \
+       for (i = rcu_dereference(head); i != NULL; i = rcu_dereference(i->next))
+
 static u32 nft_hash_rnd __read_mostly;
 static bool nft_hash_rnd_initted __read_mostly;
 
@@ -38,7 +51,7 @@ static unsigned int nft_hash_data(const struct nft_data *data,
        unsigned int h;
 
        h = jhash(data->data, len, nft_hash_rnd);
-       return ((u64)h * hsize) >> 32;
+       return h & (hsize - 1);
 }
 
 static bool nft_hash_lookup(const struct nft_set *set,
@@ -46,11 +59,12 @@ static bool nft_hash_lookup(const struct nft_set *set,
                            struct nft_data *data)
 {
        const struct nft_hash *priv = nft_set_priv(set);
+       const struct nft_hash_table *tbl = rcu_dereference(priv->tbl);
        const struct nft_hash_elem *he;
        unsigned int h;
 
-       h = nft_hash_data(key, priv->hsize, set->klen);
-       hlist_for_each_entry(he, &priv->hash[h], hnode) {
+       h = nft_hash_data(key, tbl->size, set->klen);
+       nft_hash_for_each_entry_rcu(he, tbl->buckets[h]) {
                if (nft_data_cmp(&he->key, key, set->klen))
                        continue;
                if (set->flags & NFT_SET_MAP)
@@ -60,19 +74,148 @@ static bool nft_hash_lookup(const struct nft_set *set,
        return false;
 }
 
-static void nft_hash_elem_destroy(const struct nft_set *set,
-                                 struct nft_hash_elem *he)
+static void nft_hash_tbl_free(const struct nft_hash_table *tbl)
 {
-       nft_data_uninit(&he->key, NFT_DATA_VALUE);
-       if (set->flags & NFT_SET_MAP)
-               nft_data_uninit(he->data, set->dtype);
-       kfree(he);
+       if (is_vmalloc_addr(tbl))
+               vfree(tbl);
+       else
+               kfree(tbl);
+}
+
+static struct nft_hash_table *nft_hash_tbl_alloc(unsigned int nbuckets)
+{
+       struct nft_hash_table *tbl;
+       size_t size;
+
+       size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]);
+       tbl = kzalloc(size, GFP_KERNEL | __GFP_REPEAT | __GFP_NOWARN);
+       if (tbl == NULL)
+               tbl = vzalloc(size);
+       if (tbl == NULL)
+               return NULL;
+       tbl->size = nbuckets;
+
+       return tbl;
+}
+
+static void nft_hash_chain_unzip(const struct nft_set *set,
+                                const struct nft_hash_table *ntbl,
+                                struct nft_hash_table *tbl, unsigned int n)
+{
+       struct nft_hash_elem *he, *last, *next;
+       unsigned int h;
+
+       he = nft_dereference(tbl->buckets[n]);
+       if (he == NULL)
+               return;
+       h = nft_hash_data(&he->key, ntbl->size, set->klen);
+
+       /* Find last element of first chain hashing to bucket h */
+       last = he;
+       nft_hash_for_each_entry(he, he->next) {
+               if (nft_hash_data(&he->key, ntbl->size, set->klen) != h)
+                       break;
+               last = he;
+       }
+
+       /* Unlink first chain from the old table */
+       RCU_INIT_POINTER(tbl->buckets[n], last->next);
+
+       /* If end of chain reached, done */
+       if (he == NULL)
+               return;
+
+       /* Find first element of second chain hashing to bucket h */
+       next = NULL;
+       nft_hash_for_each_entry(he, he->next) {
+               if (nft_hash_data(&he->key, ntbl->size, set->klen) != h)
+                       continue;
+               next = he;
+               break;
+       }
+
+       /* Link the two chains */
+       RCU_INIT_POINTER(last->next, next);
+}
+
+static int nft_hash_tbl_expand(const struct nft_set *set, struct nft_hash *priv)
+{
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl;
+       struct nft_hash_elem *he;
+       unsigned int i, h;
+       bool complete;
+
+       ntbl = nft_hash_tbl_alloc(tbl->size * 2);
+       if (ntbl == NULL)
+               return -ENOMEM;
+
+       /* Link new table's buckets to first element in the old table
+        * hashing to the new bucket.
+        */
+       for (i = 0; i < ntbl->size; i++) {
+               h = i < tbl->size ? i : i - tbl->size;
+               nft_hash_for_each_entry(he, tbl->buckets[h]) {
+                       if (nft_hash_data(&he->key, ntbl->size, set->klen) != i)
+                               continue;
+                       RCU_INIT_POINTER(ntbl->buckets[i], he);
+                       break;
+               }
+       }
+       ntbl->elements = tbl->elements;
+
+       /* Publish new table */
+       rcu_assign_pointer(priv->tbl, ntbl);
+
+       /* Unzip interleaved hash chains */
+       do {
+               /* Wait for readers to use new table/unzipped chains */
+               synchronize_rcu();
+
+               complete = true;
+               for (i = 0; i < tbl->size; i++) {
+                       nft_hash_chain_unzip(set, ntbl, tbl, i);
+                       if (tbl->buckets[i] != NULL)
+                               complete = false;
+               }
+       } while (!complete);
+
+       nft_hash_tbl_free(tbl);
+       return 0;
+}
+
+static int nft_hash_tbl_shrink(const struct nft_set *set, struct nft_hash *priv)
+{
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl), *ntbl;
+       struct nft_hash_elem __rcu **pprev;
+       unsigned int i;
+
+       ntbl = nft_hash_tbl_alloc(tbl->size / 2);
+       if (ntbl == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < ntbl->size; i++) {
+               ntbl->buckets[i] = tbl->buckets[i];
+
+               for (pprev = &ntbl->buckets[i]; *pprev != NULL;
+                    pprev = &nft_dereference(*pprev)->next)
+                       ;
+               RCU_INIT_POINTER(*pprev, tbl->buckets[i + ntbl->size]);
+       }
+       ntbl->elements = tbl->elements;
+
+       /* Publish new table */
+       rcu_assign_pointer(priv->tbl, ntbl);
+       synchronize_rcu();
+
+       nft_hash_tbl_free(tbl);
+       return 0;
 }
 
 static int nft_hash_insert(const struct nft_set *set,
                           const struct nft_set_elem *elem)
 {
        struct nft_hash *priv = nft_set_priv(set);
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl);
        struct nft_hash_elem *he;
        unsigned int size, h;
 
@@ -91,33 +234,66 @@ static int nft_hash_insert(const struct nft_set *set,
        if (set->flags & NFT_SET_MAP)
                nft_data_copy(he->data, &elem->data);
 
-       h = nft_hash_data(&he->key, priv->hsize, set->klen);
-       hlist_add_head_rcu(&he->hnode, &priv->hash[h]);
+       h = nft_hash_data(&he->key, tbl->size, set->klen);
+       RCU_INIT_POINTER(he->next, tbl->buckets[h]);
+       rcu_assign_pointer(tbl->buckets[h], he);
+       tbl->elements++;
+
+       /* Expand table when exceeding 75% load */
+       if (tbl->elements > tbl->size / 4 * 3)
+               nft_hash_tbl_expand(set, priv);
+
        return 0;
 }
 
+static void nft_hash_elem_destroy(const struct nft_set *set,
+                                 struct nft_hash_elem *he)
+{
+       nft_data_uninit(&he->key, NFT_DATA_VALUE);
+       if (set->flags & NFT_SET_MAP)
+               nft_data_uninit(he->data, set->dtype);
+       kfree(he);
+}
+
 static void nft_hash_remove(const struct nft_set *set,
                            const struct nft_set_elem *elem)
 {
-       struct nft_hash_elem *he = elem->cookie;
+       struct nft_hash *priv = nft_set_priv(set);
+       struct nft_hash_table *tbl = nft_dereference(priv->tbl);
+       struct nft_hash_elem *he, __rcu **pprev;
 
-       hlist_del_rcu(&he->hnode);
+       pprev = elem->cookie;
+       he = nft_dereference((*pprev));
+
+       RCU_INIT_POINTER(*pprev, he->next);
+       synchronize_rcu();
        kfree(he);
+       tbl->elements--;
+
+       /* Shrink table beneath 30% load */
+       if (tbl->elements < tbl->size * 3 / 10 &&
+           tbl->size > NFT_HASH_MIN_SIZE)
+               nft_hash_tbl_shrink(set, priv);
 }
 
 static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem)
 {
        const struct nft_hash *priv = nft_set_priv(set);
+       const struct nft_hash_table *tbl = nft_dereference(priv->tbl);
+       struct nft_hash_elem __rcu * const *pprev;
        struct nft_hash_elem *he;
        unsigned int h;
 
-       h = nft_hash_data(&elem->key, priv->hsize, set->klen);
-       hlist_for_each_entry(he, &priv->hash[h], hnode) {
-               if (nft_data_cmp(&he->key, &elem->key, set->klen))
+       h = nft_hash_data(&elem->key, tbl->size, set->klen);
+       pprev = &tbl->buckets[h];
+       nft_hash_for_each_entry(he, tbl->buckets[h]) {
+               if (nft_data_cmp(&he->key, &elem->key, set->klen)) {
+                       pprev = &he->next;
                        continue;
+               }
 
-               elem->cookie = he;
-               elem->flags  = 0;
+               elem->cookie = (void *)pprev;
+               elem->flags = 0;
                if (set->flags & NFT_SET_MAP)
                        nft_data_copy(&elem->data, he->data);
                return 0;
@@ -129,12 +305,13 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
                          struct nft_set_iter *iter)
 {
        const struct nft_hash *priv = nft_set_priv(set);
+       const struct nft_hash_table *tbl = nft_dereference(priv->tbl);
        const struct nft_hash_elem *he;
        struct nft_set_elem elem;
        unsigned int i;
 
-       for (i = 0; i < priv->hsize; i++) {
-               hlist_for_each_entry(he, &priv->hash[i], hnode) {
+       for (i = 0; i < tbl->size; i++) {
+               nft_hash_for_each_entry(he, tbl->buckets[i]) {
                        if (iter->count < iter->skip)
                                goto cont;
 
@@ -161,43 +338,35 @@ static int nft_hash_init(const struct nft_set *set,
                         const struct nlattr * const tb[])
 {
        struct nft_hash *priv = nft_set_priv(set);
-       unsigned int cnt, i;
+       struct nft_hash_table *tbl;
 
        if (unlikely(!nft_hash_rnd_initted)) {
                get_random_bytes(&nft_hash_rnd, 4);
                nft_hash_rnd_initted = true;
        }
 
-       /* Aim for a load factor of 0.75 */
-       // FIXME: temporarily broken until we have set descriptions
-       cnt = 100;
-       cnt = cnt * 4 / 3;
-
-       priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL);
-       if (priv->hash == NULL)
+       tbl = nft_hash_tbl_alloc(NFT_HASH_MIN_SIZE);
+       if (tbl == NULL)
                return -ENOMEM;
-       priv->hsize = cnt;
-
-       for (i = 0; i < cnt; i++)
-               INIT_HLIST_HEAD(&priv->hash[i]);
-
+       RCU_INIT_POINTER(priv->tbl, tbl);
        return 0;
 }
 
 static void nft_hash_destroy(const struct nft_set *set)
 {
        const struct nft_hash *priv = nft_set_priv(set);
-       const struct hlist_node *next;
-       struct nft_hash_elem *elem;
+       const struct nft_hash_table *tbl = nft_dereference(priv->tbl);
+       struct nft_hash_elem *he, *next;
        unsigned int i;
 
-       for (i = 0; i < priv->hsize; i++) {
-               hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) {
-                       hlist_del(&elem->hnode);
-                       nft_hash_elem_destroy(set, elem);
+       for (i = 0; i < tbl->size; i++) {
+               for (he = nft_dereference(tbl->buckets[i]); he != NULL;
+                    he = next) {
+                       next = nft_dereference(he->next);
+                       nft_hash_elem_destroy(set, he);
                }
        }
-       kfree(priv->hash);
+       kfree(tbl);
 }
 
 static struct nft_set_ops nft_hash_ops __read_mostly = {
index f169501f1ad4389970613d1e44fb2b60759406cb..810385eb7249c7be39bcbc0e6c34abc1a6b1708d 100644 (file)
@@ -70,7 +70,8 @@ err1:
        return err;
 }
 
-static void nft_immediate_destroy(const struct nft_expr *expr)
+static void nft_immediate_destroy(const struct nft_ctx *ctx,
+                                 const struct nft_expr *expr)
 {
        const struct nft_immediate_expr *priv = nft_expr_priv(expr);
        return nft_data_uninit(&priv->data, nft_dreg_to_type(priv->dreg));
index 5af790123ad865dbb88c9e172ed4b9beb8590e01..10cfb156cdf4449dee49e53667549e5c2fccdf82 100644 (file)
@@ -23,7 +23,6 @@ static const char *nft_log_null_prefix = "";
 struct nft_log {
        struct nf_loginfo       loginfo;
        char                    *prefix;
-       int                     family;
 };
 
 static void nft_log_eval(const struct nft_expr *expr,
@@ -33,7 +32,7 @@ static void nft_log_eval(const struct nft_expr *expr,
        const struct nft_log *priv = nft_expr_priv(expr);
        struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
 
-       nf_log_packet(net, priv->family, pkt->ops->hooknum, pkt->skb, pkt->in,
+       nf_log_packet(net, pkt->ops->pf, pkt->ops->hooknum, pkt->skb, pkt->in,
                      pkt->out, &priv->loginfo, "%s", priv->prefix);
 }
 
@@ -52,8 +51,6 @@ static int nft_log_init(const struct nft_ctx *ctx,
        struct nf_loginfo *li = &priv->loginfo;
        const struct nlattr *nla;
 
-       priv->family = ctx->afi->family;
-
        nla = tb[NFTA_LOG_PREFIX];
        if (nla != NULL) {
                priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
@@ -77,7 +74,8 @@ static int nft_log_init(const struct nft_ctx *ctx,
        return 0;
 }
 
-static void nft_log_destroy(const struct nft_expr *expr)
+static void nft_log_destroy(const struct nft_ctx *ctx,
+                           const struct nft_expr *expr)
 {
        struct nft_log *priv = nft_expr_priv(expr);
 
index 8a6116b75b5a03181e3183d5090c23059dd5a09e..7fd2bea8aa239f347dc461c7bc45869dac405573 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables_core.h>
 
 struct nft_lookup {
        struct nft_set                  *set;
@@ -88,11 +89,12 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
        return 0;
 }
 
-static void nft_lookup_destroy(const struct nft_expr *expr)
+static void nft_lookup_destroy(const struct nft_ctx *ctx,
+                              const struct nft_expr *expr)
 {
        struct nft_lookup *priv = nft_expr_priv(expr);
 
-       nf_tables_unbind_set(NULL, priv->set, &priv->binding);
+       nf_tables_unbind_set(ctx, priv->set, &priv->binding);
 }
 
 static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
index e8254ad2e5a9f37e84694293c8ba4069b5e5f35e..425cf39af8907f1d0618b0904121073ea4dc116a 100644 (file)
@@ -116,7 +116,7 @@ static void nft_meta_get_eval(const struct nft_expr *expr,
                                 skb->sk->sk_socket->file->f_cred->fsgid);
                read_unlock_bh(&skb->sk->sk_callback_lock);
                break;
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
        case NFT_META_RTCLASSID: {
                const struct dst_entry *dst = skb_dst(skb);
 
@@ -199,7 +199,7 @@ static int nft_meta_init_validate_get(uint32_t key)
        case NFT_META_OIFTYPE:
        case NFT_META_SKUID:
        case NFT_META_SKGID:
-#ifdef CONFIG_NET_CLS_ROUTE
+#ifdef CONFIG_IP_ROUTE_CLASSID
        case NFT_META_RTCLASSID:
 #endif
 #ifdef CONFIG_NETWORK_SECMARK
index d3b1ffe26181b22538ab29fefadd7a41d96b76f1..a0195d28bcfc2e5b90025ac9ceb14499d1747934 100644 (file)
@@ -31,8 +31,8 @@ struct nft_nat {
        enum nft_registers      sreg_addr_max:8;
        enum nft_registers      sreg_proto_min:8;
        enum nft_registers      sreg_proto_max:8;
-       int                     family;
-       enum nf_nat_manip_type  type;
+       enum nf_nat_manip_type  type:8;
+       u8                      family;
 };
 
 static void nft_nat_eval(const struct nft_expr *expr,
@@ -88,6 +88,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        const struct nlattr * const tb[])
 {
        struct nft_nat *priv = nft_expr_priv(expr);
+       u32 family;
        int err;
 
        if (tb[NFTA_NAT_TYPE] == NULL)
@@ -107,9 +108,12 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        if (tb[NFTA_NAT_FAMILY] == NULL)
                return -EINVAL;
 
-       priv->family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
-       if (priv->family != AF_INET && priv->family != AF_INET6)
-               return -EINVAL;
+       family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
+       if (family != AF_INET && family != AF_INET6)
+               return -EAFNOSUPPORT;
+       if (family != ctx->afi->family)
+               return -EOPNOTSUPP;
+       priv->family = family;
 
        if (tb[NFTA_NAT_REG_ADDR_MIN]) {
                priv->sreg_addr_min = ntohl(nla_get_be32(
@@ -202,13 +206,7 @@ static struct nft_expr_type nft_nat_type __read_mostly = {
 
 static int __init nft_nat_module_init(void)
 {
-       int err;
-
-       err = nft_register_expr(&nft_nat_type);
-       if (err < 0)
-               return err;
-
-       return 0;
+       return nft_register_expr(&nft_nat_type);
 }
 
 static void __exit nft_nat_module_exit(void)
index a2aeb318678f9e0e577801f6e42bda4df66ea805..85daa84bfdfee3d65296fb62c723a78e180c4497 100644 (file)
@@ -135,7 +135,8 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
        if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
                return ERR_PTR(-EINVAL);
 
-       if (len <= 4 && IS_ALIGNED(offset, len) && base != NFT_PAYLOAD_LL_HEADER)
+       if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
+           base != NFT_PAYLOAD_LL_HEADER)
                return &nft_payload_fast_ops;
        else
                return &nft_payload_ops;
index cbea473d69e953e9ba9e9d36ec4962aa3af57c1e..e8ae2f6bf232d8ccef7379f9bb573291da5581b4 100644 (file)
@@ -25,7 +25,6 @@ struct nft_queue {
        u16     queuenum;
        u16     queues_total;
        u16     flags;
-       u8      family;
 };
 
 static void nft_queue_eval(const struct nft_expr *expr,
@@ -43,7 +42,7 @@ static void nft_queue_eval(const struct nft_expr *expr,
                        queue = priv->queuenum + cpu % priv->queues_total;
                } else {
                        queue = nfqueue_hash(pkt->skb, queue,
-                                            priv->queues_total, priv->family,
+                                            priv->queues_total, pkt->ops->pf,
                                             jhash_initval);
                }
        }
@@ -71,7 +70,6 @@ static int nft_queue_init(const struct nft_ctx *ctx,
                return -EINVAL;
 
        init_hashrandom(&jhash_initval);
-       priv->family = ctx->afi->family;
        priv->queuenum = ntohs(nla_get_be16(tb[NFTA_QUEUE_NUM]));
 
        if (tb[NFTA_QUEUE_TOTAL] != NULL)
index ca0c1b231bfe25cfe3c341c2aea8967f0dd4a4ec..e21d69d13506b95946820f24641fe7e48d885866 100644 (file)
@@ -69,8 +69,10 @@ static void nft_rbtree_elem_destroy(const struct nft_set *set,
                                    struct nft_rbtree_elem *rbe)
 {
        nft_data_uninit(&rbe->key, NFT_DATA_VALUE);
-       if (set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP &&
+           !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                nft_data_uninit(rbe->data, set->dtype);
+
        kfree(rbe);
 }
 
@@ -108,7 +110,8 @@ static int nft_rbtree_insert(const struct nft_set *set,
        int err;
 
        size = sizeof(*rbe);
-       if (set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP &&
+           !(elem->flags & NFT_SET_ELEM_INTERVAL_END))
                size += sizeof(rbe->data[0]);
 
        rbe = kzalloc(size, GFP_KERNEL);
@@ -117,7 +120,8 @@ static int nft_rbtree_insert(const struct nft_set *set,
 
        rbe->flags = elem->flags;
        nft_data_copy(&rbe->key, &elem->key);
-       if (set->flags & NFT_SET_MAP)
+       if (set->flags & NFT_SET_MAP &&
+           !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                nft_data_copy(rbe->data, &elem->data);
 
        err = __nft_rbtree_insert(set, rbe);
@@ -153,7 +157,8 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
                        parent = parent->rb_right;
                else {
                        elem->cookie = rbe;
-                       if (set->flags & NFT_SET_MAP)
+                       if (set->flags & NFT_SET_MAP &&
+                           !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                                nft_data_copy(&elem->data, rbe->data);
                        elem->flags = rbe->flags;
                        return 0;
@@ -177,7 +182,8 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
 
                rbe = rb_entry(node, struct nft_rbtree_elem, node);
                nft_data_copy(&elem.key, &rbe->key);
-               if (set->flags & NFT_SET_MAP)
+               if (set->flags & NFT_SET_MAP &&
+                   !(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
                        nft_data_copy(&elem.data, rbe->data);
                elem.flags = rbe->flags;
 
index 5e204711d7049781052095ca317a4efd944ea07a..f3448c2964468abc08d2b3630be18953820e1aff 100644 (file)
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_tables.h>
-#include <net/icmp.h>
-#include <net/netfilter/ipv4/nf_reject.h>
+#include <net/netfilter/nft_reject.h>
 
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-#include <net/netfilter/ipv6/nf_reject.h>
-#endif
-
-struct nft_reject {
-       enum nft_reject_types   type:8;
-       u8                      icmp_code;
-       u8                      family;
-};
-
-static void nft_reject_eval(const struct nft_expr *expr,
-                             struct nft_data data[NFT_REG_MAX + 1],
-                             const struct nft_pktinfo *pkt)
-{
-       struct nft_reject *priv = nft_expr_priv(expr);
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-       struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
-#endif
-       switch (priv->type) {
-       case NFT_REJECT_ICMP_UNREACH:
-               if (priv->family == NFPROTO_IPV4)
-                       nf_send_unreach(pkt->skb, priv->icmp_code);
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-               else if (priv->family == NFPROTO_IPV6)
-                       nf_send_unreach6(net, pkt->skb, priv->icmp_code,
-                                     pkt->ops->hooknum);
-#endif
-               break;
-       case NFT_REJECT_TCP_RST:
-               if (priv->family == NFPROTO_IPV4)
-                       nf_send_reset(pkt->skb, pkt->ops->hooknum);
-#if IS_ENABLED(CONFIG_NF_TABLES_IPV6)
-               else if (priv->family == NFPROTO_IPV6)
-                       nf_send_reset6(net, pkt->skb, pkt->ops->hooknum);
-#endif
-               break;
-       }
-
-       data[NFT_REG_VERDICT].verdict = NF_DROP;
-}
-
-static const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
+const struct nla_policy nft_reject_policy[NFTA_REJECT_MAX + 1] = {
        [NFTA_REJECT_TYPE]              = { .type = NLA_U32 },
        [NFTA_REJECT_ICMP_CODE]         = { .type = NLA_U8 },
 };
+EXPORT_SYMBOL_GPL(nft_reject_policy);
 
-static int nft_reject_init(const struct nft_ctx *ctx,
-                          const struct nft_expr *expr,
-                          const struct nlattr * const tb[])
+int nft_reject_init(const struct nft_ctx *ctx,
+                   const struct nft_expr *expr,
+                   const struct nlattr * const tb[])
 {
        struct nft_reject *priv = nft_expr_priv(expr);
 
        if (tb[NFTA_REJECT_TYPE] == NULL)
                return -EINVAL;
 
-       priv->family = ctx->afi->family;
        priv->type = ntohl(nla_get_be32(tb[NFTA_REJECT_TYPE]));
        switch (priv->type) {
        case NFT_REJECT_ICMP_UNREACH:
@@ -89,8 +47,9 @@ static int nft_reject_init(const struct nft_ctx *ctx,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(nft_reject_init);
 
-static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
+int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_reject *priv = nft_expr_priv(expr);
 
@@ -109,37 +68,7 @@ static int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr)
 nla_put_failure:
        return -1;
 }
-
-static struct nft_expr_type nft_reject_type;
-static const struct nft_expr_ops nft_reject_ops = {
-       .type           = &nft_reject_type,
-       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
-       .eval           = nft_reject_eval,
-       .init           = nft_reject_init,
-       .dump           = nft_reject_dump,
-};
-
-static struct nft_expr_type nft_reject_type __read_mostly = {
-       .name           = "reject",
-       .ops            = &nft_reject_ops,
-       .policy         = nft_reject_policy,
-       .maxattr        = NFTA_REJECT_MAX,
-       .owner          = THIS_MODULE,
-};
-
-static int __init nft_reject_module_init(void)
-{
-       return nft_register_expr(&nft_reject_type);
-}
-
-static void __exit nft_reject_module_exit(void)
-{
-       nft_unregister_expr(&nft_reject_type);
-}
-
-module_init(nft_reject_module_init);
-module_exit(nft_reject_module_exit);
+EXPORT_SYMBOL_GPL(nft_reject_dump);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("reject");
diff --git a/net/netfilter/nft_reject_inet.c b/net/netfilter/nft_reject_inet.c
new file mode 100644 (file)
index 0000000..b718a52
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nft_reject.h>
+
+static void nft_reject_inet_eval(const struct nft_expr *expr,
+                                struct nft_data data[NFT_REG_MAX + 1],
+                                const struct nft_pktinfo *pkt)
+{
+       switch (pkt->ops->pf) {
+       case NFPROTO_IPV4:
+               return nft_reject_ipv4_eval(expr, data, pkt);
+       case NFPROTO_IPV6:
+               return nft_reject_ipv6_eval(expr, data, pkt);
+       }
+}
+
+static struct nft_expr_type nft_reject_inet_type;
+static const struct nft_expr_ops nft_reject_inet_ops = {
+       .type           = &nft_reject_inet_type,
+       .size           = NFT_EXPR_SIZE(sizeof(struct nft_reject)),
+       .eval           = nft_reject_inet_eval,
+       .init           = nft_reject_init,
+       .dump           = nft_reject_dump,
+};
+
+static struct nft_expr_type nft_reject_inet_type __read_mostly = {
+       .family         = NFPROTO_INET,
+       .name           = "reject",
+       .ops            = &nft_reject_inet_ops,
+       .policy         = nft_reject_policy,
+       .maxattr        = NFTA_REJECT_MAX,
+       .owner          = THIS_MODULE,
+};
+
+static int __init nft_reject_inet_module_init(void)
+{
+       return nft_register_expr(&nft_reject_inet_type);
+}
+
+static void __exit nft_reject_inet_module_exit(void)
+{
+       nft_unregister_expr(&nft_reject_inet_type);
+}
+
+module_init(nft_reject_inet_module_init);
+module_exit(nft_reject_inet_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_ALIAS_NFT_AF_EXPR(1, "reject");
index 3228d7f24eb4107ff717af4323e834af3e680797..4973cbddc446bd50a377765bec23128716ff630e 100644 (file)
@@ -146,11 +146,11 @@ audit_tg(struct sk_buff *skb, const struct xt_action_param *par)
 
                if (par->family == NFPROTO_BRIDGE) {
                        switch (eth_hdr(skb)->h_proto) {
-                       case __constant_htons(ETH_P_IP):
+                       case htons(ETH_P_IP):
                                audit_ip4(ab, skb);
                                break;
 
-                       case __constant_htons(ETH_P_IPV6):
+                       case htons(ETH_P_IPV6):
                                audit_ip6(ab, skb);
                                break;
                        }
index 5929be622c5cd27b9e706811042c9e176a3c78f7..75747aecdebe6344ccbfcf178c299be013d8f763 100644 (file)
@@ -228,12 +228,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par,
                        goto err3;
        }
 
-       __set_bit(IPS_TEMPLATE_BIT, &ct->status);
-       __set_bit(IPS_CONFIRMED_BIT, &ct->status);
-
-       /* Overload tuple linked list to put us in template list. */
-       hlist_nulls_add_head_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode,
-                                &par->net->ct.tmpl);
+       nf_conntrack_tmpl_insert(par->net, ct);
 out:
        info->ct = ct;
        return 0;
index c40b2695633b15960ac65eb84ebc2405b4aa2c1c..458464e7bd7a841915aeebdd448cb17bb49c01e4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/jhash.h>
 #include <linux/slab.h>
 #include <linux/list.h>
+#include <linux/rbtree.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/skbuff.h>
 #include <net/netfilter/nf_conntrack_tuple.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
+#define CONNLIMIT_SLOTS                32
+#define CONNLIMIT_LOCK_SLOTS   32
+#define CONNLIMIT_GC_MAX_NODES 8
+
 /* we will save the tuples of all connections we care about */
 struct xt_connlimit_conn {
        struct hlist_node               node;
@@ -38,16 +43,26 @@ struct xt_connlimit_conn {
        union nf_inet_addr              addr;
 };
 
+struct xt_connlimit_rb {
+       struct rb_node node;
+       struct hlist_head hhead; /* connections/hosts in same subnet */
+       union nf_inet_addr addr; /* search key */
+};
+
 struct xt_connlimit_data {
-       struct hlist_head       iphash[256];
-       spinlock_t              lock;
+       struct rb_root climit_root4[CONNLIMIT_SLOTS];
+       struct rb_root climit_root6[CONNLIMIT_SLOTS];
+       spinlock_t              locks[CONNLIMIT_LOCK_SLOTS];
 };
 
 static u_int32_t connlimit_rnd __read_mostly;
+static struct kmem_cache *connlimit_rb_cachep __read_mostly;
+static struct kmem_cache *connlimit_conn_cachep __read_mostly;
 
 static inline unsigned int connlimit_iphash(__be32 addr)
 {
-       return jhash_1word((__force __u32)addr, connlimit_rnd) & 0xFF;
+       return jhash_1word((__force __u32)addr,
+                           connlimit_rnd) % CONNLIMIT_SLOTS;
 }
 
 static inline unsigned int
@@ -60,7 +75,8 @@ connlimit_iphash6(const union nf_inet_addr *addr,
        for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i)
                res.ip6[i] = addr->ip6[i] & mask->ip6[i];
 
-       return jhash2((u32 *)res.ip6, ARRAY_SIZE(res.ip6), connlimit_rnd) & 0xFF;
+       return jhash2((u32 *)res.ip6, ARRAY_SIZE(res.ip6),
+                      connlimit_rnd) % CONNLIMIT_SLOTS;
 }
 
 static inline bool already_closed(const struct nf_conn *conn)
@@ -72,13 +88,14 @@ static inline bool already_closed(const struct nf_conn *conn)
                return 0;
 }
 
-static inline unsigned int
+static int
 same_source_net(const union nf_inet_addr *addr,
                const union nf_inet_addr *mask,
                const union nf_inet_addr *u3, u_int8_t family)
 {
        if (family == NFPROTO_IPV4) {
-               return (addr->ip & mask->ip) == (u3->ip & mask->ip);
+               return ntohl(addr->ip & mask->ip) -
+                      ntohl(u3->ip & mask->ip);
        } else {
                union nf_inet_addr lh, rh;
                unsigned int i;
@@ -88,89 +105,205 @@ same_source_net(const union nf_inet_addr *addr,
                        rh.ip6[i] = u3->ip6[i] & mask->ip6[i];
                }
 
-               return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6)) == 0;
+               return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6));
        }
 }
 
-static int count_them(struct net *net,
-                     struct xt_connlimit_data *data,
+static bool add_hlist(struct hlist_head *head,
                      const struct nf_conntrack_tuple *tuple,
-                     const union nf_inet_addr *addr,
-                     const union nf_inet_addr *mask,
-                     u_int8_t family)
+                     const union nf_inet_addr *addr)
+{
+       struct xt_connlimit_conn *conn;
+
+       conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC);
+       if (conn == NULL)
+               return false;
+       conn->tuple = *tuple;
+       conn->addr = *addr;
+       hlist_add_head(&conn->node, head);
+       return true;
+}
+
+static unsigned int check_hlist(struct net *net,
+                               struct hlist_head *head,
+                               const struct nf_conntrack_tuple *tuple,
+                               bool *addit)
 {
        const struct nf_conntrack_tuple_hash *found;
        struct xt_connlimit_conn *conn;
        struct hlist_node *n;
        struct nf_conn *found_ct;
-       struct hlist_head *hash;
-       bool addit = true;
-       int matches = 0;
-
-       if (family == NFPROTO_IPV6)
-               hash = &data->iphash[connlimit_iphash6(addr, mask)];
-       else
-               hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
+       unsigned int length = 0;
 
+       *addit = true;
        rcu_read_lock();
 
        /* check the saved connections */
-       hlist_for_each_entry_safe(conn, n, hash, node) {
+       hlist_for_each_entry_safe(conn, n, head, node) {
                found    = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE,
                                                 &conn->tuple);
-               found_ct = NULL;
+               if (found == NULL) {
+                       hlist_del(&conn->node);
+                       kmem_cache_free(connlimit_conn_cachep, conn);
+                       continue;
+               }
 
-               if (found != NULL)
-                       found_ct = nf_ct_tuplehash_to_ctrack(found);
+               found_ct = nf_ct_tuplehash_to_ctrack(found);
 
-               if (found_ct != NULL &&
-                   nf_ct_tuple_equal(&conn->tuple, tuple) &&
-                   !already_closed(found_ct))
+               if (nf_ct_tuple_equal(&conn->tuple, tuple)) {
                        /*
                         * Just to be sure we have it only once in the list.
                         * We should not see tuples twice unless someone hooks
                         * this into a table without "-p tcp --syn".
                         */
-                       addit = false;
-
-               if (found == NULL) {
-                       /* this one is gone */
-                       hlist_del(&conn->node);
-                       kfree(conn);
-                       continue;
-               }
-
-               if (already_closed(found_ct)) {
+                       *addit = false;
+               } else if (already_closed(found_ct)) {
                        /*
                         * we do not care about connections which are
                         * closed already -> ditch it
                         */
                        nf_ct_put(found_ct);
                        hlist_del(&conn->node);
-                       kfree(conn);
+                       kmem_cache_free(connlimit_conn_cachep, conn);
                        continue;
                }
 
-               if (same_source_net(addr, mask, &conn->addr, family))
-                       /* same source network -> be counted! */
-                       ++matches;
                nf_ct_put(found_ct);
+               length++;
        }
 
        rcu_read_unlock();
 
-       if (addit) {
-               /* save the new connection in our list */
-               conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
-               if (conn == NULL)
-                       return -ENOMEM;
-               conn->tuple = *tuple;
-               conn->addr = *addr;
-               hlist_add_head(&conn->node, hash);
-               ++matches;
+       return length;
+}
+
+static void tree_nodes_free(struct rb_root *root,
+                           struct xt_connlimit_rb *gc_nodes[],
+                           unsigned int gc_count)
+{
+       struct xt_connlimit_rb *rbconn;
+
+       while (gc_count) {
+               rbconn = gc_nodes[--gc_count];
+               rb_erase(&rbconn->node, root);
+               kmem_cache_free(connlimit_rb_cachep, rbconn);
+       }
+}
+
+static unsigned int
+count_tree(struct net *net, struct rb_root *root,
+          const struct nf_conntrack_tuple *tuple,
+          const union nf_inet_addr *addr, const union nf_inet_addr *mask,
+          u8 family)
+{
+       struct xt_connlimit_rb *gc_nodes[CONNLIMIT_GC_MAX_NODES];
+       struct rb_node **rbnode, *parent;
+       struct xt_connlimit_rb *rbconn;
+       struct xt_connlimit_conn *conn;
+       unsigned int gc_count;
+       bool no_gc = false;
+
+ restart:
+       gc_count = 0;
+       parent = NULL;
+       rbnode = &(root->rb_node);
+       while (*rbnode) {
+               int diff;
+               bool addit;
+
+               rbconn = container_of(*rbnode, struct xt_connlimit_rb, node);
+
+               parent = *rbnode;
+               diff = same_source_net(addr, mask, &rbconn->addr, family);
+               if (diff < 0) {
+                       rbnode = &((*rbnode)->rb_left);
+               } else if (diff > 0) {
+                       rbnode = &((*rbnode)->rb_right);
+               } else {
+                       /* same source network -> be counted! */
+                       unsigned int count;
+                       count = check_hlist(net, &rbconn->hhead, tuple, &addit);
+
+                       tree_nodes_free(root, gc_nodes, gc_count);
+                       if (!addit)
+                               return count;
+
+                       if (!add_hlist(&rbconn->hhead, tuple, addr))
+                               return 0; /* hotdrop */
+
+                       return count + 1;
+               }
+
+               if (no_gc || gc_count >= ARRAY_SIZE(gc_nodes))
+                       continue;
+
+               /* only used for GC on hhead, retval and 'addit' ignored */
+               check_hlist(net, &rbconn->hhead, tuple, &addit);
+               if (hlist_empty(&rbconn->hhead))
+                       gc_nodes[gc_count++] = rbconn;
+       }
+
+       if (gc_count) {
+               no_gc = true;
+               tree_nodes_free(root, gc_nodes, gc_count);
+               /* tree_node_free before new allocation permits
+                * allocator to re-use newly free'd object.
+                *
+                * This is a rare event; in most cases we will find
+                * existing node to re-use. (or gc_count is 0).
+                */
+               goto restart;
+       }
+
+       /* no match, need to insert new node */
+       rbconn = kmem_cache_alloc(connlimit_rb_cachep, GFP_ATOMIC);
+       if (rbconn == NULL)
+               return 0;
+
+       conn = kmem_cache_alloc(connlimit_conn_cachep, GFP_ATOMIC);
+       if (conn == NULL) {
+               kmem_cache_free(connlimit_rb_cachep, rbconn);
+               return 0;
+       }
+
+       conn->tuple = *tuple;
+       conn->addr = *addr;
+       rbconn->addr = *addr;
+
+       INIT_HLIST_HEAD(&rbconn->hhead);
+       hlist_add_head(&conn->node, &rbconn->hhead);
+
+       rb_link_node(&rbconn->node, parent, rbnode);
+       rb_insert_color(&rbconn->node, root);
+       return 1;
+}
+
+static int count_them(struct net *net,
+                     struct xt_connlimit_data *data,
+                     const struct nf_conntrack_tuple *tuple,
+                     const union nf_inet_addr *addr,
+                     const union nf_inet_addr *mask,
+                     u_int8_t family)
+{
+       struct rb_root *root;
+       int count;
+       u32 hash;
+
+       if (family == NFPROTO_IPV6) {
+               hash = connlimit_iphash6(addr, mask);
+               root = &data->climit_root6[hash];
+       } else {
+               hash = connlimit_iphash(addr->ip & mask->ip);
+               root = &data->climit_root4[hash];
        }
 
-       return matches;
+       spin_lock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]);
+
+       count = count_tree(net, root, tuple, addr, mask, family);
+
+       spin_unlock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]);
+
+       return count;
 }
 
 static bool
@@ -183,7 +316,7 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
        const struct nf_conntrack_tuple *tuple_ptr = &tuple;
        enum ip_conntrack_info ctinfo;
        const struct nf_conn *ct;
-       int connections;
+       unsigned int connections;
 
        ct = nf_ct_get(skb, &ctinfo);
        if (ct != NULL)
@@ -202,12 +335,9 @@ connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par)
                          iph->daddr : iph->saddr;
        }
 
-       spin_lock_bh(&info->data->lock);
        connections = count_them(net, info->data, tuple_ptr, &addr,
                                 &info->mask, par->family);
-       spin_unlock_bh(&info->data->lock);
-
-       if (connections < 0)
+       if (connections == 0)
                /* kmalloc failed, drop it entirely */
                goto hotdrop;
 
@@ -247,29 +377,47 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par)
                return -ENOMEM;
        }
 
-       spin_lock_init(&info->data->lock);
-       for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i)
-               INIT_HLIST_HEAD(&info->data->iphash[i]);
+       for (i = 0; i < ARRAY_SIZE(info->data->locks); ++i)
+               spin_lock_init(&info->data->locks[i]);
+
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i)
+               info->data->climit_root4[i] = RB_ROOT;
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i)
+               info->data->climit_root6[i] = RB_ROOT;
 
        return 0;
 }
 
-static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
+static void destroy_tree(struct rb_root *r)
 {
-       const struct xt_connlimit_info *info = par->matchinfo;
        struct xt_connlimit_conn *conn;
+       struct xt_connlimit_rb *rbconn;
        struct hlist_node *n;
-       struct hlist_head *hash = info->data->iphash;
+       struct rb_node *node;
+
+       while ((node = rb_first(r)) != NULL) {
+               rbconn = container_of(node, struct xt_connlimit_rb, node);
+
+               rb_erase(node, r);
+
+               hlist_for_each_entry_safe(conn, n, &rbconn->hhead, node)
+                       kmem_cache_free(connlimit_conn_cachep, conn);
+
+               kmem_cache_free(connlimit_rb_cachep, rbconn);
+       }
+}
+
+static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
+{
+       const struct xt_connlimit_info *info = par->matchinfo;
        unsigned int i;
 
        nf_ct_l3proto_module_put(par->family);
 
-       for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) {
-               hlist_for_each_entry_safe(conn, n, &hash[i], node) {
-                       hlist_del(&conn->node);
-                       kfree(conn);
-               }
-       }
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i)
+               destroy_tree(&info->data->climit_root4[i]);
+       for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i)
+               destroy_tree(&info->data->climit_root6[i]);
 
        kfree(info->data);
 }
@@ -287,12 +435,37 @@ static struct xt_match connlimit_mt_reg __read_mostly = {
 
 static int __init connlimit_mt_init(void)
 {
-       return xt_register_match(&connlimit_mt_reg);
+       int ret;
+
+       BUILD_BUG_ON(CONNLIMIT_LOCK_SLOTS > CONNLIMIT_SLOTS);
+       BUILD_BUG_ON((CONNLIMIT_SLOTS % CONNLIMIT_LOCK_SLOTS) != 0);
+
+       connlimit_conn_cachep = kmem_cache_create("xt_connlimit_conn",
+                                          sizeof(struct xt_connlimit_conn),
+                                          0, 0, NULL);
+       if (!connlimit_conn_cachep)
+               return -ENOMEM;
+
+       connlimit_rb_cachep = kmem_cache_create("xt_connlimit_rb",
+                                          sizeof(struct xt_connlimit_rb),
+                                          0, 0, NULL);
+       if (!connlimit_rb_cachep) {
+               kmem_cache_destroy(connlimit_conn_cachep);
+               return -ENOMEM;
+       }
+       ret = xt_register_match(&connlimit_mt_reg);
+       if (ret != 0) {
+               kmem_cache_destroy(connlimit_conn_cachep);
+               kmem_cache_destroy(connlimit_rb_cachep);
+       }
+       return ret;
 }
 
 static void __exit connlimit_mt_exit(void)
 {
        xt_unregister_match(&connlimit_mt_reg);
+       kmem_cache_destroy(connlimit_conn_cachep);
+       kmem_cache_destroy(connlimit_rb_cachep);
 }
 
 module_init(connlimit_mt_init);
index a4c7561698c5c2fa5dd9b79717e0cc7116347e54..89d53104c6b365b12c76ff684064bc5d032656c3 100644 (file)
@@ -60,7 +60,7 @@ static bool comp_mt(const struct sk_buff *skb, struct xt_action_param *par)
        }
 
        return spi_match(compinfo->spis[0], compinfo->spis[1],
-                        ntohl(chdr->cpi << 16),
+                        ntohs(chdr->cpi),
                         !!(compinfo->invflags & XT_IPCOMP_INV_SPI));
 }
 
index fdf51353cf78ac80958cadfa0e58e159970aa8bf..c2d585c4f7c5cb2c82ea2adb03723e90b61c91f1 100644 (file)
@@ -1460,7 +1460,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
        if (nlk->netlink_bind && nlk->groups[0]) {
                int i;
 
-               for (i=0; i<nlk->ngroups; i++) {
+               for (i = 0; i < nlk->ngroups; i++) {
                        if (test_bit(i, nlk->groups))
                                nlk->netlink_bind(i);
                }
@@ -1489,8 +1489,8 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family != AF_NETLINK)
                return -EINVAL;
 
-       /* Only superuser is allowed to send multicasts */
-       if (nladdr->nl_groups && !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
+       if ((nladdr->nl_groups || nladdr->nl_pid) &&
+           !netlink_capable(sock, NL_CFG_F_NONROOT_SEND))
                return -EPERM;
 
        if (!nlk->portid)
@@ -2343,6 +2343,11 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        }
 #endif
 
+       /* Record the max length of recvmsg() calls for future allocations */
+       nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len);
+       nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len,
+                                    16384);
+
        copied = data_skb->len;
        if (len < copied) {
                msg->msg_flags |= MSG_TRUNC;
@@ -2549,7 +2554,7 @@ __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int fla
        struct nlmsghdr *nlh;
        int size = nlmsg_msg_size(len);
 
-       nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
+       nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_ALIGN(size));
        nlh->nlmsg_type = type;
        nlh->nlmsg_len = size;
        nlh->nlmsg_flags = flags;
@@ -2587,7 +2592,27 @@ static int netlink_dump(struct sock *sk)
        if (!netlink_rx_is_mmaped(sk) &&
            atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
                goto errout_skb;
-       skb = netlink_alloc_skb(sk, alloc_size, nlk->portid, GFP_KERNEL);
+
+       /* NLMSG_GOODSIZE is small to avoid high order allocations being
+        * required, but it makes sense to _attempt_ a 16K bytes allocation
+        * to reduce number of system calls on dump operations, if user
+        * ever provided a big enough buffer.
+        */
+       if (alloc_size < nlk->max_recvmsg_len) {
+               skb = netlink_alloc_skb(sk,
+                                       nlk->max_recvmsg_len,
+                                       nlk->portid,
+                                       GFP_KERNEL |
+                                       __GFP_NOWARN |
+                                       __GFP_NORETRY);
+               /* available room should be exact amount to avoid MSG_TRUNC */
+               if (skb)
+                       skb_reserve(skb, skb_tailroom(skb) -
+                                        nlk->max_recvmsg_len);
+       }
+       if (!skb)
+               skb = netlink_alloc_skb(sk, alloc_size, nlk->portid,
+                                       GFP_KERNEL);
        if (!skb)
                goto errout_skb;
        netlink_skb_set_owner_r(skb, sk);
index acbd774eeb7c5afd568d8eb9aa375ecc81949793..ed13a790b00e1684215e04c6a68f71f9491cb3c9 100644 (file)
@@ -31,6 +31,7 @@ struct netlink_sock {
        u32                     ngroups;
        unsigned long           *groups;
        unsigned long           state;
+       size_t                  max_recvmsg_len;
        wait_queue_head_t       wait;
        bool                    cb_running;
        struct netlink_callback cb;
index df4692826ead9ef8b5761f58ef7218bf4b3f5119..a3276e3c4feb065278b5195652378157619ff94c 100644 (file)
@@ -55,6 +55,7 @@
 
 #include "datapath.h"
 #include "flow.h"
+#include "flow_table.h"
 #include "flow_netlink.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
@@ -160,7 +161,6 @@ static void destroy_dp_rcu(struct rcu_head *rcu)
 {
        struct datapath *dp = container_of(rcu, struct datapath, rcu);
 
-       ovs_flow_tbl_destroy(&dp->table);
        free_percpu(dp->stats_percpu);
        release_net(ovs_dp_get_net(dp));
        kfree(dp->ports);
@@ -256,10 +256,10 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 
 out:
        /* Update datapath statistics. */
-       u64_stats_update_begin(&stats->sync);
+       u64_stats_update_begin(&stats->syncp);
        (*stats_counter)++;
        stats->n_mask_hit += n_mask_hit;
-       u64_stats_update_end(&stats->sync);
+       u64_stats_update_end(&stats->syncp);
 }
 
 static struct genl_family dp_packet_genl_family = {
@@ -295,9 +295,9 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
 err:
        stats = this_cpu_ptr(dp->stats_percpu);
 
-       u64_stats_update_begin(&stats->sync);
+       u64_stats_update_begin(&stats->syncp);
        stats->n_lost++;
-       u64_stats_update_end(&stats->sync);
+       u64_stats_update_end(&stats->syncp);
 
        return err;
 }
@@ -464,12 +464,24 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
        }
        nla->nla_len = nla_attr_size(skb->len);
 
-       skb_zerocopy(user_skb, skb, skb->len, hlen);
+       err = skb_zerocopy(user_skb, skb, skb->len, hlen);
+       if (err)
+               goto out;
+
+       /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
+       if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
+               size_t plen = NLA_ALIGN(user_skb->len) - user_skb->len;
+
+               if (plen > 0)
+                       memset(skb_put(user_skb, plen), 0, plen);
+       }
 
        ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
 
        err = genlmsg_unicast(ovs_dp_get_net(dp), user_skb, upcall_info->portid);
 out:
+       if (err)
+               skb_tx_error(skb);
        kfree_skb(nskb);
        return err;
 }
@@ -598,9 +610,9 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats,
                percpu_stats = per_cpu_ptr(dp->stats_percpu, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&percpu_stats->sync);
+                       start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
                        local_stats = *percpu_stats;
-               } while (u64_stats_fetch_retry_bh(&percpu_stats->sync, start));
+               } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
 
                stats->n_hit += local_stats.n_hit;
                stats->n_missed += local_stats.n_missed;
@@ -852,11 +864,8 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
                        goto err_unlock_ovs;
 
                /* The unmasked key has to be the same for flow updates. */
-               error = -EINVAL;
-               if (!ovs_flow_cmp_unmasked_key(flow, &match)) {
-                       OVS_NLERR("Flow modification message rejected, unmasked key does not match.\n");
+               if (!ovs_flow_cmp_unmasked_key(flow, &match))
                        goto err_unlock_ovs;
-               }
 
                /* Update actions. */
                old_acts = ovsl_dereference(flow->sf_acts);
@@ -1079,6 +1088,7 @@ static size_t ovs_dp_cmd_msg_size(void)
        msgsize += nla_total_size(IFNAMSIZ);
        msgsize += nla_total_size(sizeof(struct ovs_dp_stats));
        msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats));
+       msgsize += nla_total_size(sizeof(u32)); /* OVS_DP_ATTR_USER_FEATURES */
 
        return msgsize;
 }
@@ -1168,7 +1178,7 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb, struct genl_info *in
        struct datapath *dp;
 
        dp = lookup_datapath(sock_net(skb->sk), info->userhdr, info->attrs);
-       if (!dp)
+       if (IS_ERR(dp))
                return;
 
        WARN(dp->user_features, "Dropping previously announced user features\n");
@@ -1209,18 +1219,12 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (err)
                goto err_free_dp;
 
-       dp->stats_percpu = alloc_percpu(struct dp_stats_percpu);
+       dp->stats_percpu = netdev_alloc_pcpu_stats(struct dp_stats_percpu);
        if (!dp->stats_percpu) {
                err = -ENOMEM;
                goto err_destroy_table;
        }
 
-       for_each_possible_cpu(i) {
-               struct dp_stats_percpu *dpath_stats;
-               dpath_stats = per_cpu_ptr(dp->stats_percpu, i);
-               u64_stats_init(&dpath_stats->sync);
-       }
-
        dp->ports = kmalloc(DP_VPORT_HASH_BUCKETS * sizeof(struct hlist_head),
                            GFP_KERNEL);
        if (!dp->ports) {
@@ -1279,7 +1283,7 @@ err_destroy_ports_array:
 err_destroy_percpu:
        free_percpu(dp->stats_percpu);
 err_destroy_table:
-       ovs_flow_tbl_destroy(&dp->table);
+       ovs_flow_tbl_destroy(&dp->table, false);
 err_free_dp:
        release_net(ovs_dp_get_net(dp));
        kfree(dp);
@@ -1306,10 +1310,13 @@ static void __dp_destroy(struct datapath *dp)
        list_del_rcu(&dp->list_node);
 
        /* OVSP_LOCAL is datapath internal port. We need to make sure that
-        * all port in datapath are destroyed first before freeing datapath.
+        * all ports in datapath are destroyed first before freeing datapath.
         */
        ovs_dp_detach_port(ovs_vport_ovsl(dp, OVSP_LOCAL));
 
+       /* RCU destroy the flow table */
+       ovs_flow_tbl_destroy(&dp->table, true);
+
        call_rcu(&dp->rcu, destroy_dp_rcu);
 }
 
@@ -1753,11 +1760,12 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        int bucket = cb->args[0], skip = cb->args[1];
        int i, j = 0;
 
+       rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
-       if (!dp)
+       if (!dp) {
+               rcu_read_unlock();
                return -ENODEV;
-
-       rcu_read_lock();
+       }
        for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
                struct vport *vport;
 
index 6be9fbb5e9cbd57e11cce9ebac259d896db5a79c..05317380fc03a03af708716f162738727cab5fff 100644 (file)
@@ -55,7 +55,7 @@ struct dp_stats_percpu {
        u64 n_missed;
        u64 n_lost;
        u64 n_mask_hit;
-       struct u64_stats_sync sync;
+       struct u64_stats_sync syncp;
 };
 
 /**
index 16f4b46161d4fe2b806a46e895aa46922e2ce038..2998989e76db0a7ccb8e25ef11aa393180956593 100644 (file)
@@ -73,6 +73,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, struct sk_buff *skb)
 
        if ((flow->key.eth.type == htons(ETH_P_IP) ||
             flow->key.eth.type == htons(ETH_P_IPV6)) &&
+           flow->key.ip.frag != OVS_FRAG_TYPE_LATER &&
            flow->key.ip.proto == IPPROTO_TCP &&
            likely(skb->len >= skb_transport_offset(skb) + sizeof(struct tcphdr))) {
                tcp_flags = TCP_FLAGS_BE16(tcp_hdr(skb));
@@ -91,7 +92,7 @@ static void stats_read(struct flow_stats *stats,
                       unsigned long *used, __be16 *tcp_flags)
 {
        spin_lock(&stats->lock);
-       if (time_after(stats->used, *used))
+       if (!*used || time_after(stats->used, *used))
                *used = stats->used;
        *tcp_flags |= stats->tcp_flags;
        ovs_stats->n_packets += stats->packet_count;
@@ -102,30 +103,24 @@ static void stats_read(struct flow_stats *stats,
 void ovs_flow_stats_get(struct sw_flow *flow, struct ovs_flow_stats *ovs_stats,
                        unsigned long *used, __be16 *tcp_flags)
 {
-       int cpu, cur_cpu;
+       int cpu;
 
        *used = 0;
        *tcp_flags = 0;
        memset(ovs_stats, 0, sizeof(*ovs_stats));
 
+       local_bh_disable();
        if (!flow->stats.is_percpu) {
                stats_read(flow->stats.stat, ovs_stats, used, tcp_flags);
        } else {
-               cur_cpu = get_cpu();
                for_each_possible_cpu(cpu) {
                        struct flow_stats *stats;
 
-                       if (cpu == cur_cpu)
-                               local_bh_disable();
-
                        stats = per_cpu_ptr(flow->stats.cpu_stats, cpu);
                        stats_read(stats, ovs_stats, used, tcp_flags);
-
-                       if (cpu == cur_cpu)
-                               local_bh_enable();
                }
-               put_cpu();
        }
+       local_bh_enable();
 }
 
 static void stats_reset(struct flow_stats *stats)
@@ -140,25 +135,17 @@ static void stats_reset(struct flow_stats *stats)
 
 void ovs_flow_stats_clear(struct sw_flow *flow)
 {
-       int cpu, cur_cpu;
+       int cpu;
 
+       local_bh_disable();
        if (!flow->stats.is_percpu) {
                stats_reset(flow->stats.stat);
        } else {
-               cur_cpu = get_cpu();
-
                for_each_possible_cpu(cpu) {
-
-                       if (cpu == cur_cpu)
-                               local_bh_disable();
-
                        stats_reset(per_cpu_ptr(flow->stats.cpu_stats, cpu));
-
-                       if (cpu == cur_cpu)
-                               local_bh_enable();
                }
-               put_cpu();
        }
+       local_bh_enable();
 }
 
 static int check_header(struct sk_buff *skb, int len)
index c58a0fe3c8892d4e09eb7377b60a06ae469efb09..3c268b3d71c34baa0a8c70888823b37da454fffd 100644 (file)
@@ -153,29 +153,29 @@ static void rcu_free_flow_callback(struct rcu_head *rcu)
        flow_free(flow);
 }
 
-static void flow_mask_del_ref(struct sw_flow_mask *mask, bool deferred)
-{
-       if (!mask)
-               return;
-
-       BUG_ON(!mask->ref_count);
-       mask->ref_count--;
-
-       if (!mask->ref_count) {
-               list_del_rcu(&mask->list);
-               if (deferred)
-                       kfree_rcu(mask, rcu);
-               else
-                       kfree(mask);
-       }
-}
-
 void ovs_flow_free(struct sw_flow *flow, bool deferred)
 {
        if (!flow)
                return;
 
-       flow_mask_del_ref(flow->mask, deferred);
+       if (flow->mask) {
+               struct sw_flow_mask *mask = flow->mask;
+
+               /* ovs-lock is required to protect mask-refcount and
+                * mask list.
+                */
+               ASSERT_OVSL();
+               BUG_ON(!mask->ref_count);
+               mask->ref_count--;
+
+               if (!mask->ref_count) {
+                       list_del_rcu(&mask->list);
+                       if (deferred)
+                               kfree_rcu(mask, rcu);
+                       else
+                               kfree(mask);
+               }
+       }
 
        if (deferred)
                call_rcu(&flow->rcu, rcu_free_flow_callback);
@@ -188,26 +188,9 @@ static void free_buckets(struct flex_array *buckets)
        flex_array_free(buckets);
 }
 
+
 static void __table_instance_destroy(struct table_instance *ti)
 {
-       int i;
-
-       if (ti->keep_flows)
-               goto skip_flows;
-
-       for (i = 0; i < ti->n_buckets; i++) {
-               struct sw_flow *flow;
-               struct hlist_head *head = flex_array_get(ti->buckets, i);
-               struct hlist_node *n;
-               int ver = ti->node_ver;
-
-               hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
-                       hlist_del(&flow->hash_node[ver]);
-                       ovs_flow_free(flow, false);
-               }
-       }
-
-skip_flows:
        free_buckets(ti->buckets);
        kfree(ti);
 }
@@ -258,20 +241,38 @@ static void flow_tbl_destroy_rcu_cb(struct rcu_head *rcu)
 
 static void table_instance_destroy(struct table_instance *ti, bool deferred)
 {
+       int i;
+
        if (!ti)
                return;
 
+       if (ti->keep_flows)
+               goto skip_flows;
+
+       for (i = 0; i < ti->n_buckets; i++) {
+               struct sw_flow *flow;
+               struct hlist_head *head = flex_array_get(ti->buckets, i);
+               struct hlist_node *n;
+               int ver = ti->node_ver;
+
+               hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
+                       hlist_del_rcu(&flow->hash_node[ver]);
+                       ovs_flow_free(flow, deferred);
+               }
+       }
+
+skip_flows:
        if (deferred)
                call_rcu(&ti->rcu, flow_tbl_destroy_rcu_cb);
        else
                __table_instance_destroy(ti);
 }
 
-void ovs_flow_tbl_destroy(struct flow_table *table)
+void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred)
 {
        struct table_instance *ti = ovsl_dereference(table->ti);
 
-       table_instance_destroy(ti, false);
+       table_instance_destroy(ti, deferred);
 }
 
 struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *ti,
@@ -504,16 +505,11 @@ static struct sw_flow_mask *mask_alloc(void)
 
        mask = kmalloc(sizeof(*mask), GFP_KERNEL);
        if (mask)
-               mask->ref_count = 0;
+               mask->ref_count = 1;
 
        return mask;
 }
 
-static void mask_add_ref(struct sw_flow_mask *mask)
-{
-       mask->ref_count++;
-}
-
 static bool mask_equal(const struct sw_flow_mask *a,
                       const struct sw_flow_mask *b)
 {
@@ -554,9 +550,11 @@ static int flow_mask_insert(struct flow_table *tbl, struct sw_flow *flow,
                mask->key = new->key;
                mask->range = new->range;
                list_add_rcu(&mask->list, &tbl->mask_list);
+       } else {
+               BUG_ON(!mask->ref_count);
+               mask->ref_count++;
        }
 
-       mask_add_ref(mask);
        flow->mask = mask;
        return 0;
 }
index 1996e34c0fd85b1a9f88c3e328fe191146be5b51..baaeb101924d81a4beb373be93e07287ed9be020 100644 (file)
@@ -60,7 +60,7 @@ void ovs_flow_free(struct sw_flow *, bool deferred);
 
 int ovs_flow_tbl_init(struct flow_table *);
 int ovs_flow_tbl_count(struct flow_table *table);
-void ovs_flow_tbl_destroy(struct flow_table *table);
+void ovs_flow_tbl_destroy(struct flow_table *table, bool deferred);
 int ovs_flow_tbl_flush(struct flow_table *flow_table);
 
 int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
index 208dd9a26dd16d003a0f49d4288f8704cbe15c8e..42c0f4a0b78c4c3033ab77d12c376590c228459d 100644 (file)
@@ -121,7 +121,6 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
 {
        struct vport *vport;
        size_t alloc_size;
-       int i;
 
        alloc_size = sizeof(struct vport);
        if (priv_size) {
@@ -139,19 +138,12 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
        vport->ops = ops;
        INIT_HLIST_NODE(&vport->dp_hash_node);
 
-       vport->percpu_stats = alloc_percpu(struct pcpu_sw_netstats);
+       vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
        if (!vport->percpu_stats) {
                kfree(vport);
                return ERR_PTR(-ENOMEM);
        }
 
-       for_each_possible_cpu(i) {
-               struct pcpu_sw_netstats *vport_stats;
-               vport_stats = per_cpu_ptr(vport->percpu_stats, i);
-               u64_stats_init(&vport_stats->syncp);
-       }
-
-
        spin_lock_init(&vport->stats_lock);
 
        return vport;
@@ -285,9 +277,9 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
                percpu_stats = per_cpu_ptr(vport->percpu_stats, i);
 
                do {
-                       start = u64_stats_fetch_begin_bh(&percpu_stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&percpu_stats->syncp);
                        local_stats = *percpu_stats;
-               } while (u64_stats_fetch_retry_bh(&percpu_stats->syncp, start));
+               } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start));
 
                stats->rx_bytes         += local_stats.rx_bytes;
                stats->rx_packets       += local_stats.rx_packets;
index 6a2bb37506c567c1f03de74bf51eb8aa357e318e..01039d2b16955ad459c4e14362b940ef794beed1 100644 (file)
@@ -243,40 +243,40 @@ static int packet_direct_xmit(struct sk_buff *skb)
        const struct net_device_ops *ops = dev->netdev_ops;
        netdev_features_t features;
        struct netdev_queue *txq;
+       int ret = NETDEV_TX_BUSY;
        u16 queue_map;
-       int ret;
 
        if (unlikely(!netif_running(dev) ||
-                    !netif_carrier_ok(dev))) {
-               kfree_skb(skb);
-               return NET_XMIT_DROP;
-       }
+                    !netif_carrier_ok(dev)))
+               goto drop;
 
        features = netif_skb_features(skb);
        if (skb_needs_linearize(skb, features) &&
-           __skb_linearize(skb)) {
-               kfree_skb(skb);
-               return NET_XMIT_DROP;
-       }
+           __skb_linearize(skb))
+               goto drop;
 
        queue_map = skb_get_queue_mapping(skb);
        txq = netdev_get_tx_queue(dev, queue_map);
 
-       __netif_tx_lock_bh(txq);
-       if (unlikely(netif_xmit_frozen_or_stopped(txq))) {
-               ret = NETDEV_TX_BUSY;
-               kfree_skb(skb);
-               goto out;
+       local_bh_disable();
+
+       HARD_TX_LOCK(dev, txq, smp_processor_id());
+       if (!netif_xmit_frozen_or_stopped(txq)) {
+               ret = ops->ndo_start_xmit(skb, dev);
+               if (ret == NETDEV_TX_OK)
+                       txq_trans_update(txq);
        }
+       HARD_TX_UNLOCK(dev, txq);
 
-       ret = ops->ndo_start_xmit(skb, dev);
-       if (likely(dev_xmit_complete(ret)))
-               txq_trans_update(txq);
-       else
+       local_bh_enable();
+
+       if (!dev_xmit_complete(ret))
                kfree_skb(skb);
-out:
-       __netif_tx_unlock_bh(txq);
+
        return ret;
+drop:
+       kfree_skb(skb);
+       return NET_XMIT_DROP;
 }
 
 static struct net_device *packet_cached_dev_get(struct packet_sock *po)
@@ -308,11 +308,27 @@ static bool packet_use_direct_xmit(const struct packet_sock *po)
        return po->xmit == packet_direct_xmit;
 }
 
-static u16 packet_pick_tx_queue(struct net_device *dev)
+static u16 __packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
 {
        return (u16) raw_smp_processor_id() % dev->real_num_tx_queues;
 }
 
+static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+       u16 queue_index;
+
+       if (ops->ndo_select_queue) {
+               queue_index = ops->ndo_select_queue(dev, skb, NULL,
+                                                   __packet_pick_tx_queue);
+               queue_index = netdev_cap_txqueue(dev, queue_index);
+       } else {
+               queue_index = __packet_pick_tx_queue(dev, skb);
+       }
+
+       skb_set_queue_mapping(skb, queue_index);
+}
+
 /* register_prot_hook must be invoked with the po->bind_lock held,
  * or from a context in which asynchronous accesses to the packet
  * socket is not possible (packet_create()).
@@ -1261,7 +1277,7 @@ static unsigned int fanout_demux_hash(struct packet_fanout *f,
                                      struct sk_buff *skb,
                                      unsigned int num)
 {
-       return reciprocal_scale(skb->rxhash, num);
+       return reciprocal_scale(skb_get_hash(skb), num);
 }
 
 static unsigned int fanout_demux_lb(struct packet_fanout *f,
@@ -1346,7 +1362,6 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev,
                        if (!skb)
                                return 0;
                }
-               skb_get_hash(skb);
                idx = fanout_demux_hash(f, skb, num);
                break;
        case PACKET_FANOUT_LB:
@@ -2241,8 +2256,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        if (unlikely(!(dev->flags & IFF_UP)))
                goto out_put;
 
-       reserve = dev->hard_header_len;
-
+       reserve = dev->hard_header_len + VLAN_HLEN;
        size_max = po->tx_ring.frame_size
                - (po->tp_hdrlen - sizeof(struct sockaddr_ll));
 
@@ -2269,8 +2283,19 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                        goto out_status;
 
                tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
-                               addr, hlen);
+                                         addr, hlen);
+               if (tp_len > dev->mtu + dev->hard_header_len) {
+                       struct ethhdr *ehdr;
+                       /* Earlier code assumed this would be a VLAN pkt,
+                        * double-check this now that we have the actual
+                        * packet in hand.
+                        */
 
+                       skb_reset_mac_header(skb);
+                       ehdr = eth_hdr(skb);
+                       if (ehdr->h_proto != htons(ETH_P_8021Q))
+                               tp_len = -EMSGSIZE;
+               }
                if (unlikely(tp_len < 0)) {
                        if (po->tp_loss) {
                                __packet_set_status(po, ph,
@@ -2285,7 +2310,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                        }
                }
 
-               skb_set_queue_mapping(skb, packet_pick_tx_queue(dev));
+               packet_pick_tx_queue(dev, skb);
+
                skb->destructor = tpacket_destruct_skb;
                __packet_set_status(po, ph, TP_STATUS_SENDING);
                packet_inc_pending(&po->tx_ring);
@@ -2499,7 +2525,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        skb->dev = dev;
        skb->priority = sk->sk_priority;
        skb->mark = sk->sk_mark;
-       skb_set_queue_mapping(skb, packet_pick_tx_queue(dev));
+
+       packet_pick_tx_queue(dev, skb);
 
        if (po->has_vnet_hdr) {
                if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
@@ -3786,7 +3813,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
                 */
                        if (!tx_ring)
                                init_prb_bdqc(po, rb, pg_vec, req_u, tx_ring);
-                               break;
+                       break;
                default:
                        break;
                }
index d1c3429b69eddd49face1e8cc4967ad8afa07c7c..ec126f91276b349c7fe8e181ad4ce7aec24f0c67 100644 (file)
@@ -20,9 +20,8 @@ af-rxrpc-y := \
        ar-skbuff.o \
        ar-transport.o
 
-ifeq ($(CONFIG_PROC_FS),y)
-af-rxrpc-y += ar-proc.o
-endif
+af-rxrpc-$(CONFIG_PROC_FS) += ar-proc.o
+af-rxrpc-$(CONFIG_SYSCTL) += sysctl.o
 
 obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o
 
index e61aa6001c65fb5c7521b02cb693a409f62fe1fe..7b1670489638e565c7ccea71961f8532986c94cb 100644 (file)
@@ -838,6 +838,12 @@ static int __init af_rxrpc_init(void)
                goto error_key_type_s;
        }
 
+       ret = rxrpc_sysctl_init();
+       if (ret < 0) {
+               printk(KERN_CRIT "RxRPC: Cannot register sysctls\n");
+               goto error_sysctls;
+       }
+
 #ifdef CONFIG_PROC_FS
        proc_create("rxrpc_calls", 0, init_net.proc_net, &rxrpc_call_seq_fops);
        proc_create("rxrpc_conns", 0, init_net.proc_net,
@@ -845,6 +851,8 @@ static int __init af_rxrpc_init(void)
 #endif
        return 0;
 
+error_sysctls:
+       unregister_key_type(&key_type_rxrpc_s);
 error_key_type_s:
        unregister_key_type(&key_type_rxrpc);
 error_key_type:
@@ -865,6 +873,7 @@ error_call_jar:
 static void __exit af_rxrpc_exit(void)
 {
        _enter("");
+       rxrpc_sysctl_exit();
        unregister_key_type(&key_type_rxrpc_s);
        unregister_key_type(&key_type_rxrpc);
        sock_unregister(PF_RXRPC);
index cd97a0ce48d80f73efbf2476e272f737c787bad9..c6be17a959a6e4981ecfff38af85805df6d8b26e 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-static unsigned int rxrpc_ack_defer = 1;
+/*
+ * How long to wait before scheduling ACK generation after seeing a
+ * packet with RXRPC_REQUEST_ACK set (in jiffies).
+ */
+unsigned rxrpc_requested_ack_delay = 1;
+
+/*
+ * How long to wait before scheduling an ACK with subtype DELAY (in jiffies).
+ *
+ * We use this when we've received new data packets.  If those packets aren't
+ * all consumed within this time we will send a DELAY ACK if an ACK was not
+ * requested to let the sender know it doesn't need to resend.
+ */
+unsigned rxrpc_soft_ack_delay = 1 * HZ;
+
+/*
+ * How long to wait before scheduling an ACK with subtype IDLE (in jiffies).
+ *
+ * We use this when we've consumed some previously soft-ACK'd packets when
+ * further packets aren't immediately received to decide when to send an IDLE
+ * ACK let the other end know that it can free up its Tx buffer space.
+ */
+unsigned rxrpc_idle_ack_delay = 0.5 * HZ;
+
+/*
+ * Receive window size in packets.  This indicates the maximum number of
+ * unconsumed received packets we're willing to retain in memory.  Once this
+ * limit is hit, we should generate an EXCEEDS_WINDOW ACK and discard further
+ * packets.
+ */
+unsigned rxrpc_rx_window_size = 32;
+
+/*
+ * Maximum Rx MTU size.  This indicates to the sender the size of jumbo packet
+ * made by gluing normal packets together that we're willing to handle.
+ */
+unsigned rxrpc_rx_mtu = 5692;
+
+/*
+ * The maximum number of fragments in a received jumbo packet that we tell the
+ * sender that we're willing to handle.
+ */
+unsigned rxrpc_rx_jumbo_max = 4;
 
 static const char *rxrpc_acks(u8 reason)
 {
@@ -82,24 +124,23 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
        switch (ack_reason) {
        case RXRPC_ACK_DELAY:
                _debug("run delay timer");
-               call->ack_timer.expires = jiffies + rxrpc_ack_timeout * HZ;
-               add_timer(&call->ack_timer);
-               return;
+               expiry = rxrpc_soft_ack_delay;
+               goto run_timer;
 
        case RXRPC_ACK_IDLE:
                if (!immediate) {
                        _debug("run defer timer");
-                       expiry = 1;
+                       expiry = rxrpc_idle_ack_delay;
                        goto run_timer;
                }
                goto cancel_timer;
 
        case RXRPC_ACK_REQUESTED:
-               if (!rxrpc_ack_defer)
+               expiry = rxrpc_requested_ack_delay;
+               if (!expiry)
                        goto cancel_timer;
                if (!immediate || serial == cpu_to_be32(1)) {
                        _debug("run defer timer");
-                       expiry = rxrpc_ack_defer;
                        goto run_timer;
                }
 
@@ -1174,11 +1215,11 @@ send_ACK:
        mtu = call->conn->trans->peer->if_mtu;
        mtu -= call->conn->trans->peer->hdrsize;
        ackinfo.maxMTU  = htonl(mtu);
-       ackinfo.rwind   = htonl(32);
+       ackinfo.rwind   = htonl(rxrpc_rx_window_size);
 
        /* permit the peer to send us jumbo packets if it wants to */
-       ackinfo.rxMTU   = htonl(5692);
-       ackinfo.jumbo_max = htonl(4);
+       ackinfo.rxMTU   = htonl(rxrpc_rx_mtu);
+       ackinfo.jumbo_max = htonl(rxrpc_rx_jumbo_max);
 
        hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
        _proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
index a3bbb360a3f96e0ee4aa6aac2e7eea830305b564..a9e05db0f5d5900e93f87a8567e7533a1745c82a 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/circ_buf.h>
+#include <linux/hashtable.h>
+#include <linux/spinlock_types.h>
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Maximum lifetime of a call (in jiffies).
+ */
+unsigned rxrpc_max_call_lifetime = 60 * HZ;
+
+/*
+ * Time till dead call expires after last use (in jiffies).
+ */
+unsigned rxrpc_dead_call_expiry = 2 * HZ;
+
 const char *const rxrpc_call_states[] = {
        [RXRPC_CALL_CLIENT_SEND_REQUEST]        = "ClSndReq",
        [RXRPC_CALL_CLIENT_AWAIT_REPLY]         = "ClAwtRpl",
@@ -38,8 +50,6 @@ const char *const rxrpc_call_states[] = {
 struct kmem_cache *rxrpc_call_jar;
 LIST_HEAD(rxrpc_calls);
 DEFINE_RWLOCK(rxrpc_call_lock);
-static unsigned int rxrpc_call_max_lifetime = 60;
-static unsigned int rxrpc_dead_call_timeout = 2;
 
 static void rxrpc_destroy_call(struct work_struct *work);
 static void rxrpc_call_life_expired(unsigned long _call);
@@ -47,6 +57,145 @@ static void rxrpc_dead_call_expired(unsigned long _call);
 static void rxrpc_ack_time_expired(unsigned long _call);
 static void rxrpc_resend_time_expired(unsigned long _call);
 
+static DEFINE_SPINLOCK(rxrpc_call_hash_lock);
+static DEFINE_HASHTABLE(rxrpc_call_hash, 10);
+
+/*
+ * Hash function for rxrpc_call_hash
+ */
+static unsigned long rxrpc_call_hashfunc(
+       u8              clientflag,
+       __be32          cid,
+       __be32          call_id,
+       __be32          epoch,
+       __be16          service_id,
+       sa_family_t     proto,
+       void            *localptr,
+       unsigned int    addr_size,
+       const u8        *peer_addr)
+{
+       const u16 *p;
+       unsigned int i;
+       unsigned long key;
+       u32 hcid = ntohl(cid);
+
+       _enter("");
+
+       key = (unsigned long)localptr;
+       /* We just want to add up the __be32 values, so forcing the
+        * cast should be okay.
+        */
+       key += (__force u32)epoch;
+       key += (__force u16)service_id;
+       key += (__force u32)call_id;
+       key += (hcid & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT;
+       key += hcid & RXRPC_CHANNELMASK;
+       key += clientflag;
+       key += proto;
+       /* Step through the peer address in 16-bit portions for speed */
+       for (i = 0, p = (const u16 *)peer_addr; i < addr_size >> 1; i++, p++)
+               key += *p;
+       _leave(" key = 0x%lx", key);
+       return key;
+}
+
+/*
+ * Add a call to the hashtable
+ */
+static void rxrpc_call_hash_add(struct rxrpc_call *call)
+{
+       unsigned long key;
+       unsigned int addr_size = 0;
+
+       _enter("");
+       switch (call->proto) {
+       case AF_INET:
+               addr_size = sizeof(call->peer_ip.ipv4_addr);
+               break;
+       case AF_INET6:
+               addr_size = sizeof(call->peer_ip.ipv6_addr);
+               break;
+       default:
+               break;
+       }
+       key = rxrpc_call_hashfunc(call->in_clientflag, call->cid,
+                                 call->call_id, call->epoch,
+                                 call->service_id, call->proto,
+                                 call->conn->trans->local, addr_size,
+                                 call->peer_ip.ipv6_addr);
+       /* Store the full key in the call */
+       call->hash_key = key;
+       spin_lock(&rxrpc_call_hash_lock);
+       hash_add_rcu(rxrpc_call_hash, &call->hash_node, key);
+       spin_unlock(&rxrpc_call_hash_lock);
+       _leave("");
+}
+
+/*
+ * Remove a call from the hashtable
+ */
+static void rxrpc_call_hash_del(struct rxrpc_call *call)
+{
+       _enter("");
+       spin_lock(&rxrpc_call_hash_lock);
+       hash_del_rcu(&call->hash_node);
+       spin_unlock(&rxrpc_call_hash_lock);
+       _leave("");
+}
+
+/*
+ * Find a call in the hashtable and return it, or NULL if it
+ * isn't there.
+ */
+struct rxrpc_call *rxrpc_find_call_hash(
+       u8              clientflag,
+       __be32          cid,
+       __be32          call_id,
+       __be32          epoch,
+       __be16          service_id,
+       void            *localptr,
+       sa_family_t     proto,
+       const u8        *peer_addr)
+{
+       unsigned long key;
+       unsigned int addr_size = 0;
+       struct rxrpc_call *call = NULL;
+       struct rxrpc_call *ret = NULL;
+
+       _enter("");
+       switch (proto) {
+       case AF_INET:
+               addr_size = sizeof(call->peer_ip.ipv4_addr);
+               break;
+       case AF_INET6:
+               addr_size = sizeof(call->peer_ip.ipv6_addr);
+               break;
+       default:
+               break;
+       }
+
+       key = rxrpc_call_hashfunc(clientflag, cid, call_id, epoch,
+                                 service_id, proto, localptr, addr_size,
+                                 peer_addr);
+       hash_for_each_possible_rcu(rxrpc_call_hash, call, hash_node, key) {
+               if (call->hash_key == key &&
+                   call->call_id == call_id &&
+                   call->cid == cid &&
+                   call->in_clientflag == clientflag &&
+                   call->service_id == service_id &&
+                   call->proto == proto &&
+                   call->local == localptr &&
+                   memcmp(call->peer_ip.ipv6_addr, peer_addr,
+                             addr_size) == 0 &&
+                   call->epoch == epoch) {
+                       ret = call;
+                       break;
+               }
+       }
+       _leave(" = %p", ret);
+       return ret;
+}
+
 /*
  * allocate a new call
  */
@@ -91,7 +240,7 @@ static struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp)
        call->rx_data_expect = 1;
        call->rx_data_eaten = 0;
        call->rx_first_oos = 0;
-       call->ackr_win_top = call->rx_data_eaten + 1 + RXRPC_MAXACKS;
+       call->ackr_win_top = call->rx_data_eaten + 1 + rxrpc_rx_window_size;
        call->creation_jif = jiffies;
        return call;
 }
@@ -128,11 +277,31 @@ static struct rxrpc_call *rxrpc_alloc_client_call(
                return ERR_PTR(ret);
        }
 
+       /* Record copies of information for hashtable lookup */
+       call->proto = rx->proto;
+       call->local = trans->local;
+       switch (call->proto) {
+       case AF_INET:
+               call->peer_ip.ipv4_addr =
+                       trans->peer->srx.transport.sin.sin_addr.s_addr;
+               break;
+       case AF_INET6:
+               memcpy(call->peer_ip.ipv6_addr,
+                      trans->peer->srx.transport.sin6.sin6_addr.in6_u.u6_addr8,
+                      sizeof(call->peer_ip.ipv6_addr));
+               break;
+       }
+       call->epoch = call->conn->epoch;
+       call->service_id = call->conn->service_id;
+       call->in_clientflag = call->conn->in_clientflag;
+       /* Add the new call to the hashtable */
+       rxrpc_call_hash_add(call);
+
        spin_lock(&call->conn->trans->peer->lock);
        list_add(&call->error_link, &call->conn->trans->peer->error_targets);
        spin_unlock(&call->conn->trans->peer->lock);
 
-       call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ;
+       call->lifetimer.expires = jiffies + rxrpc_max_call_lifetime;
        add_timer(&call->lifetimer);
 
        _leave(" = %p", call);
@@ -320,9 +489,12 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
                parent = *p;
                call = rb_entry(parent, struct rxrpc_call, conn_node);
 
-               if (call_id < call->call_id)
+               /* The tree is sorted in order of the __be32 value without
+                * turning it into host order.
+                */
+               if ((__force u32)call_id < (__force u32)call->call_id)
                        p = &(*p)->rb_left;
-               else if (call_id > call->call_id)
+               else if ((__force u32)call_id > (__force u32)call->call_id)
                        p = &(*p)->rb_right;
                else
                        goto old_call;
@@ -347,9 +519,31 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,
        list_add_tail(&call->link, &rxrpc_calls);
        write_unlock_bh(&rxrpc_call_lock);
 
+       /* Record copies of information for hashtable lookup */
+       call->proto = rx->proto;
+       call->local = conn->trans->local;
+       switch (call->proto) {
+       case AF_INET:
+               call->peer_ip.ipv4_addr =
+                       conn->trans->peer->srx.transport.sin.sin_addr.s_addr;
+               break;
+       case AF_INET6:
+               memcpy(call->peer_ip.ipv6_addr,
+                      conn->trans->peer->srx.transport.sin6.sin6_addr.in6_u.u6_addr8,
+                      sizeof(call->peer_ip.ipv6_addr));
+               break;
+       default:
+               break;
+       }
+       call->epoch = conn->epoch;
+       call->service_id = conn->service_id;
+       call->in_clientflag = conn->in_clientflag;
+       /* Add the new call to the hashtable */
+       rxrpc_call_hash_add(call);
+
        _net("CALL incoming %d on CONN %d", call->debug_id, call->conn->debug_id);
 
-       call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ;
+       call->lifetimer.expires = jiffies + rxrpc_max_call_lifetime;
        add_timer(&call->lifetimer);
        _leave(" = %p {%d} [new]", call, call->debug_id);
        return call;
@@ -533,7 +727,7 @@ void rxrpc_release_call(struct rxrpc_call *call)
        del_timer_sync(&call->resend_timer);
        del_timer_sync(&call->ack_timer);
        del_timer_sync(&call->lifetimer);
-       call->deadspan.expires = jiffies + rxrpc_dead_call_timeout * HZ;
+       call->deadspan.expires = jiffies + rxrpc_dead_call_expiry;
        add_timer(&call->deadspan);
 
        _leave("");
@@ -665,6 +859,9 @@ static void rxrpc_cleanup_call(struct rxrpc_call *call)
                rxrpc_put_connection(call->conn);
        }
 
+       /* Remove the call from the hash */
+       rxrpc_call_hash_del(call);
+
        if (call->acks_window) {
                _debug("kill Tx window %d",
                       CIRC_CNT(call->acks_head, call->acks_tail,
index 7bf5b5b9e8b9400af1cbaecaeaf9a8c222670492..6631f4f1e39be713029c8b9b504db4ea741fb3e6 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Time till a connection expires after last use (in seconds).
+ */
+unsigned rxrpc_connection_expiry = 10 * 60;
+
 static void rxrpc_connection_reaper(struct work_struct *work);
 
 LIST_HEAD(rxrpc_connections);
 DEFINE_RWLOCK(rxrpc_connection_lock);
-static unsigned long rxrpc_connection_timeout = 10 * 60;
 static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);
 
 /*
@@ -862,7 +866,7 @@ static void rxrpc_connection_reaper(struct work_struct *work)
 
                spin_lock(&conn->trans->client_lock);
                write_lock(&conn->trans->conn_lock);
-               reap_time = conn->put_time + rxrpc_connection_timeout;
+               reap_time = conn->put_time + rxrpc_connection_expiry;
 
                if (atomic_read(&conn->usage) > 0) {
                        ;
@@ -916,7 +920,7 @@ void __exit rxrpc_destroy_all_connections(void)
 {
        _enter("");
 
-       rxrpc_connection_timeout = 0;
+       rxrpc_connection_expiry = 0;
        cancel_delayed_work(&rxrpc_connection_reap);
        rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
 
index a9206087b4d7a87ced5cef6c77b69fc2bb86a11c..db57458c824c87b463ceff200be22c07df936b73 100644 (file)
@@ -83,6 +83,7 @@ void rxrpc_UDP_error_report(struct sock *sk)
 
                if (mtu == 0) {
                        /* they didn't give us a size, estimate one */
+                       mtu = peer->if_mtu;
                        if (mtu > 1500) {
                                mtu >>= 1;
                                if (mtu < 1500)
index 529572f18d1fa56b71a3154c9d822445fffef358..73742647c1354ebc76cdc44289fcc5948ca188ac 100644 (file)
@@ -25,8 +25,6 @@
 #include <net/net_namespace.h>
 #include "ar-internal.h"
 
-unsigned long rxrpc_ack_timeout = 1;
-
 const char *rxrpc_pkts[] = {
        "?00",
        "DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG",
@@ -349,8 +347,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)
         * it */
        if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
                _proto("ACK Requested on %%%u", serial);
-               rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial,
-                                 !(sp->hdr.flags & RXRPC_MORE_PACKETS));
+               rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, false);
        }
 
        switch (sp->hdr.type) {
@@ -526,36 +523,38 @@ protocol_error:
  * post an incoming packet to the appropriate call/socket to deal with
  * - must get rid of the sk_buff, either by freeing it or by queuing it
  */
-static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
+static void rxrpc_post_packet_to_call(struct rxrpc_call *call,
                                      struct sk_buff *skb)
 {
        struct rxrpc_skb_priv *sp;
-       struct rxrpc_call *call;
-       struct rb_node *p;
-       __be32 call_id;
-
-       _enter("%p,%p", conn, skb);
 
-       read_lock_bh(&conn->lock);
+       _enter("%p,%p", call, skb);
 
        sp = rxrpc_skb(skb);
 
-       /* look at extant calls by channel number first */
-       call = conn->channels[ntohl(sp->hdr.cid) & RXRPC_CHANNELMASK];
-       if (!call || call->call_id != sp->hdr.callNumber)
-               goto call_not_extant;
-
        _debug("extant call [%d]", call->state);
-       ASSERTCMP(call->conn, ==, conn);
 
        read_lock(&call->state_lock);
        switch (call->state) {
        case RXRPC_CALL_LOCALLY_ABORTED:
-               if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events))
+               if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) {
                        rxrpc_queue_call(call);
+                       goto free_unlock;
+               }
        case RXRPC_CALL_REMOTELY_ABORTED:
        case RXRPC_CALL_NETWORK_ERROR:
        case RXRPC_CALL_DEAD:
+               goto dead_call;
+       case RXRPC_CALL_COMPLETE:
+       case RXRPC_CALL_CLIENT_FINAL_ACK:
+               /* complete server call */
+               if (call->conn->in_clientflag)
+                       goto dead_call;
+               /* resend last packet of a completed call */
+               _debug("final ack again");
+               rxrpc_get_call(call);
+               set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
+               rxrpc_queue_call(call);
                goto free_unlock;
        default:
                break;
@@ -563,7 +562,6 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
 
        read_unlock(&call->state_lock);
        rxrpc_get_call(call);
-       read_unlock_bh(&conn->lock);
 
        if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
            sp->hdr.flags & RXRPC_JUMBO_PACKET)
@@ -574,78 +572,16 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,
        rxrpc_put_call(call);
        goto done;
 
-call_not_extant:
-       /* search the completed calls in case what we're dealing with is
-        * there */
-       _debug("call not extant");
-
-       call_id = sp->hdr.callNumber;
-       p = conn->calls.rb_node;
-       while (p) {
-               call = rb_entry(p, struct rxrpc_call, conn_node);
-
-               if (call_id < call->call_id)
-                       p = p->rb_left;
-               else if (call_id > call->call_id)
-                       p = p->rb_right;
-               else
-                       goto found_completed_call;
-       }
-
 dead_call:
-       /* it's a either a really old call that we no longer remember or its a
-        * new incoming call */
-       read_unlock_bh(&conn->lock);
-
-       if (sp->hdr.flags & RXRPC_CLIENT_INITIATED &&
-           sp->hdr.seq == cpu_to_be32(1)) {
-               _debug("incoming call");
-               skb_queue_tail(&conn->trans->local->accept_queue, skb);
-               rxrpc_queue_work(&conn->trans->local->acceptor);
-               goto done;
-       }
-
-       _debug("dead call");
-       skb->priority = RX_CALL_DEAD;
-       rxrpc_reject_packet(conn->trans->local, skb);
-       goto done;
-
-       /* resend last packet of a completed call
-        * - client calls may have been aborted or ACK'd
-        * - server calls may have been aborted
-        */
-found_completed_call:
-       _debug("completed call");
-
-       if (atomic_read(&call->usage) == 0)
-               goto dead_call;
-
-       /* synchronise any state changes */
-       read_lock(&call->state_lock);
-       ASSERTIFCMP(call->state != RXRPC_CALL_CLIENT_FINAL_ACK,
-                   call->state, >=, RXRPC_CALL_COMPLETE);
-
-       if (call->state == RXRPC_CALL_LOCALLY_ABORTED ||
-           call->state == RXRPC_CALL_REMOTELY_ABORTED ||
-           call->state == RXRPC_CALL_DEAD) {
-               read_unlock(&call->state_lock);
-               goto dead_call;
-       }
-
-       if (call->conn->in_clientflag) {
-               read_unlock(&call->state_lock);
-               goto dead_call; /* complete server call */
+       if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) {
+               skb->priority = RX_CALL_DEAD;
+               rxrpc_reject_packet(call->conn->trans->local, skb);
+               goto unlock;
        }
-
-       _debug("final ack again");
-       rxrpc_get_call(call);
-       set_bit(RXRPC_CALL_ACK_FINAL, &call->events);
-       rxrpc_queue_call(call);
-
 free_unlock:
-       read_unlock(&call->state_lock);
-       read_unlock_bh(&conn->lock);
        rxrpc_free_skb(skb);
+unlock:
+       read_unlock(&call->state_lock);
 done:
        _leave("");
 }
@@ -664,17 +600,42 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,
        rxrpc_queue_conn(conn);
 }
 
+static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local,
+                                              struct sk_buff *skb,
+                                              struct rxrpc_skb_priv *sp)
+{
+       struct rxrpc_peer *peer;
+       struct rxrpc_transport *trans;
+       struct rxrpc_connection *conn;
+
+       peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr,
+                               udp_hdr(skb)->source);
+       if (IS_ERR(peer))
+               goto cant_find_conn;
+
+       trans = rxrpc_find_transport(local, peer);
+       rxrpc_put_peer(peer);
+       if (!trans)
+               goto cant_find_conn;
+
+       conn = rxrpc_find_connection(trans, &sp->hdr);
+       rxrpc_put_transport(trans);
+       if (!conn)
+               goto cant_find_conn;
+
+       return conn;
+cant_find_conn:
+       return NULL;
+}
+
 /*
  * handle data received on the local endpoint
  * - may be called in interrupt context
  */
 void rxrpc_data_ready(struct sock *sk, int count)
 {
-       struct rxrpc_connection *conn;
-       struct rxrpc_transport *trans;
        struct rxrpc_skb_priv *sp;
        struct rxrpc_local *local;
-       struct rxrpc_peer *peer;
        struct sk_buff *skb;
        int ret;
 
@@ -749,27 +710,34 @@ void rxrpc_data_ready(struct sock *sk, int count)
            (sp->hdr.callNumber == 0 || sp->hdr.seq == 0))
                goto bad_message;
 
-       peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, udp_hdr(skb)->source);
-       if (IS_ERR(peer))
-               goto cant_route_call;
+       if (sp->hdr.callNumber == 0) {
+               /* This is a connection-level packet. These should be
+                * fairly rare, so the extra overhead of looking them up the
+                * old-fashioned way doesn't really hurt */
+               struct rxrpc_connection *conn;
 
-       trans = rxrpc_find_transport(local, peer);
-       rxrpc_put_peer(peer);
-       if (!trans)
-               goto cant_route_call;
+               conn = rxrpc_conn_from_local(local, skb, sp);
+               if (!conn)
+                       goto cant_route_call;
 
-       conn = rxrpc_find_connection(trans, &sp->hdr);
-       rxrpc_put_transport(trans);
-       if (!conn)
-               goto cant_route_call;
-
-       _debug("CONN %p {%d}", conn, conn->debug_id);
-
-       if (sp->hdr.callNumber == 0)
+               _debug("CONN %p {%d}", conn, conn->debug_id);
                rxrpc_post_packet_to_conn(conn, skb);
-       else
-               rxrpc_post_packet_to_call(conn, skb);
-       rxrpc_put_connection(conn);
+               rxrpc_put_connection(conn);
+       } else {
+               struct rxrpc_call *call;
+               u8 in_clientflag = 0;
+
+               if (sp->hdr.flags & RXRPC_CLIENT_INITIATED)
+                       in_clientflag = RXRPC_CLIENT_INITIATED;
+               call = rxrpc_find_call_hash(in_clientflag, sp->hdr.cid,
+                                           sp->hdr.callNumber, sp->hdr.epoch,
+                                           sp->hdr.serviceId, local, AF_INET,
+                                           (u8 *)&ip_hdr(skb)->saddr);
+               if (call)
+                       rxrpc_post_packet_to_call(call, skb);
+               else
+                       goto cant_route_call;
+       }
        rxrpc_put_local(local);
        return;
 
@@ -790,8 +758,10 @@ cant_route_call:
                skb->priority = RX_CALL_DEAD;
        }
 
-       _debug("reject");
-       rxrpc_reject_packet(local, skb);
+       if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) {
+               _debug("reject type %d",sp->hdr.type);
+               rxrpc_reject_packet(local, skb);
+       }
        rxrpc_put_local(local);
        _leave(" [no call]");
        return;
index 5f43675ee1df3822ecf98e432797f9b498047b58..c831d44b0841a07233c20881a1fc516ab425041d 100644 (file)
@@ -396,9 +396,20 @@ struct rxrpc_call {
 #define RXRPC_ACKR_WINDOW_ASZ DIV_ROUND_UP(RXRPC_MAXACKS, BITS_PER_LONG)
        unsigned long           ackr_window[RXRPC_ACKR_WINDOW_ASZ + 1];
 
+       struct hlist_node       hash_node;
+       unsigned long           hash_key;       /* Full hash key */
+       u8                      in_clientflag;  /* Copy of conn->in_clientflag for hashing */
+       struct rxrpc_local      *local;         /* Local endpoint. Used for hashing. */
+       sa_family_t             proto;          /* Frame protocol */
        /* the following should all be in net order */
        __be32                  cid;            /* connection ID + channel index  */
        __be32                  call_id;        /* call ID on connection  */
+       __be32                  epoch;          /* epoch of this connection */
+       __be16                  service_id;     /* service ID */
+       union {                                 /* Peer IP address for hashing */
+               __be32  ipv4_addr;
+               __u8    ipv6_addr[16];          /* Anticipates eventual IPv6 support */
+       } peer_ip;
 };
 
 /*
@@ -433,6 +444,13 @@ int rxrpc_reject_call(struct rxrpc_sock *);
 /*
  * ar-ack.c
  */
+extern unsigned rxrpc_requested_ack_delay;
+extern unsigned rxrpc_soft_ack_delay;
+extern unsigned rxrpc_idle_ack_delay;
+extern unsigned rxrpc_rx_window_size;
+extern unsigned rxrpc_rx_mtu;
+extern unsigned rxrpc_rx_jumbo_max;
+
 void __rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool);
 void rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool);
 void rxrpc_process_call(struct work_struct *);
@@ -440,10 +458,14 @@ void rxrpc_process_call(struct work_struct *);
 /*
  * ar-call.c
  */
+extern unsigned rxrpc_max_call_lifetime;
+extern unsigned rxrpc_dead_call_expiry;
 extern struct kmem_cache *rxrpc_call_jar;
 extern struct list_head rxrpc_calls;
 extern rwlock_t rxrpc_call_lock;
 
+struct rxrpc_call *rxrpc_find_call_hash(u8,  __be32, __be32, __be32,
+                                       __be16, void *, sa_family_t, const u8 *);
 struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *,
                                         struct rxrpc_transport *,
                                         struct rxrpc_conn_bundle *,
@@ -460,6 +482,7 @@ void __exit rxrpc_destroy_all_calls(void);
 /*
  * ar-connection.c
  */
+extern unsigned rxrpc_connection_expiry;
 extern struct list_head rxrpc_connections;
 extern rwlock_t rxrpc_connection_lock;
 
@@ -493,7 +516,6 @@ void rxrpc_UDP_error_handler(struct work_struct *);
 /*
  * ar-input.c
  */
-extern unsigned long rxrpc_ack_timeout;
 extern const char *rxrpc_pkts[];
 
 void rxrpc_data_ready(struct sock *, int);
@@ -504,6 +526,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *, struct sk_buff *);
  * ar-local.c
  */
 extern rwlock_t rxrpc_local_lock;
+
 struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *);
 void rxrpc_put_local(struct rxrpc_local *);
 void __exit rxrpc_destroy_all_locals(void);
@@ -522,7 +545,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time_t,
 /*
  * ar-output.c
  */
-extern int rxrpc_resend_timeout;
+extern unsigned rxrpc_resend_timeout;
 
 int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *);
 int rxrpc_client_sendmsg(struct kiocb *, struct rxrpc_sock *,
@@ -572,6 +595,8 @@ void rxrpc_packet_destructor(struct sk_buff *);
 /*
  * ar-transport.c
  */
+extern unsigned rxrpc_transport_expiry;
+
 struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *,
                                            struct rxrpc_peer *, gfp_t);
 void rxrpc_put_transport(struct rxrpc_transport *);
@@ -579,6 +604,17 @@ void __exit rxrpc_destroy_all_transports(void);
 struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *,
                                             struct rxrpc_peer *);
 
+/*
+ * sysctl.c
+ */
+#ifdef CONFIG_SYSCTL
+extern int __init rxrpc_sysctl_init(void);
+extern void rxrpc_sysctl_exit(void);
+#else
+static inline int __init rxrpc_sysctl_init(void) { return 0; }
+static inline void rxrpc_sysctl_exit(void) {}
+#endif
+
 /*
  * debug tracing
  */
index d0e8f1c1898a092437bb035208c9c616f16a17ae..0b4b9a79f5abd0fb24e413551550aba25e7ce8e4 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
-int rxrpc_resend_timeout = 4;
+/*
+ * Time till packet resend (in jiffies).
+ */
+unsigned rxrpc_resend_timeout = 4 * HZ;
 
 static int rxrpc_send_data(struct kiocb *iocb,
                           struct rxrpc_sock *rx,
@@ -487,7 +490,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,
               ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));
 
        sp->need_resend = false;
-       sp->resend_at = jiffies + rxrpc_resend_timeout * HZ;
+       sp->resend_at = jiffies + rxrpc_resend_timeout;
        if (!test_and_set_bit(RXRPC_CALL_RUN_RTIMER, &call->flags)) {
                _debug("run timer");
                call->resend_timer.expires = sp->resend_at;
@@ -666,6 +669,7 @@ static int rxrpc_send_data(struct kiocb *iocb,
                /* add the packet to the send queue if it's now full */
                if (sp->remain <= 0 || (segment == 0 && !more)) {
                        struct rxrpc_connection *conn = call->conn;
+                       uint32_t seq;
                        size_t pad;
 
                        /* pad out if we're using security */
@@ -678,11 +682,12 @@ static int rxrpc_send_data(struct kiocb *iocb,
                                        memset(skb_put(skb, pad), 0, pad);
                        }
 
+                       seq = atomic_inc_return(&call->sequence);
+
                        sp->hdr.epoch = conn->epoch;
                        sp->hdr.cid = call->cid;
                        sp->hdr.callNumber = call->call_id;
-                       sp->hdr.seq =
-                               htonl(atomic_inc_return(&call->sequence));
+                       sp->hdr.seq = htonl(seq);
                        sp->hdr.serial =
                                htonl(atomic_inc_return(&conn->serial));
                        sp->hdr.type = RXRPC_PACKET_TYPE_DATA;
@@ -697,6 +702,8 @@ static int rxrpc_send_data(struct kiocb *iocb,
                        else if (CIRC_SPACE(call->acks_head, call->acks_tail,
                                            call->acks_winsz) > 1)
                                sp->hdr.flags |= RXRPC_MORE_PACKETS;
+                       if (more && seq & 1)
+                               sp->hdr.flags |= RXRPC_REQUEST_ACK;
 
                        ret = rxrpc_secure_packet(
                                call, skb, skb->mark,
index 34b5490dde655ccdbac5dcbbc7b0df1b88ab42ca..e9aaa65c07784cf9991f5bef279e4dab49a6912f 100644 (file)
@@ -180,16 +180,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (copy > len - copied)
                        copy = len - copied;
 
-               if (skb->ip_summed == CHECKSUM_UNNECESSARY ||
-                   skb->ip_summed == CHECKSUM_PARTIAL) {
-                       ret = skb_copy_datagram_iovec(skb, offset,
-                                                     msg->msg_iov, copy);
-               } else {
-                       ret = skb_copy_and_csum_datagram_iovec(skb, offset,
-                                                              msg->msg_iov);
-                       if (ret == -EINVAL)
-                               goto csum_copy_error;
-               }
+               ret = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copy);
 
                if (ret < 0)
                        goto copy_error;
@@ -348,20 +339,6 @@ copy_error:
        _leave(" = %d", ret);
        return ret;
 
-csum_copy_error:
-       _debug("csum error");
-       release_sock(&rx->sk);
-       if (continue_call)
-               rxrpc_put_call(continue_call);
-       rxrpc_kill_skb(skb);
-       if (!(flags & MSG_PEEK)) {
-               if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
-                       BUG();
-       }
-       skb_kill_datagram(&rx->sk, skb, flags);
-       rxrpc_put_call(call);
-       return -EAGAIN;
-
 wait_interrupted:
        ret = sock_intr_errno(timeo);
 wait_error:
index de755e04d29ce1495a0f0c9459b487da85c0b413..4cfab49e329dbba1a2cfa05c1faeff66fd016031 100644 (file)
@@ -83,9 +83,14 @@ static void rxrpc_hard_ACK_data(struct rxrpc_call *call,
                rxrpc_request_final_ACK(call);
        } else if (atomic_dec_and_test(&call->ackr_not_idle) &&
                   test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) {
+               /* We previously soft-ACK'd some received packets that have now
+                * been consumed, so send a hard-ACK if no more packets are
+                * immediately forthcoming to allow the transmitter to free up
+                * its Tx bufferage.
+                */
                _debug("send Rx idle ACK");
                __rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial,
-                                   true);
+                                   false);
        }
 
        spin_unlock_bh(&call->lock);
index 92df566930b9a05c23d109cb9e42806698cbb535..1976dec84f297cfb126df6bcd53129f1d518001b 100644 (file)
 #include <net/af_rxrpc.h>
 #include "ar-internal.h"
 
+/*
+ * Time after last use at which transport record is cleaned up.
+ */
+unsigned rxrpc_transport_expiry = 3600 * 24;
+
 static void rxrpc_transport_reaper(struct work_struct *work);
 
 static LIST_HEAD(rxrpc_transports);
 static DEFINE_RWLOCK(rxrpc_transport_lock);
-static unsigned long rxrpc_transport_timeout = 3600 * 24;
 static DECLARE_DELAYED_WORK(rxrpc_transport_reap, rxrpc_transport_reaper);
 
 /*
@@ -235,7 +239,7 @@ static void rxrpc_transport_reaper(struct work_struct *work)
                if (likely(atomic_read(&trans->usage) > 0))
                        continue;
 
-               reap_time = trans->put_time + rxrpc_transport_timeout;
+               reap_time = trans->put_time + rxrpc_transport_expiry;
                if (reap_time <= now)
                        list_move_tail(&trans->link, &graveyard);
                else if (reap_time < earliest)
@@ -271,7 +275,7 @@ void __exit rxrpc_destroy_all_transports(void)
 {
        _enter("");
 
-       rxrpc_transport_timeout = 0;
+       rxrpc_transport_expiry = 0;
        cancel_delayed_work(&rxrpc_transport_reap);
        rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0);
 
diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c
new file mode 100644 (file)
index 0000000..50a98a9
--- /dev/null
@@ -0,0 +1,146 @@
+/* sysctls for configuring RxRPC operating parameters
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/sysctl.h>
+#include <net/sock.h>
+#include <net/af_rxrpc.h>
+#include "ar-internal.h"
+
+static struct ctl_table_header *rxrpc_sysctl_reg_table;
+static const unsigned zero = 0;
+static const unsigned one = 1;
+static const unsigned four = 4;
+static const unsigned n_65535 = 65535;
+static const unsigned n_max_acks = RXRPC_MAXACKS;
+
+/*
+ * RxRPC operating parameters.
+ *
+ * See Documentation/networking/rxrpc.txt and the variable definitions for more
+ * information on the individual parameters.
+ */
+static struct ctl_table rxrpc_sysctl_table[] = {
+       /* Values measured in milliseconds */
+       {
+               .procname       = "req_ack_delay",
+               .data           = &rxrpc_requested_ack_delay,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&zero,
+       },
+       {
+               .procname       = "soft_ack_delay",
+               .data           = &rxrpc_soft_ack_delay,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "idle_ack_delay",
+               .data           = &rxrpc_idle_ack_delay,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "resend_timeout",
+               .data           = &rxrpc_resend_timeout,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_ms_jiffies,
+               .extra1         = (void *)&one,
+       },
+
+       /* Values measured in seconds but used in jiffies */
+       {
+               .procname       = "max_call_lifetime",
+               .data           = &rxrpc_max_call_lifetime,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "dead_call_expiry",
+               .data           = &rxrpc_dead_call_expiry,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_jiffies,
+               .extra1         = (void *)&one,
+       },
+
+       /* Values measured in seconds */
+       {
+               .procname       = "connection_expiry",
+               .data           = &rxrpc_connection_expiry,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+       },
+       {
+               .procname       = "transport_expiry",
+               .data           = &rxrpc_transport_expiry,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+       },
+
+       /* Non-time values */
+       {
+               .procname       = "rx_window_size",
+               .data           = &rxrpc_rx_window_size,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+               .extra2         = (void *)&n_max_acks,
+       },
+       {
+               .procname       = "rx_mtu",
+               .data           = &rxrpc_rx_mtu,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+               .extra1         = (void *)&n_65535,
+       },
+       {
+               .procname       = "rx_jumbo_max",
+               .data           = &rxrpc_rx_jumbo_max,
+               .maxlen         = sizeof(unsigned),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = (void *)&one,
+               .extra2         = (void *)&four,
+       },
+
+       { }
+};
+
+int __init rxrpc_sysctl_init(void)
+{
+       rxrpc_sysctl_reg_table = register_net_sysctl(&init_net, "net/rxrpc",
+                                                    rxrpc_sysctl_table);
+       if (!rxrpc_sysctl_reg_table)
+               return -ENOMEM;
+       return 0;
+}
+
+void rxrpc_sysctl_exit(void)
+{
+       if (rxrpc_sysctl_reg_table)
+               unregister_net_sysctl_table(rxrpc_sysctl_reg_table);
+}
index 72bdc71663458e8cc131ab392b6af7673f35207d..8a5ba5add4bcd60e59a9b2468df88812212012f4 100644 (file)
 #include <net/act_api.h>
 #include <net/netlink.h>
 
-void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
+void tcf_hash_destroy(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);
        spin_unlock_bh(&hinfo->lock);
@@ -42,18 +45,22 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
 }
 EXPORT_SYMBOL(tcf_hash_destroy);
 
-int tcf_hash_release(struct tcf_common *p, int bind,
-                    struct tcf_hashinfo *hinfo)
+int tcf_hash_release(struct tc_action *a, int bind)
 {
+       struct tcf_common *p = a->priv;
        int ret = 0;
 
        if (p) {
                if (bind)
                        p->tcfc_bindcnt--;
+               else if (p->tcfc_bindcnt > 0)
+                       return -EPERM;
 
                p->tcfc_refcnt--;
                if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
-                       tcf_hash_destroy(p, hinfo);
+                       if (a->ops->cleanup)
+                               a->ops->cleanup(a, bind);
+                       tcf_hash_destroy(a);
                        ret = 1;
                }
        }
@@ -118,6 +125,7 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
        struct tcf_common *p;
        struct nlattr *nest;
        int i = 0, n_i = 0;
+       int ret = -EINVAL;
 
        nest = nla_nest_start(skb, a->order);
        if (nest == NULL)
@@ -127,10 +135,13 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
        for (i = 0; i < (hinfo->hmask + 1); i++) {
                head = &hinfo->htab[tcf_hash(i, hinfo->hmask)];
                hlist_for_each_entry_safe(p, n, head, tcfc_head) {
-                       if (ACT_P_DELETED == tcf_hash_release(p, 0, hinfo)) {
+                       a->priv = p;
+                       ret = tcf_hash_release(a, 0);
+                       if (ret == ACT_P_DELETED) {
                                module_put(a->ops->owner);
                                n_i++;
-                       }
+                       } else if (ret < 0)
+                               goto nla_put_failure;
                }
        }
        if (nla_put_u32(skb, TCA_FCNT, n_i))
@@ -140,7 +151,7 @@ static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
        return n_i;
 nla_put_failure:
        nla_nest_cancel(skb, nest);
-       return -EINVAL;
+       return ret;
 }
 
 static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
@@ -198,7 +209,7 @@ int tcf_hash_search(struct tc_action *a, u32 index)
 }
 EXPORT_SYMBOL(tcf_hash_search);
 
-struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind)
+int tcf_hash_check(u32 index, struct tc_action *a, int bind)
 {
        struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct tcf_common *p = NULL;
@@ -207,19 +218,30 @@ struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind)
                        p->tcfc_bindcnt++;
                p->tcfc_refcnt++;
                a->priv = p;
+               return 1;
        }
-       return p;
+       return 0;
 }
 EXPORT_SYMBOL(tcf_hash_check);
 
-struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
-                                  struct tc_action *a, int size, int bind)
+void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est)
+{
+       struct tcf_common *pc = a->priv;
+       if (est)
+               gen_kill_estimator(&pc->tcfc_bstats,
+                                  &pc->tcfc_rate_est);
+       kfree_rcu(pc, tcfc_rcu);
+}
+EXPORT_SYMBOL(tcf_hash_cleanup);
+
+int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
+                   int size, int bind)
 {
        struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct tcf_common *p = kzalloc(size, GFP_KERNEL);
 
        if (unlikely(!p))
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
        p->tcfc_refcnt = 1;
        if (bind)
                p->tcfc_bindcnt = 1;
@@ -234,17 +256,19 @@ struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
                                            &p->tcfc_lock, est);
                if (err) {
                        kfree(p);
-                       return ERR_PTR(err);
+                       return err;
                }
        }
 
        a->priv = (void *) p;
-       return p;
+       return 0;
 }
 EXPORT_SYMBOL(tcf_hash_create);
 
-void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo)
+void tcf_hash_insert(struct tc_action *a)
 {
+       struct tcf_common *p = a->priv;
+       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
 
        spin_lock_bh(&hinfo->lock);
@@ -256,12 +280,13 @@ EXPORT_SYMBOL(tcf_hash_insert);
 static LIST_HEAD(act_base);
 static DEFINE_RWLOCK(act_mod_lock);
 
-int tcf_register_action(struct tc_action_ops *act)
+int tcf_register_action(struct tc_action_ops *act, unsigned int mask)
 {
        struct tc_action_ops *a;
+       int err;
 
-       /* Must supply act, dump, cleanup and init */
-       if (!act->act || !act->dump || !act->cleanup || !act->init)
+       /* Must supply act, dump and init */
+       if (!act->act || !act->dump || !act->init)
                return -EINVAL;
 
        /* Supply defaults */
@@ -270,10 +295,21 @@ int tcf_register_action(struct tc_action_ops *act)
        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;
                }
        }
@@ -292,6 +328,8 @@ int tcf_unregister_action(struct tc_action_ops *act)
        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;
                }
@@ -368,16 +406,21 @@ exec_done:
 }
 EXPORT_SYMBOL(tcf_action_exec);
 
-void tcf_action_destroy(struct list_head *actions, int bind)
+int tcf_action_destroy(struct list_head *actions, int bind)
 {
        struct tc_action *a, *tmp;
+       int ret = 0;
 
        list_for_each_entry_safe(a, tmp, actions, list) {
-               if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
+               ret = tcf_hash_release(a, bind);
+               if (ret == ACT_P_DELETED)
                        module_put(a->ops->owner);
+               else if (ret < 0)
+                       return ret;
                list_del(&a->list);
                kfree(a);
        }
+       return ret;
 }
 
 int
@@ -642,6 +685,20 @@ act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
        return rtnl_unicast(skb, net, portid);
 }
 
+static struct tc_action *create_a(int i)
+{
+       struct tc_action *act;
+
+       act = kzalloc(sizeof(*act), GFP_KERNEL);
+       if (act == NULL) {
+               pr_debug("create_a: failed to alloc!\n");
+               return NULL;
+       }
+       act->order = i;
+       INIT_LIST_HEAD(&act->list);
+       return act;
+}
+
 static struct tc_action *
 tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
 {
@@ -661,11 +718,10 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
        index = nla_get_u32(tb[TCA_ACT_INDEX]);
 
        err = -ENOMEM;
-       a = kzalloc(sizeof(struct tc_action), GFP_KERNEL);
+       a = create_a(0);
        if (a == NULL)
                goto err_out;
 
-       INIT_LIST_HEAD(&a->list);
        err = -EINVAL;
        a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
        if (a->ops == NULL) /* could happen in batch of actions */
@@ -695,20 +751,6 @@ static void cleanup_a(struct list_head *actions)
        }
 }
 
-static struct tc_action *create_a(int i)
-{
-       struct tc_action *act;
-
-       act = kzalloc(sizeof(*act), GFP_KERNEL);
-       if (act == NULL) {
-               pr_debug("create_a: failed to alloc!\n");
-               return NULL;
-       }
-       act->order = i;
-       INIT_LIST_HEAD(&act->list);
-       return act;
-}
-
 static int tca_action_flush(struct net *net, struct nlattr *nla,
                            struct nlmsghdr *n, u32 portid)
 {
@@ -720,18 +762,12 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
        struct nlattr *nest;
        struct nlattr *tb[TCA_ACT_MAX + 1];
        struct nlattr *kind;
-       struct tc_action *a = create_a(0);
+       struct tc_action a;
        int err = -ENOMEM;
 
-       if (a == NULL) {
-               pr_debug("tca_action_flush: couldnt create tc_action\n");
-               return err;
-       }
-
        skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!skb) {
                pr_debug("tca_action_flush: failed skb alloc\n");
-               kfree(a);
                return err;
        }
 
@@ -743,8 +779,10 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 
        err = -EINVAL;
        kind = tb[TCA_ACT_KIND];
-       a->ops = tc_lookup_action(kind);
-       if (a->ops == NULL) /*some idjot trying to flush unknown action */
+       memset(&a, 0, sizeof(struct tc_action));
+       INIT_LIST_HEAD(&a.list);
+       a.ops = tc_lookup_action(kind);
+       if (a.ops == NULL) /*some idjot trying to flush unknown action */
                goto err_out;
 
        nlh = nlmsg_put(skb, portid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t), 0);
@@ -759,7 +797,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(skb, &dcb, RTM_DELACTION, &a);
        if (err < 0)
                goto out_module_put;
        if (err == 0)
@@ -769,8 +807,7 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
 
        nlh->nlmsg_len = skb_tail_pointer(skb) - b;
        nlh->nlmsg_flags |= NLM_F_ROOT;
-       module_put(a->ops->owner);
-       kfree(a);
+       module_put(a.ops->owner);
        err = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
                             n->nlmsg_flags & NLM_F_ECHO);
        if (err > 0)
@@ -779,11 +816,10 @@ static int tca_action_flush(struct net *net, struct nlattr *nla,
        return err;
 
 out_module_put:
-       module_put(a->ops->owner);
+       module_put(a.ops->owner);
 err_out:
 noflush_out:
        kfree_skb(skb);
-       kfree(a);
        return err;
 }
 
@@ -805,7 +841,11 @@ tcf_del_notify(struct net *net, struct nlmsghdr *n, struct list_head *actions,
        }
 
        /* now do the delete */
-       tcf_action_destroy(actions, 0);
+       ret = tcf_action_destroy(actions, 0);
+       if (ret < 0) {
+               kfree_skb(skb);
+               return ret;
+       }
 
        ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
                             n->nlmsg_flags & NLM_F_ECHO);
index 2210187c45c2772a9f21dae081af50eeabcf6366..edbf40dac709df3e88f33948a1c77800dbe25b75 100644 (file)
@@ -37,7 +37,6 @@
 #include <net/tc_act/tc_csum.h>
 
 #define CSUM_TAB_MASK 15
-static struct tcf_hashinfo csum_hash_info;
 
 static const struct nla_policy csum_policy[TCA_CSUM_MAX + 1] = {
        [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
@@ -48,7 +47,6 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
 {
        struct nlattr *tb[TCA_CSUM_MAX + 1];
        struct tc_csum *parm;
-       struct tcf_common *pc;
        struct tcf_csum *p;
        int ret = 0, err;
 
@@ -63,38 +61,31 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
                return -EINVAL;
        parm = nla_data(tb[TCA_CSUM_PARMS]);
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+       if (!tcf_hash_check(parm->index, a, bind)) {
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind);
+               if (ret)
+                       return ret;
                ret = ACT_P_CREATED;
        } else {
                if (bind)/* dont override defaults */
                        return 0;
-               tcf_hash_release(pc, bind, a->ops->hinfo);
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
        }
 
-       p = to_tcf_csum(pc);
+       p = to_tcf_csum(a);
        spin_lock_bh(&p->tcf_lock);
        p->tcf_action = parm->action;
        p->update_flags = parm->update_flags;
        spin_unlock_bh(&p->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
 
        return ret;
 }
 
-static int tcf_csum_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_csum *p = a->priv;
-       return tcf_hash_release(&p->common, bind, &csum_hash_info);
-}
-
 /**
  * tcf_csum_skb_nextlayer - Get next layer pointer
  * @skb: sk_buff to use
@@ -569,12 +560,10 @@ nla_put_failure:
 
 static struct tc_action_ops act_csum_ops = {
        .kind           = "csum",
-       .hinfo          = &csum_hash_info,
        .type           = TCA_ACT_CSUM,
        .owner          = THIS_MODULE,
        .act            = tcf_csum,
        .dump           = tcf_csum_dump,
-       .cleanup        = tcf_csum_cleanup,
        .init           = tcf_csum_init,
 };
 
@@ -583,11 +572,7 @@ MODULE_LICENSE("GPL");
 
 static int __init csum_init_module(void)
 {
-       int err = tcf_hashinfo_init(&csum_hash_info, CSUM_TAB_MASK);
-       if (err)
-               return err;
-
-       return tcf_register_action(&act_csum_ops);
+       return tcf_register_action(&act_csum_ops, CSUM_TAB_MASK);
 }
 
 static void __exit csum_cleanup_module(void)
index a0eed30d58111ab49e11f9cc97c4dc0d30e93c9e..d6bcbd9f7791eb25cd250358b21b73b7bb80c3a0 100644 (file)
@@ -24,7 +24,6 @@
 #include <net/tc_act/tc_gact.h>
 
 #define GACT_TAB_MASK  15
-static struct tcf_hashinfo gact_hash_info;
 
 #ifdef CONFIG_GACT_PROB
 static int gact_net_rand(struct tcf_gact *gact)
@@ -57,7 +56,6 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        struct nlattr *tb[TCA_GACT_MAX + 1];
        struct tc_gact *parm;
        struct tcf_gact *gact;
-       struct tcf_common *pc;
        int ret = 0;
        int err;
 #ifdef CONFIG_GACT_PROB
@@ -86,21 +84,20 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
        }
 #endif
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+       if (!tcf_hash_check(parm->index, a, bind)) {
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind);
+               if (ret)
+                       return ret;
                ret = ACT_P_CREATED;
        } else {
                if (bind)/* dont override defaults */
                        return 0;
-               tcf_hash_release(pc, bind, a->ops->hinfo);
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
        }
 
-       gact = to_gact(pc);
+       gact = to_gact(a);
 
        spin_lock_bh(&gact->tcf_lock);
        gact->tcf_action = parm->action;
@@ -113,19 +110,10 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
 #endif
        spin_unlock_bh(&gact->tcf_lock);
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
        return ret;
 }
 
-static int tcf_gact_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_gact *gact = a->priv;
-
-       if (gact)
-               return tcf_hash_release(&gact->common, bind, a->ops->hinfo);
-       return 0;
-}
-
 static int tcf_gact(struct sk_buff *skb, const struct tc_action *a,
                    struct tcf_result *res)
 {
@@ -191,12 +179,10 @@ nla_put_failure:
 
 static struct tc_action_ops act_gact_ops = {
        .kind           =       "gact",
-       .hinfo          =       &gact_hash_info,
        .type           =       TCA_ACT_GACT,
        .owner          =       THIS_MODULE,
        .act            =       tcf_gact,
        .dump           =       tcf_gact_dump,
-       .cleanup        =       tcf_gact_cleanup,
        .init           =       tcf_gact_init,
 };
 
@@ -206,21 +192,17 @@ MODULE_LICENSE("GPL");
 
 static int __init gact_init_module(void)
 {
-       int err = tcf_hashinfo_init(&gact_hash_info, GACT_TAB_MASK);
-       if (err)
-               return err;
 #ifdef CONFIG_GACT_PROB
        pr_info("GACT probability on\n");
 #else
        pr_info("GACT probability NOT on\n");
 #endif
-       return tcf_register_action(&act_gact_ops);
+       return tcf_register_action(&act_gact_ops, GACT_TAB_MASK);
 }
 
 static void __exit gact_cleanup_module(void)
 {
        tcf_unregister_action(&act_gact_ops);
-       tcf_hashinfo_destroy(&gact_hash_info);
 }
 
 module_init(gact_init_module);
index 0a6d621740273ffddec7dffc1837f483be8bb0e2..8a64a0734aeebd29894111b4e93d288076b1df35 100644 (file)
@@ -29,7 +29,6 @@
 
 
 #define IPT_TAB_MASK     15
-static struct tcf_hashinfo ipt_hash_info;
 
 static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook)
 {
@@ -69,22 +68,12 @@ static void ipt_destroy_target(struct xt_entry_target *t)
        module_put(par.target->me);
 }
 
-static int tcf_ipt_release(struct tcf_ipt *ipt, int bind)
+static void tcf_ipt_release(struct tc_action *a, int bind)
 {
-       int ret = 0;
-       if (ipt) {
-               if (bind)
-                       ipt->tcf_bindcnt--;
-               ipt->tcf_refcnt--;
-               if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) {
-                       ipt_destroy_target(ipt->tcfi_t);
-                       kfree(ipt->tcfi_tname);
-                       kfree(ipt->tcfi_t);
-                       tcf_hash_destroy(&ipt->common, &ipt_hash_info);
-                       ret = ACT_P_DELETED;
-               }
-       }
-       return ret;
+       struct tcf_ipt *ipt = to_ipt(a);
+       ipt_destroy_target(ipt->tcfi_t);
+       kfree(ipt->tcfi_tname);
+       kfree(ipt->tcfi_t);
 }
 
 static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
@@ -99,7 +88,6 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
 {
        struct nlattr *tb[TCA_IPT_MAX + 1];
        struct tcf_ipt *ipt;
-       struct tcf_common *pc;
        struct xt_entry_target *td, *t;
        char *tname;
        int ret = 0, err;
@@ -125,21 +113,20 @@ 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]);
 
-       pc = tcf_hash_check(index, a, bind);
-       if (!pc) {
-               pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+       if (!tcf_hash_check(index, a, bind) ) {
+               ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind);
+               if (ret)
+                       return ret;
                ret = ACT_P_CREATED;
        } else {
                if (bind)/* dont override defaults */
                        return 0;
-               tcf_ipt_release(to_ipt(pc), bind);
+               tcf_hash_release(a, bind);
 
                if (!ovr)
                        return -EEXIST;
        }
-       ipt = to_ipt(pc);
+       ipt = to_ipt(a);
 
        hook = nla_get_u32(tb[TCA_IPT_HOOK]);
 
@@ -170,7 +157,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(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
        return ret;
 
 err3:
@@ -178,21 +165,11 @@ err3:
 err2:
        kfree(tname);
 err1:
-       if (ret == ACT_P_CREATED) {
-               if (est)
-                       gen_kill_estimator(&pc->tcfc_bstats,
-                                          &pc->tcfc_rate_est);
-               kfree_rcu(pc, tcfc_rcu);
-       }
+       if (ret == ACT_P_CREATED)
+               tcf_hash_cleanup(a, est);
        return err;
 }
 
-static int tcf_ipt_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_ipt *ipt = a->priv;
-       return tcf_ipt_release(ipt, bind);
-}
-
 static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
@@ -284,23 +261,21 @@ nla_put_failure:
 
 static struct tc_action_ops act_ipt_ops = {
        .kind           =       "ipt",
-       .hinfo          =       &ipt_hash_info,
        .type           =       TCA_ACT_IPT,
        .owner          =       THIS_MODULE,
        .act            =       tcf_ipt,
        .dump           =       tcf_ipt_dump,
-       .cleanup        =       tcf_ipt_cleanup,
+       .cleanup        =       tcf_ipt_release,
        .init           =       tcf_ipt_init,
 };
 
 static struct tc_action_ops act_xt_ops = {
        .kind           =       "xt",
-       .hinfo          =       &ipt_hash_info,
        .type           =       TCA_ACT_XT,
        .owner          =       THIS_MODULE,
        .act            =       tcf_ipt,
        .dump           =       tcf_ipt_dump,
-       .cleanup        =       tcf_ipt_cleanup,
+       .cleanup        =       tcf_ipt_release,
        .init           =       tcf_ipt_init,
 };
 
@@ -311,20 +286,16 @@ MODULE_ALIAS("act_xt");
 
 static int __init ipt_init_module(void)
 {
-       int ret1, ret2, err;
-       err = tcf_hashinfo_init(&ipt_hash_info, IPT_TAB_MASK);
-       if (err)
-               return err;
+       int ret1, ret2;
 
-       ret1 = tcf_register_action(&act_xt_ops);
+       ret1 = tcf_register_action(&act_xt_ops, IPT_TAB_MASK);
        if (ret1 < 0)
                printk("Failed to load xt action\n");
-       ret2 = tcf_register_action(&act_ipt_ops);
+       ret2 = tcf_register_action(&act_ipt_ops, IPT_TAB_MASK);
        if (ret2 < 0)
                printk("Failed to load ipt action\n");
 
        if (ret1 < 0 && ret2 < 0) {
-               tcf_hashinfo_destroy(&ipt_hash_info);
                return ret1;
        } else
                return 0;
@@ -334,7 +305,6 @@ static void __exit ipt_cleanup_module(void)
 {
        tcf_unregister_action(&act_xt_ops);
        tcf_unregister_action(&act_ipt_ops);
-       tcf_hashinfo_destroy(&ipt_hash_info);
 }
 
 module_init(ipt_init_module);
index 0b2c6d39d39671f9f96f57528e35588816a62e88..4f912c0e225b674dfa117060ee547b99feb972ca 100644 (file)
 
 #define MIRRED_TAB_MASK     7
 static LIST_HEAD(mirred_list);
-static struct tcf_hashinfo mirred_hash_info;
 
-static int tcf_mirred_release(struct tcf_mirred *m, int bind)
+static void tcf_mirred_release(struct tc_action *a, int bind)
 {
-       if (m) {
-               if (bind)
-                       m->tcf_bindcnt--;
-               m->tcf_refcnt--;
-               if (!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
-                       list_del(&m->tcfm_list);
-                       if (m->tcfm_dev)
-                               dev_put(m->tcfm_dev);
-                       tcf_hash_destroy(&m->common, &mirred_hash_info);
-                       return 1;
-               }
-       }
-       return 0;
+       struct tcf_mirred *m = to_mirred(a);
+       list_del(&m->tcfm_list);
+       if (m->tcfm_dev)
+               dev_put(m->tcfm_dev);
 }
 
 static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
@@ -61,7 +51,6 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
        struct nlattr *tb[TCA_MIRRED_MAX + 1];
        struct tc_mirred *parm;
        struct tcf_mirred *m;
-       struct tcf_common *pc;
        struct net_device *dev;
        int ret, ok_push = 0;
 
@@ -101,21 +90,20 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                dev = NULL;
        }
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
+       if (!tcf_hash_check(parm->index, a, bind)) {
                if (dev == NULL)
                        return -EINVAL;
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*m), bind);
+               if (ret)
+                       return ret;
                ret = ACT_P_CREATED;
        } else {
                if (!ovr) {
-                       tcf_mirred_release(to_mirred(pc), bind);
+                       tcf_hash_release(a, bind);
                        return -EEXIST;
                }
        }
-       m = to_mirred(pc);
+       m = to_mirred(a);
 
        spin_lock_bh(&m->tcf_lock);
        m->tcf_action = parm->action;
@@ -131,21 +119,12 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla,
        spin_unlock_bh(&m->tcf_lock);
        if (ret == ACT_P_CREATED) {
                list_add(&m->tcfm_list, &mirred_list);
-               tcf_hash_insert(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
        }
 
        return ret;
 }
 
-static int tcf_mirred_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_mirred *m = a->priv;
-
-       if (m)
-               return tcf_mirred_release(m, bind);
-       return 0;
-}
-
 static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
                      struct tcf_result *res)
 {
@@ -254,12 +233,11 @@ static struct notifier_block mirred_device_notifier = {
 
 static struct tc_action_ops act_mirred_ops = {
        .kind           =       "mirred",
-       .hinfo          =       &mirred_hash_info,
        .type           =       TCA_ACT_MIRRED,
        .owner          =       THIS_MODULE,
        .act            =       tcf_mirred,
        .dump           =       tcf_mirred_dump,
-       .cleanup        =       tcf_mirred_cleanup,
+       .cleanup        =       tcf_mirred_release,
        .init           =       tcf_mirred_init,
 };
 
@@ -273,19 +251,13 @@ static int __init mirred_init_module(void)
        if (err)
                return err;
 
-       err = tcf_hashinfo_init(&mirred_hash_info, MIRRED_TAB_MASK);
-       if (err) {
-               unregister_netdevice_notifier(&mirred_device_notifier);
-               return err;
-       }
        pr_info("Mirror/redirect action on\n");
-       return tcf_register_action(&act_mirred_ops);
+       return tcf_register_action(&act_mirred_ops, MIRRED_TAB_MASK);
 }
 
 static void __exit mirred_cleanup_module(void)
 {
        tcf_unregister_action(&act_mirred_ops);
-       tcf_hashinfo_destroy(&mirred_hash_info);
        unregister_netdevice_notifier(&mirred_device_notifier);
 }
 
index 81f0404bb33555244faf74504af4a8becf00d65a..270a030d5fd099ee7b6f6d74d51b6015aa690647 100644 (file)
@@ -31,8 +31,6 @@
 
 #define NAT_TAB_MASK   15
 
-static struct tcf_hashinfo nat_hash_info;
-
 static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
        [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) },
 };
@@ -44,7 +42,6 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
        struct tc_nat *parm;
        int ret = 0, err;
        struct tcf_nat *p;
-       struct tcf_common *pc;
 
        if (nla == NULL)
                return -EINVAL;
@@ -57,20 +54,19 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                return -EINVAL;
        parm = nla_data(tb[TCA_NAT_PARMS]);
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+       if (!tcf_hash_check(parm->index, a, bind)) {
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind);
+               if (ret)
+                       return ret;
                ret = ACT_P_CREATED;
        } else {
                if (bind)
                        return 0;
-               tcf_hash_release(pc, bind, a->ops->hinfo);
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
        }
-       p = to_tcf_nat(pc);
+       p = to_tcf_nat(a);
 
        spin_lock_bh(&p->tcf_lock);
        p->old_addr = parm->old_addr;
@@ -82,18 +78,11 @@ 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(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
 
        return ret;
 }
 
-static int tcf_nat_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_nat *p = a->priv;
-
-       return tcf_hash_release(&p->common, bind, &nat_hash_info);
-}
-
 static int tcf_nat(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
@@ -293,12 +282,10 @@ nla_put_failure:
 
 static struct tc_action_ops act_nat_ops = {
        .kind           =       "nat",
-       .hinfo          =       &nat_hash_info,
        .type           =       TCA_ACT_NAT,
        .owner          =       THIS_MODULE,
        .act            =       tcf_nat,
        .dump           =       tcf_nat_dump,
-       .cleanup        =       tcf_nat_cleanup,
        .init           =       tcf_nat_init,
 };
 
@@ -307,16 +294,12 @@ MODULE_LICENSE("GPL");
 
 static int __init nat_init_module(void)
 {
-       int err = tcf_hashinfo_init(&nat_hash_info, NAT_TAB_MASK);
-       if (err)
-               return err;
-       return tcf_register_action(&act_nat_ops);
+       return tcf_register_action(&act_nat_ops, NAT_TAB_MASK);
 }
 
 static void __exit nat_cleanup_module(void)
 {
        tcf_unregister_action(&act_nat_ops);
-       tcf_hashinfo_destroy(&nat_hash_info);
 }
 
 module_init(nat_init_module);
index be3f0f6875bb1b594f35685336d41d1a3fe62515..5f9bcb2e080bcd666c7c374a837916a227a0e41c 100644 (file)
@@ -25,8 +25,6 @@
 
 #define PEDIT_TAB_MASK 15
 
-static struct tcf_hashinfo pedit_hash_info;
-
 static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
        [TCA_PEDIT_PARMS]       = { .len = sizeof(struct tc_pedit) },
 };
@@ -39,7 +37,6 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        struct tc_pedit *parm;
        int ret = 0, err;
        struct tcf_pedit *p;
-       struct tcf_common *pc;
        struct tc_pedit_key *keys = NULL;
        int ksize;
 
@@ -57,26 +54,22 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
        if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize)
                return -EINVAL;
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
+       if (!tcf_hash_check(parm->index, a, bind)) {
                if (!parm->nkeys)
                        return -EINVAL;
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
-               p = to_pedit(pc);
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind);
+               if (ret)
+                       return ret;
+               p = to_pedit(a);
                keys = kmalloc(ksize, GFP_KERNEL);
                if (keys == NULL) {
-                       if (est)
-                               gen_kill_estimator(&pc->tcfc_bstats,
-                                                  &pc->tcfc_rate_est);
-                       kfree_rcu(pc, tcfc_rcu);
+                       tcf_hash_cleanup(a, est);
                        return -ENOMEM;
                }
                ret = ACT_P_CREATED;
        } else {
-               p = to_pedit(pc);
-               tcf_hash_release(pc, bind, a->ops->hinfo);
+               p = to_pedit(a);
+               tcf_hash_release(a, bind);
                if (bind)
                        return 0;
                if (!ovr)
@@ -100,22 +93,15 @@ 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(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
        return ret;
 }
 
-static int tcf_pedit_cleanup(struct tc_action *a, int bind)
+static void tcf_pedit_cleanup(struct tc_action *a, int bind)
 {
        struct tcf_pedit *p = a->priv;
-
-       if (p) {
-               struct tc_pedit_key *keys = p->tcfp_keys;
-               if (tcf_hash_release(&p->common, bind, &pedit_hash_info)) {
-                       kfree(keys);
-                       return 1;
-               }
-       }
-       return 0;
+       struct tc_pedit_key *keys = p->tcfp_keys;
+       kfree(keys);
 }
 
 static int tcf_pedit(struct sk_buff *skb, const struct tc_action *a,
@@ -230,7 +216,6 @@ nla_put_failure:
 
 static struct tc_action_ops act_pedit_ops = {
        .kind           =       "pedit",
-       .hinfo          =       &pedit_hash_info,
        .type           =       TCA_ACT_PEDIT,
        .owner          =       THIS_MODULE,
        .act            =       tcf_pedit,
@@ -245,15 +230,11 @@ MODULE_LICENSE("GPL");
 
 static int __init pedit_init_module(void)
 {
-       int err = tcf_hashinfo_init(&pedit_hash_info, PEDIT_TAB_MASK);
-       if (err)
-               return err;
-       return tcf_register_action(&act_pedit_ops);
+       return tcf_register_action(&act_pedit_ops, PEDIT_TAB_MASK);
 }
 
 static void __exit pedit_cleanup_module(void)
 {
-       tcf_hashinfo_destroy(&pedit_hash_info);
        tcf_unregister_action(&act_pedit_ops);
 }
 
index 1778209a332fa1ac251c02beaa97a49cfec747f3..0566e4606a4ac86710ebbc04a80c9ad1729849cd 100644 (file)
@@ -41,7 +41,6 @@ struct tcf_police {
        container_of(pc, struct tcf_police, common)
 
 #define POL_TAB_MASK     15
-static struct tcf_hashinfo police_hash_info;
 
 /* old policer structure from before tc actions */
 struct tc_police_compat {
@@ -234,7 +233,7 @@ override:
 
        police->tcfp_t_c = ktime_to_ns(ktime_get());
        police->tcf_index = parm->index ? parm->index :
-               tcf_hash_new_index(a->ops->hinfo);
+               tcf_hash_new_index(hinfo);
        h = tcf_hash(police->tcf_index, POL_TAB_MASK);
        spin_lock_bh(&hinfo->lock);
        hlist_add_head(&police->tcf_head, &hinfo->htab[h]);
@@ -253,14 +252,6 @@ failure:
        return err;
 }
 
-static int tcf_act_police_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_police *p = a->priv;
-       if (p)
-               return tcf_hash_release(&p->common, bind, &police_hash_info);
-       return 0;
-}
-
 static int tcf_act_police(struct sk_buff *skb, const struct tc_action *a,
                          struct tcf_result *res)
 {
@@ -357,12 +348,10 @@ MODULE_LICENSE("GPL");
 
 static struct tc_action_ops act_police_ops = {
        .kind           =       "police",
-       .hinfo          =       &police_hash_info,
        .type           =       TCA_ID_POLICE,
        .owner          =       THIS_MODULE,
        .act            =       tcf_act_police,
        .dump           =       tcf_act_police_dump,
-       .cleanup        =       tcf_act_police_cleanup,
        .init           =       tcf_act_police_locate,
        .walk           =       tcf_act_police_walker
 };
@@ -370,19 +359,12 @@ static struct tc_action_ops act_police_ops = {
 static int __init
 police_init_module(void)
 {
-       int err = tcf_hashinfo_init(&police_hash_info, POL_TAB_MASK);
-       if (err)
-               return err;
-       err = tcf_register_action(&act_police_ops);
-       if (err)
-               tcf_hashinfo_destroy(&police_hash_info);
-       return err;
+       return tcf_register_action(&act_police_ops, POL_TAB_MASK);
 }
 
 static void __exit
 police_cleanup_module(void)
 {
-       tcf_hashinfo_destroy(&police_hash_info);
        tcf_unregister_action(&act_police_ops);
 }
 
index 8ef2f1fcbfba20d9dcf853f21e1101b0ff363108..992c2317ce8871c84c45f2d387c5a3b5408d11fb 100644 (file)
@@ -25,7 +25,6 @@
 #include <net/tc_act/tc_defact.h>
 
 #define SIMP_TAB_MASK     7
-static struct tcf_hashinfo simp_hash_info;
 
 #define SIMP_MAX_DATA  32
 static int tcf_simp(struct sk_buff *skb, const struct tc_action *a,
@@ -47,20 +46,10 @@ static int tcf_simp(struct sk_buff *skb, const struct tc_action *a,
        return d->tcf_action;
 }
 
-static int tcf_simp_release(struct tcf_defact *d, int bind)
+static void tcf_simp_release(struct tc_action *a, int bind)
 {
-       int ret = 0;
-       if (d) {
-               if (bind)
-                       d->tcf_bindcnt--;
-               d->tcf_refcnt--;
-               if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) {
-                       kfree(d->tcfd_defdata);
-                       tcf_hash_destroy(&d->common, &simp_hash_info);
-                       ret = 1;
-               }
-       }
-       return ret;
+       struct tcf_defact *d = to_defact(a);
+       kfree(d->tcfd_defdata);
 }
 
 static int alloc_defdata(struct tcf_defact *d, char *defdata)
@@ -94,7 +83,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
        struct nlattr *tb[TCA_DEF_MAX + 1];
        struct tc_defact *parm;
        struct tcf_defact *d;
-       struct tcf_common *pc;
        char *defdata;
        int ret = 0, err;
 
@@ -114,29 +102,25 @@ 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]);
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+       if (!tcf_hash_check(parm->index, a, bind)) {
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*d), bind);
+               if (ret)
+                       return ret;
 
-               d = to_defact(pc);
+               d = to_defact(a);
                ret = alloc_defdata(d, defdata);
                if (ret < 0) {
-                       if (est)
-                               gen_kill_estimator(&pc->tcfc_bstats,
-                                                  &pc->tcfc_rate_est);
-                       kfree_rcu(pc, tcfc_rcu);
+                       tcf_hash_cleanup(a, est);
                        return ret;
                }
                d->tcf_action = parm->action;
                ret = ACT_P_CREATED;
        } else {
-               d = to_defact(pc);
+               d = to_defact(a);
 
                if (bind)
                        return 0;
-               tcf_simp_release(d, bind);
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
 
@@ -144,19 +128,10 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
        }
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
        return ret;
 }
 
-static int tcf_simp_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_defact *d = a->priv;
-
-       if (d)
-               return tcf_simp_release(d, bind);
-       return 0;
-}
-
 static int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
                         int bind, int ref)
 {
@@ -187,12 +162,11 @@ nla_put_failure:
 
 static struct tc_action_ops act_simp_ops = {
        .kind           =       "simple",
-       .hinfo          =       &simp_hash_info,
        .type           =       TCA_ACT_SIMP,
        .owner          =       THIS_MODULE,
        .act            =       tcf_simp,
        .dump           =       tcf_simp_dump,
-       .cleanup        =       tcf_simp_cleanup,
+       .cleanup        =       tcf_simp_release,
        .init           =       tcf_simp_init,
 };
 
@@ -202,23 +176,15 @@ MODULE_LICENSE("GPL");
 
 static int __init simp_init_module(void)
 {
-       int err, ret;
-       err = tcf_hashinfo_init(&simp_hash_info, SIMP_TAB_MASK);
-       if (err)
-               return err;
-
-       ret = tcf_register_action(&act_simp_ops);
+       int ret;
+       ret = tcf_register_action(&act_simp_ops, SIMP_TAB_MASK);
        if (!ret)
                pr_info("Simple TC action Loaded\n");
-       else
-               tcf_hashinfo_destroy(&simp_hash_info);
-
        return ret;
 }
 
 static void __exit simp_cleanup_module(void)
 {
-       tcf_hashinfo_destroy(&simp_hash_info);
        tcf_unregister_action(&act_simp_ops);
 }
 
index 98725080b5aa73a1d402a704a5a316eead4410a8..fcfeeaf838beb9e75f07f7cbda7fb2b73237a17f 100644 (file)
@@ -28,7 +28,6 @@
 #include <net/tc_act/tc_skbedit.h>
 
 #define SKBEDIT_TAB_MASK     15
-static struct tcf_hashinfo skbedit_hash_info;
 
 static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
                       struct tcf_result *res)
@@ -65,7 +64,6 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
        struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
        struct tc_skbedit *parm;
        struct tcf_skbedit *d;
-       struct tcf_common *pc;
        u32 flags = 0, *priority = NULL, *mark = NULL;
        u16 *queue_mapping = NULL;
        int ret = 0, err;
@@ -100,19 +98,18 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
 
        parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
 
-       pc = tcf_hash_check(parm->index, a, bind);
-       if (!pc) {
-               pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind);
-               if (IS_ERR(pc))
-                       return PTR_ERR(pc);
+       if (!tcf_hash_check(parm->index, a, bind)) {
+               ret = tcf_hash_create(parm->index, est, a, sizeof(*d), bind);
+               if (ret)
+                       return ret;
 
-               d = to_skbedit(pc);
+               d = to_skbedit(a);
                ret = ACT_P_CREATED;
        } else {
-               d = to_skbedit(pc);
+               d = to_skbedit(a);
                if (bind)
                        return 0;
-               tcf_hash_release(pc, bind, a->ops->hinfo);
+               tcf_hash_release(a, bind);
                if (!ovr)
                        return -EEXIST;
        }
@@ -132,19 +129,10 @@ 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(pc, a->ops->hinfo);
+               tcf_hash_insert(a);
        return ret;
 }
 
-static int tcf_skbedit_cleanup(struct tc_action *a, int bind)
-{
-       struct tcf_skbedit *d = a->priv;
-
-       if (d)
-               return tcf_hash_release(&d->common, bind, &skbedit_hash_info);
-       return 0;
-}
-
 static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
                            int bind, int ref)
 {
@@ -186,12 +174,10 @@ nla_put_failure:
 
 static struct tc_action_ops act_skbedit_ops = {
        .kind           =       "skbedit",
-       .hinfo          =       &skbedit_hash_info,
        .type           =       TCA_ACT_SKBEDIT,
        .owner          =       THIS_MODULE,
        .act            =       tcf_skbedit,
        .dump           =       tcf_skbedit_dump,
-       .cleanup        =       tcf_skbedit_cleanup,
        .init           =       tcf_skbedit_init,
 };
 
@@ -201,15 +187,11 @@ MODULE_LICENSE("GPL");
 
 static int __init skbedit_init_module(void)
 {
-       int err = tcf_hashinfo_init(&skbedit_hash_info, SKBEDIT_TAB_MASK);
-       if (err)
-               return err;
-       return tcf_register_action(&act_skbedit_ops);
+       return tcf_register_action(&act_skbedit_ops, SKBEDIT_TAB_MASK);
 }
 
 static void __exit skbedit_cleanup_module(void)
 {
-       tcf_hashinfo_destroy(&skbedit_hash_info);
        tcf_unregister_action(&act_skbedit_ops);
 }
 
index a366537f82c6b7981472cdcc51e977a139f3b540..63a3ce75c02ee959fe67d6b203e01420d86b03ad 100644 (file)
 #include <net/act_api.h>
 #include <net/pkt_cls.h>
 
-#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *))
+#define HTSIZE 256
 
 struct fw_head {
-       struct fw_filter *ht[HTSIZE];
-       u32 mask;
+       u32                     mask;
+       struct fw_filter        *ht[HTSIZE];
 };
 
 struct fw_filter {
@@ -46,30 +46,11 @@ struct fw_filter {
        struct tcf_exts         exts;
 };
 
-static inline int fw_hash(u32 handle)
+static u32 fw_hash(u32 handle)
 {
-       if (HTSIZE == 4096)
-               return ((handle >> 24) & 0xFFF) ^
-                      ((handle >> 12) & 0xFFF) ^
-                      (handle & 0xFFF);
-       else if (HTSIZE == 2048)
-               return ((handle >> 22) & 0x7FF) ^
-                      ((handle >> 11) & 0x7FF) ^
-                      (handle & 0x7FF);
-       else if (HTSIZE == 1024)
-               return ((handle >> 20) & 0x3FF) ^
-                      ((handle >> 10) & 0x3FF) ^
-                      (handle & 0x3FF);
-       else if (HTSIZE == 512)
-               return (handle >> 27) ^
-                      ((handle >> 18) & 0x1FF) ^
-                      ((handle >> 9) & 0x1FF) ^
-                      (handle & 0x1FF);
-       else if (HTSIZE == 256) {
-               u8 *t = (u8 *) &handle;
-               return t[0] ^ t[1] ^ t[2] ^ t[3];
-       } else
-               return handle & (HTSIZE - 1);
+       handle ^= (handle >> 16);
+       handle ^= (handle >> 8);
+       return handle % HTSIZE;
 }
 
 static int fw_classify(struct sk_buff *skb, const struct tcf_proto *tp,
index 1313145e3b8650853514552a0ddb371b4000b788..a0b84e0e22deb4c9e998499b1e202ebaafda95f8 100644 (file)
@@ -273,11 +273,12 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
 
 void qdisc_list_add(struct Qdisc *q)
 {
-       struct Qdisc *root = qdisc_dev(q)->qdisc;
+       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+               struct Qdisc *root = qdisc_dev(q)->qdisc;
 
-       WARN_ON_ONCE(root == &noop_qdisc);
-       if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
+               WARN_ON_ONCE(root == &noop_qdisc);
                list_add_tail(&q->list, &root->list);
+       }
 }
 EXPORT_SYMBOL(qdisc_list_add);
 
@@ -1303,6 +1304,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
        struct gnet_dump d;
        struct qdisc_size_table *stab;
 
+       cond_resched();
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
        if (!nlh)
                goto out_nlmsg_trim;
@@ -1434,9 +1436,9 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
        s_idx = cb->args[0];
        s_q_idx = q_idx = cb->args[1];
 
-       rcu_read_lock();
        idx = 0;
-       for_each_netdev_rcu(net, dev) {
+       ASSERT_RTNL();
+       for_each_netdev(net, dev) {
                struct netdev_queue *dev_queue;
 
                if (idx < s_idx)
@@ -1459,8 +1461,6 @@ cont:
        }
 
 done:
-       rcu_read_unlock();
-
        cb->args[0] = idx;
        cb->args[1] = q_idx;
 
@@ -1617,6 +1617,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q,
        struct gnet_dump d;
        const struct Qdisc_class_ops *cl_ops = q->ops->cl_ops;
 
+       cond_resched();
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*tcm), flags);
        if (!nlh)
                goto out_nlmsg_trim;
index 1f9c31411f1998dec927fccf05362f09408558b4..8449b337f9e3c9991b36144b98965a08d463cdf9 100644 (file)
@@ -623,8 +623,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
                if (nla_put_u32(skb, TCA_ATM_EXCESS, 0))
                        goto nla_put_failure;
        }
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index 2f80d01d42a6d8b971345229d407f062df921b04..ead526467ccae574d6afddb7a5146fc7507e68a9 100644 (file)
@@ -1563,8 +1563,7 @@ static int cbq_dump(struct Qdisc *sch, struct sk_buff *skb)
                goto nla_put_failure;
        if (cbq_dump_attr(skb, &q->link) < 0)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
@@ -1599,8 +1598,7 @@ cbq_dump_class(struct Qdisc *sch, unsigned long arg,
                goto nla_put_failure;
        if (cbq_dump_attr(skb, cl) < 0)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index 08ef7a42c0e411657e789cb140fad522aef97ed1..23c682b42f99ecb86ca8a103005a52d692a21d38 100644 (file)
@@ -601,6 +601,7 @@ static int fq_resize(struct Qdisc *sch, u32 log)
 {
        struct fq_sched_data *q = qdisc_priv(sch);
        struct rb_root *array;
+       void *old_fq_root;
        u32 idx;
 
        if (q->fq_root && log == q->fq_trees_log)
@@ -615,13 +616,19 @@ static int fq_resize(struct Qdisc *sch, u32 log)
        for (idx = 0; idx < (1U << log); idx++)
                array[idx] = RB_ROOT;
 
-       if (q->fq_root) {
-               fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
-               fq_free(q->fq_root);
-       }
+       sch_tree_lock(sch);
+
+       old_fq_root = q->fq_root;
+       if (old_fq_root)
+               fq_rehash(q, old_fq_root, q->fq_trees_log, array, log);
+
        q->fq_root = array;
        q->fq_trees_log = log;
 
+       sch_tree_unlock(sch);
+
+       fq_free(old_fq_root);
+
        return 0;
 }
 
@@ -697,9 +704,11 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt)
                q->flow_refill_delay = usecs_to_jiffies(usecs_delay);
        }
 
-       if (!err)
+       if (!err) {
+               sch_tree_unlock(sch);
                err = fq_resize(sch, fq_log);
-
+               sch_tree_lock(sch);
+       }
        while (sch->q.qlen > sch->limit) {
                struct sk_buff *skb = fq_dequeue(sch);
 
@@ -772,8 +781,7 @@ static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log))
                goto nla_put_failure;
 
-       nla_nest_end(skb, opts);
-       return skb->len;
+       return nla_nest_end(skb, opts);
 
 nla_put_failure:
        return -1;
index ba5bc929eac732900c1d6e3150ad224f3a50a1ae..0bf432c782c1f17cdb8bbb1b8ece16848e63c27e 100644 (file)
@@ -450,8 +450,7 @@ static int fq_codel_dump(struct Qdisc *sch, struct sk_buff *skb)
                        q->flows_cnt))
                goto nla_put_failure;
 
-       nla_nest_end(skb, opts);
-       return skb->len;
+       return nla_nest_end(skb, opts);
 
 nla_put_failure:
        return -1;
index c4075610502cf3f53f4ac3f1bc1be7b096e7f488..ec8aeaac1dd7ad7a077fddac3535c18064351b77 100644 (file)
@@ -1353,8 +1353,7 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,
                goto nla_put_failure;
        if (hfsc_dump_curves(skb, cl) < 0)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
  nla_put_failure:
        nla_nest_cancel(skb, nest);
index 647680b1c625ec9ca41adff446cd2bc32bc76a54..edee03d922e28678cc4f4ba843f600236cf06f08 100644 (file)
@@ -691,8 +691,7 @@ static int hhf_dump(struct Qdisc *sch, struct sk_buff *skb)
            nla_put_u32(skb, TCA_HHF_NON_HH_WEIGHT, q->hhf_non_hh_weight))
                goto nla_put_failure;
 
-       nla_nest_end(skb, opts);
-       return skb->len;
+       return nla_nest_end(skb, opts);
 
 nla_put_failure:
        return -1;
index 722e137df244dfef1fbd1ab8e8b477546990acde..9f949abcacef1680dcdc15579c7fe56611f21852 100644 (file)
@@ -1062,12 +1062,13 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
 
 static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
 {
-       spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
        struct htb_sched *q = qdisc_priv(sch);
        struct nlattr *nest;
        struct tc_htb_glob gopt;
 
-       spin_lock_bh(root_lock);
+       /* Its safe to not acquire qdisc lock. As we hold RTNL,
+        * no change can happen on the qdisc parameters.
+        */
 
        gopt.direct_pkts = q->direct_pkts;
        gopt.version = HTB_VER;
@@ -1081,13 +1082,10 @@ static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
        if (nla_put(skb, TCA_HTB_INIT, sizeof(gopt), &gopt) ||
            nla_put_u32(skb, TCA_HTB_DIRECT_QLEN, q->direct_qlen))
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
 
-       spin_unlock_bh(root_lock);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
-       spin_unlock_bh(root_lock);
        nla_nest_cancel(skb, nest);
        return -1;
 }
@@ -1096,11 +1094,12 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
                          struct sk_buff *skb, struct tcmsg *tcm)
 {
        struct htb_class *cl = (struct htb_class *)arg;
-       spinlock_t *root_lock = qdisc_root_sleeping_lock(sch);
        struct nlattr *nest;
        struct tc_htb_opt opt;
 
-       spin_lock_bh(root_lock);
+       /* Its safe to not acquire qdisc lock. As we hold RTNL,
+        * no change can happen on the class parameters.
+        */
        tcm->tcm_parent = cl->parent ? cl->parent->common.classid : TC_H_ROOT;
        tcm->tcm_handle = cl->common.classid;
        if (!cl->level && cl->un.leaf.q)
@@ -1128,12 +1127,9 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg,
            nla_put_u64(skb, TCA_HTB_CEIL64, cl->ceil.rate_bytes_ps))
                goto nla_put_failure;
 
-       nla_nest_end(skb, nest);
-       spin_unlock_bh(root_lock);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
-       spin_unlock_bh(root_lock);
        nla_nest_cancel(skb, nest);
        return -1;
 }
index bce1665239b8ff7e55901b216fb705bd6b31229e..62871c14e1f93fef31e5795ad2b8ae2f064399a4 100644 (file)
@@ -100,8 +100,7 @@ static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
        nest = nla_nest_start(skb, TCA_OPTIONS);
        if (nest == NULL)
                goto nla_put_failure;
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index de1059af6da14c563115147852c4f52b80a9387d..f1669a00f5710c297310f4a1da4a1b4e72cd3cab 100644 (file)
@@ -117,6 +117,11 @@ struct netem_sched_data {
                LOST_IN_BURST_PERIOD,
        } _4_state_model;
 
+       enum {
+               GOOD_STATE = 1,
+               BAD_STATE,
+       } GE_state_model;
+
        /* Correlated Loss Generation models */
        struct clgstate {
                /* state of the Markov chain */
@@ -272,15 +277,15 @@ static bool loss_gilb_ell(struct netem_sched_data *q)
        struct clgstate *clg = &q->clg;
 
        switch (clg->state) {
-       case 1:
+       case GOOD_STATE:
                if (prandom_u32() < clg->a1)
-                       clg->state = 2;
+                       clg->state = BAD_STATE;
                if (prandom_u32() < clg->a4)
                        return true;
                break;
-       case 2:
+       case BAD_STATE:
                if (prandom_u32() < clg->a2)
-                       clg->state = 1;
+                       clg->state = GOOD_STATE;
                if (prandom_u32() > clg->a3)
                        return true;
        }
@@ -689,9 +694,8 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
        return 0;
 }
 
-static void get_correlation(struct Qdisc *sch, const struct nlattr *attr)
+static void get_correlation(struct netem_sched_data *q, const struct nlattr *attr)
 {
-       struct netem_sched_data *q = qdisc_priv(sch);
        const struct tc_netem_corr *c = nla_data(attr);
 
        init_crandom(&q->delay_cor, c->delay_corr);
@@ -699,27 +703,24 @@ static void get_correlation(struct Qdisc *sch, const struct nlattr *attr)
        init_crandom(&q->dup_cor, c->dup_corr);
 }
 
-static void get_reorder(struct Qdisc *sch, const struct nlattr *attr)
+static void get_reorder(struct netem_sched_data *q, const struct nlattr *attr)
 {
-       struct netem_sched_data *q = qdisc_priv(sch);
        const struct tc_netem_reorder *r = nla_data(attr);
 
        q->reorder = r->probability;
        init_crandom(&q->reorder_cor, r->correlation);
 }
 
-static void get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
+static void get_corrupt(struct netem_sched_data *q, const struct nlattr *attr)
 {
-       struct netem_sched_data *q = qdisc_priv(sch);
        const struct tc_netem_corrupt *r = nla_data(attr);
 
        q->corrupt = r->probability;
        init_crandom(&q->corrupt_cor, r->correlation);
 }
 
-static void get_rate(struct Qdisc *sch, const struct nlattr *attr)
+static void get_rate(struct netem_sched_data *q, const struct nlattr *attr)
 {
-       struct netem_sched_data *q = qdisc_priv(sch);
        const struct tc_netem_rate *r = nla_data(attr);
 
        q->rate = r->rate;
@@ -732,9 +733,8 @@ static void get_rate(struct Qdisc *sch, const struct nlattr *attr)
                q->cell_size_reciprocal = (struct reciprocal_value) { 0 };
 }
 
-static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
+static int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
 {
-       struct netem_sched_data *q = qdisc_priv(sch);
        const struct nlattr *la;
        int rem;
 
@@ -752,7 +752,7 @@ static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
 
                        q->loss_model = CLG_4_STATES;
 
-                       q->clg.state = 1;
+                       q->clg.state = TX_IN_GAP_PERIOD;
                        q->clg.a1 = gi->p13;
                        q->clg.a2 = gi->p31;
                        q->clg.a3 = gi->p32;
@@ -770,7 +770,7 @@ static int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
                        }
 
                        q->loss_model = CLG_GILB_ELL;
-                       q->clg.state = 1;
+                       q->clg.state = GOOD_STATE;
                        q->clg.a1 = ge->p;
                        q->clg.a2 = ge->r;
                        q->clg.a3 = ge->h;
@@ -821,6 +821,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        struct netem_sched_data *q = qdisc_priv(sch);
        struct nlattr *tb[TCA_NETEM_MAX + 1];
        struct tc_netem_qopt *qopt;
+       struct clgstate old_clg;
+       int old_loss_model = CLG_RANDOM;
        int ret;
 
        if (opt == NULL)
@@ -831,6 +833,33 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        if (ret < 0)
                return ret;
 
+       /* backup q->clg and q->loss_model */
+       old_clg = q->clg;
+       old_loss_model = q->loss_model;
+
+       if (tb[TCA_NETEM_LOSS]) {
+               ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
+               if (ret) {
+                       q->loss_model = old_loss_model;
+                       return ret;
+               }
+       } else {
+               q->loss_model = CLG_RANDOM;
+       }
+
+       if (tb[TCA_NETEM_DELAY_DIST]) {
+               ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
+               if (ret) {
+                       /* recover clg and loss_model, in case of
+                        * q->clg and q->loss_model were modified
+                        * in get_loss_clg()
+                        */
+                       q->clg = old_clg;
+                       q->loss_model = old_loss_model;
+                       return ret;
+               }
+       }
+
        sch->limit = qopt->limit;
 
        q->latency = qopt->latency;
@@ -848,22 +877,16 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
                q->reorder = ~0;
 
        if (tb[TCA_NETEM_CORR])
-               get_correlation(sch, tb[TCA_NETEM_CORR]);
-
-       if (tb[TCA_NETEM_DELAY_DIST]) {
-               ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
-               if (ret)
-                       return ret;
-       }
+               get_correlation(q, tb[TCA_NETEM_CORR]);
 
        if (tb[TCA_NETEM_REORDER])
-               get_reorder(sch, tb[TCA_NETEM_REORDER]);
+               get_reorder(q, tb[TCA_NETEM_REORDER]);
 
        if (tb[TCA_NETEM_CORRUPT])
-               get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
+               get_corrupt(q, tb[TCA_NETEM_CORRUPT]);
 
        if (tb[TCA_NETEM_RATE])
-               get_rate(sch, tb[TCA_NETEM_RATE]);
+               get_rate(q, tb[TCA_NETEM_RATE]);
 
        if (tb[TCA_NETEM_RATE64])
                q->rate = max_t(u64, q->rate,
@@ -872,10 +895,6 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt)
        if (tb[TCA_NETEM_ECN])
                q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]);
 
-       q->loss_model = CLG_RANDOM;
-       if (tb[TCA_NETEM_LOSS])
-               ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
-
        return ret;
 }
 
index a255d0200a593a708a6f30f4e9dbb70fabb917c3..fefeeb73f15f18a84406ed686dc653ff3327ef45 100644 (file)
  *
  * ECN support is added by Naeem Khademi <naeemk@ifi.uio.no>
  * University of Oslo, Norway.
+ *
+ * References:
+ * IETF draft submission: http://tools.ietf.org/html/draft-pan-aqm-pie-00
+ * IEEE  Conference on High Performance Switching and Routing 2013 :
+ * "PIE: A * Lightweight Control Scheme to Address the Bufferbloat Problem"
  */
 
 #include <linux/module.h>
@@ -36,7 +41,7 @@ struct pie_params {
        psched_time_t target;   /* user specified target delay in pschedtime */
        u32 tupdate;            /* timer frequency (in jiffies) */
        u32 limit;              /* number of packets that can be enqueued */
-       u32 alpha;              /* alpha and beta are between -4 and 4 */
+       u32 alpha;              /* alpha and beta are between 0 and 32 */
        u32 beta;               /* and are used for shift relative to 1 */
        bool ecn;               /* true if ecn is enabled */
        bool bytemode;          /* to scale drop early prob based on pkt size */
@@ -326,10 +331,16 @@ static void calculate_probability(struct Qdisc *sch)
        if (qdelay == 0 && qlen != 0)
                update_prob = false;
 
-       /* Add ranges for alpha and beta, more aggressive for high dropping
-        * mode and gentle steps for light dropping mode
-        * In light dropping mode, take gentle steps; in medium dropping mode,
-        * take medium steps; in high dropping mode, take big steps.
+       /* In the algorithm, alpha and beta are between 0 and 2 with typical
+        * value for alpha as 0.125. In this implementation, we use values 0-32
+        * passed from user space to represent this. Also, alpha and beta have
+        * unit of HZ and need to be scaled before they can used to update
+        * probability. alpha/beta are updated locally below by 1) scaling them
+        * appropriately 2) scaling down by 16 to come to 0-2 range.
+        * Please see paper for details.
+        *
+        * We scale alpha and beta differently depending on whether we are in
+        * light, medium or high dropping mode.
         */
        if (q->vars.prob < MAX_PROB / 100) {
                alpha =
index 1cb413fead89522a64931a4e2472b39c4d6a720d..18ff634337092d5f8e7cba8fe817542f1455738f 100644 (file)
 struct tbf_sched_data {
 /* Parameters */
        u32             limit;          /* Maximal length of backlog: bytes */
+       u32             max_size;
        s64             buffer;         /* Token bucket depth/rate: MUST BE >= MTU/B */
        s64             mtu;
-       u32             max_size;
        struct psched_ratecfg rate;
        struct psched_ratecfg peak;
-       bool peak_present;
 
 /* Variables */
        s64     tokens;                 /* Current number of B tokens */
@@ -222,6 +221,11 @@ static unsigned int tbf_drop(struct Qdisc *sch)
        return len;
 }
 
+static bool tbf_peak_present(const struct tbf_sched_data *q)
+{
+       return q->peak.rate_bytes_ps;
+}
+
 static struct sk_buff *tbf_dequeue(struct Qdisc *sch)
 {
        struct tbf_sched_data *q = qdisc_priv(sch);
@@ -238,7 +242,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc *sch)
                now = ktime_to_ns(ktime_get());
                toks = min_t(s64, now - q->t_c, q->buffer);
 
-               if (q->peak_present) {
+               if (tbf_peak_present(q)) {
                        ptoks = toks + q->ptokens;
                        if (ptoks > q->mtu)
                                ptoks = q->mtu;
@@ -334,18 +338,6 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                        qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate,
                                                      tb[TCA_TBF_PTAB]));
 
-       if (q->qdisc != &noop_qdisc) {
-               err = fifo_set_limit(q->qdisc, qopt->limit);
-               if (err)
-                       goto done;
-       } else if (qopt->limit > 0) {
-               child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
-               if (IS_ERR(child)) {
-                       err = PTR_ERR(child);
-                       goto done;
-               }
-       }
-
        buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U);
        mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U);
 
@@ -378,6 +370,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                } else {
                        max_size = min_t(u64, max_size, psched_ns_t2l(&peak, mtu));
                }
+       } else {
+               memset(&peak, 0, sizeof(peak));
        }
 
        if (max_size < psched_mtu(qdisc_dev(sch)))
@@ -390,6 +384,18 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
                goto done;
        }
 
+       if (q->qdisc != &noop_qdisc) {
+               err = fifo_set_limit(q->qdisc, qopt->limit);
+               if (err)
+                       goto done;
+       } else if (qopt->limit > 0) {
+               child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
+               if (IS_ERR(child)) {
+                       err = PTR_ERR(child);
+                       goto done;
+               }
+       }
+
        sch_tree_lock(sch);
        if (child) {
                qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen);
@@ -410,12 +416,7 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
        q->ptokens = q->mtu;
 
        memcpy(&q->rate, &rate, sizeof(struct psched_ratecfg));
-       if (qopt->peakrate.rate) {
-               memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg));
-               q->peak_present = true;
-       } else {
-               q->peak_present = false;
-       }
+       memcpy(&q->peak, &peak, sizeof(struct psched_ratecfg));
 
        sch_tree_unlock(sch);
        err = 0;
@@ -458,7 +459,7 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
 
        opt.limit = q->limit;
        psched_ratecfg_getrate(&opt.rate, &q->rate);
-       if (q->peak_present)
+       if (tbf_peak_present(q))
                psched_ratecfg_getrate(&opt.peakrate, &q->peak);
        else
                memset(&opt.peakrate, 0, sizeof(opt.peakrate));
@@ -469,13 +470,12 @@ static int tbf_dump(struct Qdisc *sch, struct sk_buff *skb)
        if (q->rate.rate_bytes_ps >= (1ULL << 32) &&
            nla_put_u64(skb, TCA_TBF_RATE64, q->rate.rate_bytes_ps))
                goto nla_put_failure;
-       if (q->peak_present &&
+       if (tbf_peak_present(q) &&
            q->peak.rate_bytes_ps >= (1ULL << 32) &&
            nla_put_u64(skb, TCA_TBF_PRATE64, q->peak.rate_bytes_ps))
                goto nla_put_failure;
 
-       nla_nest_end(skb, nest);
-       return skb->len;
+       return nla_nest_end(skb, nest);
 
 nla_put_failure:
        nla_nest_cancel(skb, nest);
index 5ae60920067470463420f0b3aa879e7c0999f200..4f6d6f9d127474b457cf274a1a0977bb75c6e8dc 100644 (file)
@@ -1239,78 +1239,106 @@ void sctp_assoc_update(struct sctp_association *asoc,
 }
 
 /* Update the retran path for sending a retransmitted packet.
- * Round-robin through the active transports, else round-robin
- * through the inactive transports as this is the next best thing
- * we can try.
+ * See also RFC4960, 6.4. Multi-Homed SCTP Endpoints:
+ *
+ *   When there is outbound data to send and the primary path
+ *   becomes inactive (e.g., due to failures), or where the
+ *   SCTP user explicitly requests to send data to an
+ *   inactive destination transport address, before reporting
+ *   an error to its ULP, the SCTP endpoint should try to send
+ *   the data to an alternate active destination transport
+ *   address if one exists.
+ *
+ *   When retransmitting data that timed out, if the endpoint
+ *   is multihomed, it should consider each source-destination
+ *   address pair in its retransmission selection policy.
+ *   When retransmitting timed-out data, the endpoint should
+ *   attempt to pick the most divergent source-destination
+ *   pair from the original source-destination pair to which
+ *   the packet was transmitted.
+ *
+ *   Note: Rules for picking the most divergent source-destination
+ *   pair are an implementation decision and are not specified
+ *   within this document.
+ *
+ * Our basic strategy is to round-robin transports in priorities
+ * according to sctp_state_prio_map[] e.g., if no such
+ * transport with state SCTP_ACTIVE exists, round-robin through
+ * SCTP_UNKNOWN, etc. You get the picture.
  */
-void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+static const u8 sctp_trans_state_to_prio_map[] = {
+       [SCTP_ACTIVE]   = 3,    /* best case */
+       [SCTP_UNKNOWN]  = 2,
+       [SCTP_PF]       = 1,
+       [SCTP_INACTIVE] = 0,    /* worst case */
+};
+
+static u8 sctp_trans_score(const struct sctp_transport *trans)
 {
-       struct sctp_transport *t, *next;
-       struct list_head *head = &asoc->peer.transport_addr_list;
-       struct list_head *pos;
+       return sctp_trans_state_to_prio_map[trans->state];
+}
 
-       if (asoc->peer.transport_count == 1)
-               return;
+static struct sctp_transport *sctp_trans_elect_best(struct sctp_transport *curr,
+                                                   struct sctp_transport *best)
+{
+       if (best == NULL)
+               return curr;
 
-       /* Find the next transport in a round-robin fashion. */
-       t = asoc->peer.retran_path;
-       pos = &t->transports;
-       next = NULL;
+       return sctp_trans_score(curr) > sctp_trans_score(best) ? curr : best;
+}
 
-       while (1) {
-               /* Skip the head. */
-               if (pos->next == head)
-                       pos = head->next;
-               else
-                       pos = pos->next;
+void sctp_assoc_update_retran_path(struct sctp_association *asoc)
+{
+       struct sctp_transport *trans = asoc->peer.retran_path;
+       struct sctp_transport *trans_next = NULL;
 
-               t = list_entry(pos, struct sctp_transport, transports);
+       /* We're done as we only have the one and only path. */
+       if (asoc->peer.transport_count == 1)
+               return;
+       /* If active_path and retran_path are the same and active,
+        * then this is the only active path. Use it.
+        */
+       if (asoc->peer.active_path == asoc->peer.retran_path &&
+           asoc->peer.active_path->state == SCTP_ACTIVE)
+               return;
 
-               /* We have exhausted the list, but didn't find any
-                * other active transports.  If so, use the next
-                * transport.
-                */
-               if (t == asoc->peer.retran_path) {
-                       t = next;
+       /* Iterate from retran_path's successor back to retran_path. */
+       for (trans = list_next_entry(trans, transports); 1;
+            trans = list_next_entry(trans, transports)) {
+               /* Manually skip the head element. */
+               if (&trans->transports == &asoc->peer.transport_addr_list)
+                       continue;
+               if (trans->state == SCTP_UNCONFIRMED)
+                       continue;
+               trans_next = sctp_trans_elect_best(trans, trans_next);
+               /* Active is good enough for immediate return. */
+               if (trans_next->state == SCTP_ACTIVE)
                        break;
-               }
-
-               /* Try to find an active transport. */
-
-               if ((t->state == SCTP_ACTIVE) ||
-                   (t->state == SCTP_UNKNOWN)) {
+               /* We've reached the end, time to update path. */
+               if (trans == asoc->peer.retran_path)
                        break;
-               } else {
-                       /* Keep track of the next transport in case
-                        * we don't find any active transport.
-                        */
-                       if (t->state != SCTP_UNCONFIRMED && !next)
-                               next = t;
-               }
        }
 
-       if (t)
-               asoc->peer.retran_path = t;
-       else
-               t = asoc->peer.retran_path;
+       asoc->peer.retran_path = trans_next;
 
-       pr_debug("%s: association:%p addr:%pISpc\n", __func__, asoc,
-                &t->ipaddr.sa);
+       pr_debug("%s: association:%p updated new path to addr:%pISpc\n",
+                __func__, asoc, &asoc->peer.retran_path->ipaddr.sa);
 }
 
-/* Choose the transport for sending retransmit packet.  */
-struct sctp_transport *sctp_assoc_choose_alter_transport(
-       struct sctp_association *asoc, struct sctp_transport *last_sent_to)
+struct sctp_transport *
+sctp_assoc_choose_alter_transport(struct sctp_association *asoc,
+                                 struct sctp_transport *last_sent_to)
 {
        /* If this is the first time packet is sent, use the active path,
         * else use the retran path. If the last packet was sent over the
         * retran path, update the retran path and use it.
         */
-       if (!last_sent_to)
+       if (last_sent_to == NULL) {
                return asoc->peer.active_path;
-       else {
+       else {
                if (last_sent_to == asoc->peer.retran_path)
                        sctp_assoc_update_retran_path(asoc);
+
                return asoc->peer.retran_path;
        }
 }
@@ -1367,44 +1395,35 @@ static inline bool sctp_peer_needs_update(struct sctp_association *asoc)
        return false;
 }
 
-/* Increase asoc's rwnd by len and send any window update SACK if needed. */
-void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
+/* Update asoc's rwnd for the approximated state in the buffer,
+ * and check whether SACK needs to be sent.
+ */
+void sctp_assoc_rwnd_update(struct sctp_association *asoc, bool update_peer)
 {
+       int rx_count;
        struct sctp_chunk *sack;
        struct timer_list *timer;
 
-       if (asoc->rwnd_over) {
-               if (asoc->rwnd_over >= len) {
-                       asoc->rwnd_over -= len;
-               } else {
-                       asoc->rwnd += (len - asoc->rwnd_over);
-                       asoc->rwnd_over = 0;
-               }
-       } else {
-               asoc->rwnd += len;
-       }
+       if (asoc->ep->rcvbuf_policy)
+               rx_count = atomic_read(&asoc->rmem_alloc);
+       else
+               rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
 
-       /* If we had window pressure, start recovering it
-        * once our rwnd had reached the accumulated pressure
-        * threshold.  The idea is to recover slowly, but up
-        * to the initial advertised window.
-        */
-       if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) {
-               int change = min(asoc->pathmtu, asoc->rwnd_press);
-               asoc->rwnd += change;
-               asoc->rwnd_press -= change;
-       }
+       if ((asoc->base.sk->sk_rcvbuf - rx_count) > 0)
+               asoc->rwnd = (asoc->base.sk->sk_rcvbuf - rx_count) >> 1;
+       else
+               asoc->rwnd = 0;
 
-       pr_debug("%s: asoc:%p rwnd increased by %d to (%u, %u) - %u\n",
-                __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
-                asoc->a_rwnd);
+       pr_debug("%s: asoc:%p rwnd=%u, rx_count=%d, sk_rcvbuf=%d\n",
+                __func__, asoc, asoc->rwnd, rx_count,
+                asoc->base.sk->sk_rcvbuf);
 
        /* Send a window update SACK if the rwnd has increased by at least the
         * minimum of the association's PMTU and half of the receive buffer.
         * The algorithm used is similar to the one described in
         * Section 4.2.3.3 of RFC 1122.
         */
-       if (sctp_peer_needs_update(asoc)) {
+       if (update_peer && sctp_peer_needs_update(asoc)) {
                asoc->a_rwnd = asoc->rwnd;
 
                pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u "
@@ -1426,45 +1445,6 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len)
        }
 }
 
-/* Decrease asoc's rwnd by len. */
-void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len)
-{
-       int rx_count;
-       int over = 0;
-
-       if (unlikely(!asoc->rwnd || asoc->rwnd_over))
-               pr_debug("%s: association:%p has asoc->rwnd:%u, "
-                        "asoc->rwnd_over:%u!\n", __func__, asoc,
-                        asoc->rwnd, asoc->rwnd_over);
-
-       if (asoc->ep->rcvbuf_policy)
-               rx_count = atomic_read(&asoc->rmem_alloc);
-       else
-               rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
-
-       /* If we've reached or overflowed our receive buffer, announce
-        * a 0 rwnd if rwnd would still be positive.  Store the
-        * the potential pressure overflow so that the window can be restored
-        * back to original value.
-        */
-       if (rx_count >= asoc->base.sk->sk_rcvbuf)
-               over = 1;
-
-       if (asoc->rwnd >= len) {
-               asoc->rwnd -= len;
-               if (over) {
-                       asoc->rwnd_press += asoc->rwnd;
-                       asoc->rwnd = 0;
-               }
-       } else {
-               asoc->rwnd_over = len - asoc->rwnd;
-               asoc->rwnd = 0;
-       }
-
-       pr_debug("%s: asoc:%p rwnd decreased by %d to (%u, %u, %u)\n",
-                __func__, asoc, len, asoc->rwnd, asoc->rwnd_over,
-                asoc->rwnd_press);
-}
 
 /* Build the bind address list for the association based on info from the
  * local endpoint and the remote peer.
index 0f6259a6a932c583f4450a6fe79ef46b7d184996..2b1738ef9394537589b403f7d299181e18fb2315 100644 (file)
@@ -662,6 +662,8 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
         */
        sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk);
 
+       newsk->sk_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
+
        sk_refcnt_debug_inc(newsk);
 
        if (newsk->sk_prot->init(newsk)) {
index 632090b961c331b78efa79664392c7626451926d..3a1767ef3201a6a1870f641ef29e3683ea6dcff7 100644 (file)
@@ -1421,8 +1421,8 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
        BUG_ON(!list_empty(&chunk->list));
        list_del_init(&chunk->transmitted_list);
 
-       /* Free the chunk skb data and the SCTP_chunk stub itself. */
-       dev_kfree_skb(chunk->skb);
+       consume_skb(chunk->skb);
+       consume_skb(chunk->auth_chunk);
 
        SCTP_DBG_OBJCNT_DEC(chunk);
        kmem_cache_free(sctp_chunk_cachep, chunk);
index bd859154000e47cccdae4f9f5e4353ba3cb83fd0..5d6883ff00c3b7056639f06254caffcb14349e27 100644 (file)
@@ -495,11 +495,12 @@ static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
        }
 
        /* If the transport error count is greater than the pf_retrans
-        * threshold, and less than pathmaxrtx, then mark this transport
-        * as Partially Failed, ee SCTP Quick Failover Draft, secon 5.1,
-        * point 1
+        * threshold, and less than pathmaxrtx, and if the current state
+        * is not SCTP_UNCONFIRMED, then mark this transport as Partially
+        * Failed, see SCTP Quick Failover Draft, section 5.1
         */
        if ((transport->state != SCTP_PF) &&
+          (transport->state != SCTP_UNCONFIRMED) &&
           (asoc->pf_retrans < transport->pathmaxrxt) &&
           (transport->error_count > asoc->pf_retrans)) {
 
index 483dcd71b3c5f76a17dc66aee156c0b6caf60bac..01e002430c858c293cdda11bd2962c3340043fb9 100644 (file)
@@ -758,6 +758,12 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                struct sctp_chunk auth;
                sctp_ierror_t ret;
 
+               /* Make sure that we and the peer are AUTH capable */
+               if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) {
+                       sctp_association_free(new_asoc);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+               }
+
                /* set-up our fake chunk so that we can process it */
                auth.skb = chunk->auth_chunk;
                auth.asoc = chunk->asoc;
@@ -768,10 +774,6 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
                auth.transport = chunk->transport;
 
                ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
-
-               /* We can now safely free the auth_chunk clone */
-               kfree_skb(chunk->auth_chunk);
-
                if (ret != SCTP_IERROR_NO_ERROR) {
                        sctp_association_free(new_asoc);
                        return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -6176,7 +6178,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
         * PMTU.  In cases, such as loopback, this might be a rather
         * large spill over.
         */
-       if ((!chunk->data_accepted) && (!asoc->rwnd || asoc->rwnd_over ||
+       if ((!chunk->data_accepted) && (!asoc->rwnd ||
            (datalen > asoc->rwnd + asoc->frag_point))) {
 
                /* If this is the next TSN, consider reneging to make
index 9e91d6e5df63e4317eeeb367d55e734e5a62af2f..981aaf8b6ace45e55b80a235ebbb9dfcb693d64b 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/crypto.h>
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/compat.h>
 
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -1368,11 +1369,19 @@ static int sctp_setsockopt_connectx(struct sock *sk,
 /*
  * New (hopefully final) interface for the API.
  * We use the sctp_getaddrs_old structure so that use-space library
- * can avoid any unnecessary allocations.   The only defferent part
+ * can avoid any unnecessary allocations. The only different part
  * is that we store the actual length of the address buffer into the
- * addrs_num structure member.  That way we can re-use the existing
+ * addrs_num structure member. That way we can re-use the existing
  * code.
  */
+#ifdef CONFIG_COMPAT
+struct compat_sctp_getaddrs_old {
+       sctp_assoc_t    assoc_id;
+       s32             addr_num;
+       compat_uptr_t   addrs;          /* struct sockaddr * */
+};
+#endif
+
 static int sctp_getsockopt_connectx3(struct sock *sk, int len,
                                     char __user *optval,
                                     int __user *optlen)
@@ -1381,16 +1390,30 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len,
        sctp_assoc_t assoc_id = 0;
        int err = 0;
 
-       if (len < sizeof(param))
-               return -EINVAL;
+#ifdef CONFIG_COMPAT
+       if (is_compat_task()) {
+               struct compat_sctp_getaddrs_old param32;
 
-       if (copy_from_user(&param, optval, sizeof(param)))
-               return -EFAULT;
+               if (len < sizeof(param32))
+                       return -EINVAL;
+               if (copy_from_user(&param32, optval, sizeof(param32)))
+                       return -EFAULT;
 
-       err = __sctp_setsockopt_connectx(sk,
-                       (struct sockaddr __user *)param.addrs,
-                       param.addr_num, &assoc_id);
+               param.assoc_id = param32.assoc_id;
+               param.addr_num = param32.addr_num;
+               param.addrs = compat_ptr(param32.addrs);
+       } else
+#endif
+       {
+               if (len < sizeof(param))
+                       return -EINVAL;
+               if (copy_from_user(&param, optval, sizeof(param)))
+                       return -EFAULT;
+       }
 
+       err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *)
+                                        param.addrs, param.addr_num,
+                                        &assoc_id);
        if (err == 0 || err == -EINPROGRESS) {
                if (copy_to_user(optval, &assoc_id, sizeof(assoc_id)))
                        return -EFAULT;
@@ -2092,12 +2115,6 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
                sctp_skb_pull(skb, copied);
                skb_queue_head(&sk->sk_receive_queue, skb);
 
-               /* When only partial message is copied to the user, increase
-                * rwnd by that amount. If all the data in the skb is read,
-                * rwnd is updated when the event is freed.
-                */
-               if (!sctp_ulpevent_is_notification(event))
-                       sctp_assoc_rwnd_increase(event->asoc, copied);
                goto out;
        } else if ((event->msg_flags & MSG_NOTIFICATION) ||
                   (event->msg_flags & MSG_EOR))
index 7135e617ab0ffa7343a2d698e94c6a71d5334d9d..35c8923b5554aa33549eb872c8d2aaa292b34db1 100644 (file)
@@ -151,6 +151,7 @@ static struct ctl_table sctp_net_table[] = {
        },
        {
                .procname       = "cookie_hmac_alg",
+               .data           = &init_net.sctp.sctp_hmac_alg,
                .maxlen         = 8,
                .mode           = 0644,
                .proc_handler   = proc_sctp_do_hmac_alg,
@@ -401,15 +402,18 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
 
 int sctp_sysctl_net_register(struct net *net)
 {
-       struct ctl_table *table;
-       int i;
+       struct ctl_table *table = sctp_net_table;
+
+       if (!net_eq(net, &init_net)) {
+               int i;
 
-       table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL);
-       if (!table)
-               return -ENOMEM;
+               table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL);
+               if (!table)
+                       return -ENOMEM;
 
-       for (i = 0; table[i].data; i++)
-               table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
+               for (i = 0; table[i].data; i++)
+                       table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
+       }
 
        net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table);
        return 0;
index d0810dc5f079f67de9bf8192fa3968fd81e245f0..1d348d15b33de4c3b20f7f071442c05058e7dcc3 100644 (file)
@@ -652,5 +652,4 @@ void sctp_transport_immediate_rtx(struct sctp_transport *t)
                if (!mod_timer(&t->T3_rtx_timer, jiffies + t->rto))
                        sctp_transport_hold(t);
        }
-       return;
 }
index 85c64658bd0b183df5c7a7fd8394df757cb0b4b0..8d198ae0360634d25d3e4cff8a56cf73e389bd2d 100644 (file)
@@ -989,7 +989,7 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event,
        skb = sctp_event2skb(event);
        /* Set the owner and charge rwnd for bytes received.  */
        sctp_ulpevent_set_owner(event, asoc);
-       sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb));
+       sctp_assoc_rwnd_update(asoc, false);
 
        if (!skb->data_len)
                return;
@@ -1011,6 +1011,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
 {
        struct sk_buff *skb, *frag;
        unsigned int    len;
+       struct sctp_association *asoc;
 
        /* Current stack structures assume that the rcv buffer is
         * per socket.   For UDP style sockets this is not true as
@@ -1035,8 +1036,11 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event)
        }
 
 done:
-       sctp_assoc_rwnd_increase(event->asoc, len);
+       asoc = event->asoc;
+       sctp_association_hold(asoc);
        sctp_ulpevent_release_owner(event);
+       sctp_assoc_rwnd_update(asoc, true);
+       sctp_association_put(asoc);
 }
 
 static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event)
index 879933aaed4c07ecd9cdad1809939ff729a588a7..f25eaa30b6907dd9d8c332c54a05cc38c843f7ff 100644 (file)
@@ -450,16 +450,17 @@ EXPORT_SYMBOL(sockfd_lookup);
 
 static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
 {
-       struct file *file;
+       struct fd f = fdget(fd);
        struct socket *sock;
 
        *err = -EBADF;
-       file = fget_light(fd, fput_needed);
-       if (file) {
-               sock = sock_from_file(file, err);
-               if (sock)
+       if (f.file) {
+               sock = sock_from_file(f.file, err);
+               if (likely(sock)) {
+                       *fput_needed = f.flags;
                        return sock;
-               fput_light(file, *fput_needed);
+               }
+               fdput(f);
        }
        return NULL;
 }
@@ -593,7 +594,7 @@ void sock_release(struct socket *sock)
        }
 
        if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
-               printk(KERN_ERR "sock_release: fasync list not empty!\n");
+               pr_err("%s: fasync list not empty!\n", __func__);
 
        if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags))
                return;
@@ -1265,8 +1266,8 @@ int __sock_create(struct net *net, int family, int type, int protocol,
                static int warned;
                if (!warned) {
                        warned = 1;
-                       printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",
-                              current->comm);
+                       pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n",
+                               current->comm);
                }
                family = PF_PACKET;
        }
@@ -1985,6 +1986,10 @@ static int copy_msghdr_from_user(struct msghdr *kmsg,
 {
        if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
                return -EFAULT;
+
+       if (kmsg->msg_namelen < 0)
+               return -EINVAL;
+
        if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
                kmsg->msg_namelen = sizeof(struct sockaddr_storage);
        return 0;
@@ -2595,8 +2600,7 @@ int sock_register(const struct net_proto_family *ops)
        int err;
 
        if (ops->family >= NPROTO) {
-               printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
-                      NPROTO);
+               pr_crit("protocol %d >= NPROTO(%d)\n", ops->family, NPROTO);
                return -ENOBUFS;
        }
 
@@ -2610,7 +2614,7 @@ int sock_register(const struct net_proto_family *ops)
        }
        spin_unlock(&net_family_lock);
 
-       printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
+       pr_info("NET: Registered protocol family %d\n", ops->family);
        return err;
 }
 EXPORT_SYMBOL(sock_register);
@@ -2638,7 +2642,7 @@ void sock_unregister(int family)
 
        synchronize_rcu();
 
-       printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
+       pr_info("NET: Unregistered protocol family %d\n", family);
 }
 EXPORT_SYMBOL(sock_unregister);
 
index 6c0513a7f99232280f78067d56c5c369cb79630d..36e431ee1c902ef1c6ed777331cf97ceda0bdee4 100644 (file)
@@ -108,6 +108,7 @@ struct gss_auth {
 static DEFINE_SPINLOCK(pipe_version_lock);
 static struct rpc_wait_queue pipe_version_rpc_waitqueue;
 static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue);
+static void gss_put_auth(struct gss_auth *gss_auth);
 
 static void gss_free_ctx(struct gss_cl_ctx *);
 static const struct rpc_pipe_ops gss_upcall_ops_v0;
@@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
        if (gss_msg->ctx != NULL)
                gss_put_ctx(gss_msg->ctx);
        rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue);
+       gss_put_auth(gss_msg->auth);
        kfree(gss_msg);
 }
 
@@ -498,9 +500,12 @@ gss_alloc_msg(struct gss_auth *gss_auth,
        default:
                err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
                if (err)
-                       goto err_free_msg;
+                       goto err_put_pipe_version;
        };
+       kref_get(&gss_auth->kref);
        return gss_msg;
+err_put_pipe_version:
+       put_pipe_version(gss_auth->net);
 err_free_msg:
        kfree(gss_msg);
 err:
@@ -991,6 +996,8 @@ gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
        gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
        if (gss_auth->service == 0)
                goto err_put_mech;
+       if (!gssd_running(gss_auth->net))
+               goto err_put_mech;
        auth = &gss_auth->rpc_auth;
        auth->au_cslack = GSS_CRED_SLACK >> 2;
        auth->au_rslack = GSS_VERF_SLACK >> 2;
@@ -1061,6 +1068,12 @@ gss_free_callback(struct kref *kref)
        gss_free(gss_auth);
 }
 
+static void
+gss_put_auth(struct gss_auth *gss_auth)
+{
+       kref_put(&gss_auth->kref, gss_free_callback);
+}
+
 static void
 gss_destroy(struct rpc_auth *auth)
 {
@@ -1082,7 +1095,7 @@ gss_destroy(struct rpc_auth *auth)
        gss_auth->gss_pipe[1] = NULL;
        rpcauth_destroy_credcache(auth);
 
-       kref_put(&gss_auth->kref, gss_free_callback);
+       gss_put_auth(gss_auth);
 }
 
 /*
@@ -1253,7 +1266,7 @@ gss_destroy_nullcred(struct rpc_cred *cred)
        call_rcu(&cred->cr_rcu, gss_free_cred_callback);
        if (ctx)
                gss_put_ctx(ctx);
-       kref_put(&gss_auth->kref, gss_free_callback);
+       gss_put_auth(gss_auth);
 }
 
 static void
index 890a29912d5ab3f39d156891d4844ede04d367e8..e860d4f7ed2accd100c9ae9f715018daaae469a1 100644 (file)
@@ -64,7 +64,6 @@ static void xprt_free_allocation(struct rpc_rqst *req)
        free_page((unsigned long)xbufp->head[0].iov_base);
        xbufp = &req->rq_snd_buf;
        free_page((unsigned long)xbufp->head[0].iov_base);
-       list_del(&req->rq_bc_pa_list);
        kfree(req);
 }
 
@@ -168,8 +167,10 @@ out_free:
        /*
         * Memory allocation failed, free the temporary list
         */
-       list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list)
+       list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) {
+               list_del(&req->rq_bc_pa_list);
                xprt_free_allocation(req);
+       }
 
        dprintk("RPC:       setup backchannel transport failed\n");
        return -ENOMEM;
@@ -198,6 +199,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs)
        xprt_dec_alloc_count(xprt, max_reqs);
        list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) {
                dprintk("RPC:        req=%p\n", req);
+               list_del(&req->rq_bc_pa_list);
                xprt_free_allocation(req);
                if (--max_reqs == 0)
                        break;
index 80a6640f329bab991859e032fda658a871e65ca5..06c6ff0cb9114200d88cb85e0c98af35670932f8 100644 (file)
@@ -571,7 +571,7 @@ static void svc_check_conn_limits(struct svc_serv *serv)
        }
 }
 
-int svc_alloc_arg(struct svc_rqst *rqstp)
+static int svc_alloc_arg(struct svc_rqst *rqstp)
 {
        struct svc_serv *serv = rqstp->rq_server;
        struct xdr_buf *arg;
@@ -612,7 +612,7 @@ int svc_alloc_arg(struct svc_rqst *rqstp)
        return 0;
 }
 
-struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
+static struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
 {
        struct svc_xprt *xprt;
        struct svc_pool         *pool = rqstp->rq_pool;
@@ -691,7 +691,7 @@ struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout)
        return xprt;
 }
 
-void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt)
+static void svc_add_new_temp_xprt(struct svc_serv *serv, struct svc_xprt *newxpt)
 {
        spin_lock_bh(&serv->sv_lock);
        set_bit(XPT_TEMP, &newxpt->xpt_flags);
index 817a1e5239692e9fb3f5117f36eb0895d426ea5f..0addefca8e7757d78571928580d6f7473a1354ae 100644 (file)
@@ -510,6 +510,7 @@ static int xs_nospace(struct rpc_task *task)
        struct rpc_rqst *req = task->tk_rqstp;
        struct rpc_xprt *xprt = req->rq_xprt;
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
+       struct sock *sk = transport->inet;
        int ret = -EAGAIN;
 
        dprintk("RPC: %5u xmit incomplete (%u left of %u)\n",
@@ -527,7 +528,7 @@ static int xs_nospace(struct rpc_task *task)
                         * window size
                         */
                        set_bit(SOCK_NOSPACE, &transport->sock->flags);
-                       transport->inet->sk_write_pending++;
+                       sk->sk_write_pending++;
                        /* ...and wait for more buffer space */
                        xprt_wait_for_buffer_space(task, xs_nospace_callback);
                }
@@ -537,6 +538,9 @@ static int xs_nospace(struct rpc_task *task)
        }
 
        spin_unlock_bh(&xprt->transport_lock);
+
+       /* Race breaker in case memory is freed before above code is called */
+       sk->sk_write_space(sk);
        return ret;
 }
 
index 60b00ab93d74159cbc18e1caa1e469a7e38b651c..a74acf9ee804b43496d2c53c5ebb26160378eaa6 100644 (file)
@@ -37,6 +37,8 @@
 #ifndef _TIPC_ADDR_H
 #define _TIPC_ADDR_H
 
+#include "core.h"
+
 #define TIPC_ZONE_MASK         0xff000000u
 #define TIPC_CLUSTER_MASK      0xfffff000u
 
index bf860d9e75af2363e6538ee525c60bf7c0821b6c..95ab5ef92920fddf34c02478973b98ebbe96ba59 100644 (file)
@@ -41,9 +41,9 @@
 #include "bcast.h"
 #include "name_distr.h"
 
-#define MAX_PKT_DEFAULT_MCAST 1500     /* bcast link max packet size (fixed) */
-
-#define BCLINK_WIN_DEFAULT 20          /* bcast link window size (default) */
+#define        MAX_PKT_DEFAULT_MCAST   1500    /* bcast link max packet size (fixed) */
+#define        BCLINK_WIN_DEFAULT      20      /* bcast link window size (default) */
+#define        BCBEARER                MAX_BEARERS
 
 /**
  * struct tipc_bcbearer_pair - a pair of bearers used by broadcast link
@@ -356,9 +356,9 @@ static void bclink_peek_nack(struct tipc_msg *msg)
 }
 
 /*
- * tipc_bclink_send_msg - broadcast a packet to all nodes in cluster
+ * tipc_bclink_xmit - broadcast a packet to all nodes in cluster
  */
-int tipc_bclink_send_msg(struct sk_buff *buf)
+int tipc_bclink_xmit(struct sk_buff *buf)
 {
        int res;
 
@@ -370,7 +370,7 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
                goto exit;
        }
 
-       res = tipc_link_send_buf(bcl, buf);
+       res = __tipc_link_xmit(bcl, buf);
        if (likely(res >= 0)) {
                bclink_set_last_sent();
                bcl->stats.queue_sz_counts++;
@@ -399,19 +399,18 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
         */
 
        if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) {
-               tipc_link_send_proto_msg(
-                       node->active_links[node->addr & 1],
-                       STATE_MSG, 0, 0, 0, 0, 0);
+               tipc_link_proto_xmit(node->active_links[node->addr & 1],
+                                    STATE_MSG, 0, 0, 0, 0, 0);
                bcl->stats.sent_acks++;
        }
 }
 
 /**
- * tipc_bclink_recv_pkt - receive a broadcast packet, and deliver upwards
+ * tipc_bclink_rcv - receive a broadcast packet, and deliver upwards
  *
  * tipc_net_lock is read_locked, no other locks set
  */
-void tipc_bclink_recv_pkt(struct sk_buff *buf)
+void tipc_bclink_rcv(struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
        struct tipc_node *node;
@@ -468,7 +467,7 @@ receive:
                        spin_unlock_bh(&bc_lock);
                        tipc_node_unlock(node);
                        if (likely(msg_mcast(msg)))
-                               tipc_port_recv_mcast(buf, NULL);
+                               tipc_port_mcast_rcv(buf, NULL);
                        else
                                kfree_skb(buf);
                } else if (msg_user(msg) == MSG_BUNDLER) {
@@ -478,12 +477,12 @@ receive:
                        bcl->stats.recv_bundled += msg_msgcnt(msg);
                        spin_unlock_bh(&bc_lock);
                        tipc_node_unlock(node);
-                       tipc_link_recv_bundle(buf);
+                       tipc_link_bundle_rcv(buf);
                } else if (msg_user(msg) == MSG_FRAGMENTER) {
                        int ret;
-                       ret = tipc_link_recv_fragment(&node->bclink.reasm_head,
-                                                     &node->bclink.reasm_tail,
-                                                     &buf);
+                       ret = tipc_link_frag_rcv(&node->bclink.reasm_head,
+                                                &node->bclink.reasm_tail,
+                                                &buf);
                        if (ret == LINK_REASM_ERROR)
                                goto unlock;
                        spin_lock_bh(&bc_lock);
@@ -503,7 +502,7 @@ receive:
                        bclink_accept_pkt(node, seqno);
                        spin_unlock_bh(&bc_lock);
                        tipc_node_unlock(node);
-                       tipc_named_recv(buf);
+                       tipc_named_rcv(buf);
                } else {
                        spin_lock_bh(&bc_lock);
                        bclink_accept_pkt(node, seqno);
@@ -669,9 +668,8 @@ void tipc_bcbearer_sort(void)
        memset(bp_temp, 0, sizeof(bcbearer->bpairs_temp));
 
        for (b_index = 0; b_index < MAX_BEARERS; b_index++) {
-               struct tipc_bearer *b = &tipc_bearers[b_index];
-
-               if (!b->active || !b->nodes.count)
+               struct tipc_bearer *b = bearer_list[b_index];
+               if (!b || !b->nodes.count)
                        continue;
 
                if (!bp_temp[b->priority].primary)
@@ -785,8 +783,8 @@ void tipc_bclink_init(void)
        bcl->owner = &bclink->node;
        bcl->max_pkt = MAX_PKT_DEFAULT_MCAST;
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
-       spin_lock_init(&bcbearer->bearer.lock);
        bcl->b_ptr = &bcbearer->bearer;
+       bearer_list[BCBEARER] = &bcbearer->bearer;
        bcl->state = WORKING_WORKING;
        strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
 }
@@ -797,6 +795,7 @@ void tipc_bclink_stop(void)
        tipc_link_purge_queues(bcl);
        spin_unlock_bh(&bc_lock);
 
+       bearer_list[BCBEARER] = NULL;
        memset(bclink, 0, sizeof(*bclink));
        memset(bcbearer, 0, sizeof(*bcbearer));
 }
index 6ee587b469fd3fd9df70a7f086f1f5485dc5caa6..a80ef54b818e221a98bd9bd69a3adf28d0001f88 100644 (file)
@@ -90,8 +90,8 @@ void tipc_bclink_add_node(u32 addr);
 void tipc_bclink_remove_node(u32 addr);
 struct tipc_node *tipc_bclink_retransmit_to(void);
 void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked);
-int  tipc_bclink_send_msg(struct sk_buff *buf);
-void tipc_bclink_recv_pkt(struct sk_buff *buf);
+int  tipc_bclink_xmit(struct sk_buff *buf);
+void tipc_bclink_rcv(struct sk_buff *buf);
 u32  tipc_bclink_get_last_sent(void);
 u32  tipc_bclink_acks_missing(struct tipc_node *n_ptr);
 void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent);
index a38c89969c686128df1a556598b248a70eec665f..3fef7eb776dc12934654b2bfa7500cfa75138ad4 100644 (file)
@@ -49,9 +49,9 @@ static struct tipc_media * const media_info_array[] = {
        NULL
 };
 
-struct tipc_bearer tipc_bearers[MAX_BEARERS];
+struct tipc_bearer *bearer_list[MAX_BEARERS + 1];
 
-static void bearer_disable(struct tipc_bearer *b_ptr);
+static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down);
 
 /**
  * tipc_media_find - locates specified media object by name
@@ -177,8 +177,9 @@ struct tipc_bearer *tipc_bearer_find(const char *name)
        struct tipc_bearer *b_ptr;
        u32 i;
 
-       for (i = 0, b_ptr = tipc_bearers; i < MAX_BEARERS; i++, b_ptr++) {
-               if (b_ptr->active && (!strcmp(b_ptr->name, name)))
+       for (i = 0; i < MAX_BEARERS; i++) {
+               b_ptr = bearer_list[i];
+               if (b_ptr && (!strcmp(b_ptr->name, name)))
                        return b_ptr;
        }
        return NULL;
@@ -200,8 +201,10 @@ struct sk_buff *tipc_bearer_get_names(void)
        read_lock_bh(&tipc_net_lock);
        for (i = 0; media_info_array[i] != NULL; i++) {
                for (j = 0; j < MAX_BEARERS; j++) {
-                       b = &tipc_bearers[j];
-                       if (b->active && (b->media == media_info_array[i])) {
+                       b = bearer_list[j];
+                       if (!b)
+                               continue;
+                       if (b->media == media_info_array[i]) {
                                tipc_cfg_append_tlv(buf, TIPC_TLV_BEARER_NAME,
                                                    b->name,
                                                    strlen(b->name) + 1);
@@ -284,16 +287,17 @@ restart:
        bearer_id = MAX_BEARERS;
        with_this_prio = 1;
        for (i = MAX_BEARERS; i-- != 0; ) {
-               if (!tipc_bearers[i].active) {
+               b_ptr = bearer_list[i];
+               if (!b_ptr) {
                        bearer_id = i;
                        continue;
                }
-               if (!strcmp(name, tipc_bearers[i].name)) {
+               if (!strcmp(name, b_ptr->name)) {
                        pr_warn("Bearer <%s> rejected, already enabled\n",
                                name);
                        goto exit;
                }
-               if ((tipc_bearers[i].priority == priority) &&
+               if ((b_ptr->priority == priority) &&
                    (++with_this_prio > 2)) {
                        if (priority-- == 0) {
                                pr_warn("Bearer <%s> rejected, duplicate priority\n",
@@ -311,7 +315,11 @@ restart:
                goto exit;
        }
 
-       b_ptr = &tipc_bearers[bearer_id];
+       b_ptr = kzalloc(sizeof(*b_ptr), GFP_ATOMIC);
+       if (!b_ptr) {
+               res = -ENOMEM;
+               goto exit;
+       }
        strcpy(b_ptr->name, name);
        b_ptr->media = m_ptr;
        res = m_ptr->enable_media(b_ptr);
@@ -324,19 +332,20 @@ restart:
        b_ptr->identity = bearer_id;
        b_ptr->tolerance = m_ptr->tolerance;
        b_ptr->window = m_ptr->window;
+       b_ptr->domain = disc_domain;
        b_ptr->net_plane = bearer_id + 'A';
-       b_ptr->active = 1;
        b_ptr->priority = priority;
-       INIT_LIST_HEAD(&b_ptr->links);
-       spin_lock_init(&b_ptr->lock);
 
-       res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr, disc_domain);
+       res = tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
        if (res) {
-               bearer_disable(b_ptr);
+               bearer_disable(b_ptr, false);
                pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
                        name);
                goto exit;
        }
+
+       bearer_list[bearer_id] = b_ptr;
+
        pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
                name,
                tipc_addr_string_fill(addr_string, disc_domain), priority);
@@ -350,20 +359,11 @@ exit:
  */
 static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
 {
-       struct tipc_link *l_ptr;
-       struct tipc_link *temp_l_ptr;
-
        read_lock_bh(&tipc_net_lock);
        pr_info("Resetting bearer <%s>\n", b_ptr->name);
-       spin_lock_bh(&b_ptr->lock);
-       list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
-               struct tipc_node *n_ptr = l_ptr->owner;
-
-               spin_lock_bh(&n_ptr->lock);
-               tipc_link_reset(l_ptr);
-               spin_unlock_bh(&n_ptr->lock);
-       }
-       spin_unlock_bh(&b_ptr->lock);
+       tipc_disc_delete(b_ptr->link_req);
+       tipc_link_reset_list(b_ptr->identity);
+       tipc_disc_create(b_ptr, &b_ptr->bcast_addr);
        read_unlock_bh(&tipc_net_lock);
        return 0;
 }
@@ -373,26 +373,24 @@ static int tipc_reset_bearer(struct tipc_bearer *b_ptr)
  *
  * Note: This routine assumes caller holds tipc_net_lock.
  */
-static void bearer_disable(struct tipc_bearer *b_ptr)
+static void bearer_disable(struct tipc_bearer *b_ptr, bool shutting_down)
 {
-       struct tipc_link *l_ptr;
-       struct tipc_link *temp_l_ptr;
-       struct tipc_link_req *temp_req;
+       u32 i;
 
        pr_info("Disabling bearer <%s>\n", b_ptr->name);
-       spin_lock_bh(&b_ptr->lock);
        b_ptr->media->disable_media(b_ptr);
-       list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
-               tipc_link_delete(l_ptr);
-       }
-       temp_req = b_ptr->link_req;
-       b_ptr->link_req = NULL;
-       spin_unlock_bh(&b_ptr->lock);
 
-       if (temp_req)
-               tipc_disc_delete(temp_req);
+       tipc_link_delete_list(b_ptr->identity, shutting_down);
+       if (b_ptr->link_req)
+               tipc_disc_delete(b_ptr->link_req);
 
-       memset(b_ptr, 0, sizeof(struct tipc_bearer));
+       for (i = 0; i < MAX_BEARERS; i++) {
+               if (b_ptr == bearer_list[i]) {
+                       bearer_list[i] = NULL;
+                       break;
+               }
+       }
+       kfree(b_ptr);
 }
 
 int tipc_disable_bearer(const char *name)
@@ -406,7 +404,7 @@ int tipc_disable_bearer(const char *name)
                pr_warn("Attempt to disable unknown bearer <%s>\n", name);
                res = -EINVAL;
        } else {
-               bearer_disable(b_ptr);
+               bearer_disable(b_ptr, false);
                res = 0;
        }
        write_unlock_bh(&tipc_net_lock);
@@ -585,7 +583,11 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
                        break;
        case NETDEV_DOWN:
        case NETDEV_CHANGEMTU:
+               tipc_reset_bearer(b_ptr);
+               break;
        case NETDEV_CHANGEADDR:
+               tipc_l2_media_addr_set(b_ptr, &b_ptr->addr,
+                                      (char *)dev->dev_addr);
                tipc_reset_bearer(b_ptr);
                break;
        case NETDEV_UNREGISTER:
@@ -599,7 +601,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
 }
 
 static struct packet_type tipc_packet_type __read_mostly = {
-       .type = __constant_htons(ETH_P_TIPC),
+       .type = htons(ETH_P_TIPC),
        .func = tipc_l2_rcv_msg,
 };
 
@@ -610,8 +612,13 @@ static struct notifier_block notifier = {
 
 int tipc_bearer_setup(void)
 {
+       int err;
+
+       err = register_netdevice_notifier(&notifier);
+       if (err)
+               return err;
        dev_add_pack(&tipc_packet_type);
-       return register_netdevice_notifier(&notifier);
+       return 0;
 }
 
 void tipc_bearer_cleanup(void)
@@ -622,10 +629,14 @@ void tipc_bearer_cleanup(void)
 
 void tipc_bearer_stop(void)
 {
+       struct tipc_bearer *b_ptr;
        u32 i;
 
        for (i = 0; i < MAX_BEARERS; i++) {
-               if (tipc_bearers[i].active)
-                       bearer_disable(&tipc_bearers[i]);
+               b_ptr = bearer_list[i];
+               if (b_ptr) {
+                       bearer_disable(b_ptr, true);
+                       bearer_list[i] = NULL;
+               }
        }
 }
index 4f5db9ad5bf639056bc56f1284d7400e87095dcc..ba48145e871dd8dcd357a193b61e9234e5ad7f0d 100644 (file)
@@ -107,10 +107,8 @@ struct tipc_media {
 
 /**
  * struct tipc_bearer - Generic TIPC bearer structure
- * @dev: ptr to associated network device
- * @usr_handle: pointer to additional media-specific information about bearer
+ * @media_ptr: pointer to additional media-specific information about bearer
  * @mtu: max packet size bearer can support
- * @lock: spinlock for controlling access to bearer
  * @addr: media-specific address associated with bearer
  * @name: bearer name (format = media:interface)
  * @media: ptr to media structure associated with bearer
@@ -118,10 +116,9 @@ struct tipc_media {
  * @priority: default link priority for bearer
  * @window: default window size for bearer
  * @tolerance: default link tolerance for bearer
+ * @domain: network domain to which links can be established
  * @identity: array index of this bearer within TIPC bearer array
  * @link_req: ptr to (optional) structure making periodic link setup requests
- * @links: list of non-congested links associated with bearer
- * @active: non-zero if bearer structure is represents a bearer
  * @net_plane: network plane ('A' through 'H') currently associated with bearer
  * @nodes: indicates which nodes in cluster can be reached through bearer
  *
@@ -134,16 +131,14 @@ struct tipc_bearer {
        u32 mtu;                                /* initalized by media */
        struct tipc_media_addr addr;            /* initalized by media */
        char name[TIPC_MAX_BEARER_NAME];
-       spinlock_t lock;
        struct tipc_media *media;
        struct tipc_media_addr bcast_addr;
        u32 priority;
        u32 window;
        u32 tolerance;
+       u32 domain;
        u32 identity;
        struct tipc_link_req *link_req;
-       struct list_head links;
-       int active;
        char net_plane;
        struct tipc_node_map nodes;
 };
@@ -155,7 +150,7 @@ struct tipc_bearer_names {
 
 struct tipc_link;
 
-extern struct tipc_bearer tipc_bearers[];
+extern struct tipc_bearer *bearer_list[];
 
 /*
  * TIPC routines available to supported media types
index c301a9a592d82d570050116df07e54a4551da537..4b981c053823e90cc31963277aedd8c3682bc1a0 100644 (file)
 #define REPLY_TRUNCATED "<truncated>\n"
 
 static DEFINE_MUTEX(config_mutex);
-static struct tipc_server cfgsrv;
 
 static const void *req_tlv_area;       /* request message TLV area */
 static int req_tlv_space;              /* request message TLV area size */
 static int rep_headroom;               /* reply message headroom to use */
 
-
 struct sk_buff *tipc_cfg_reply_alloc(int payload_size)
 {
        struct sk_buff *buf;
@@ -181,19 +179,7 @@ static struct sk_buff *cfg_set_own_addr(void)
        if (tipc_own_addr)
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (cannot change node address once assigned)");
-       tipc_core_start_net(addr);
-       return tipc_cfg_reply_none();
-}
-
-static struct sk_buff *cfg_set_remote_mng(void)
-{
-       u32 value;
-
-       if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_UNSIGNED))
-               return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
-
-       value = ntohl(*(__be32 *)TLV_DATA(req_tlv_area));
-       tipc_remote_management = (value != 0);
+       tipc_net_start(addr);
        return tipc_cfg_reply_none();
 }
 
@@ -247,21 +233,10 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
        /* Check command authorization */
        if (likely(in_own_node(orig_node))) {
                /* command is permitted */
-       } else if (cmd >= 0x8000) {
+       } else {
                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                          " (cannot be done remotely)");
                goto exit;
-       } else if (!tipc_remote_management) {
-               rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NO_REMOTE);
-               goto exit;
-       } else if (cmd >= 0x4000) {
-               u32 domain = 0;
-
-               if ((tipc_nametbl_translate(TIPC_ZM_SRV, 0, &domain) == 0) ||
-                   (domain != orig_node)) {
-                       rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_ZONE_MSTR);
-                       goto exit;
-               }
        }
 
        /* Call appropriate processing routine */
@@ -310,18 +285,12 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
        case TIPC_CMD_SET_NODE_ADDR:
                rep_tlv_buf = cfg_set_own_addr();
                break;
-       case TIPC_CMD_SET_REMOTE_MNG:
-               rep_tlv_buf = cfg_set_remote_mng();
-               break;
        case TIPC_CMD_SET_MAX_PORTS:
                rep_tlv_buf = cfg_set_max_ports();
                break;
        case TIPC_CMD_SET_NETID:
                rep_tlv_buf = cfg_set_netid();
                break;
-       case TIPC_CMD_GET_REMOTE_MNG:
-               rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_remote_management);
-               break;
        case TIPC_CMD_GET_MAX_PORTS:
                rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_max_ports);
                break;
@@ -345,6 +314,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
        case TIPC_CMD_SET_MAX_PUBL:
        case TIPC_CMD_GET_MAX_PUBL:
        case TIPC_CMD_SET_LOG_SIZE:
+       case TIPC_CMD_SET_REMOTE_MNG:
+       case TIPC_CMD_GET_REMOTE_MNG:
        case TIPC_CMD_DUMP_LOG:
                rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                          " (obsolete command)");
@@ -369,80 +340,3 @@ exit:
        mutex_unlock(&config_mutex);
        return rep_tlv_buf;
 }
-
-static void cfg_conn_msg_event(int conid, struct sockaddr_tipc *addr,
-                              void *usr_data, void *buf, size_t len)
-{
-       struct tipc_cfg_msg_hdr *req_hdr;
-       struct tipc_cfg_msg_hdr *rep_hdr;
-       struct sk_buff *rep_buf;
-       int ret;
-
-       /* Validate configuration message header (ignore invalid message) */
-       req_hdr = (struct tipc_cfg_msg_hdr *)buf;
-       if ((len < sizeof(*req_hdr)) ||
-           (len != TCM_ALIGN(ntohl(req_hdr->tcm_len))) ||
-           (ntohs(req_hdr->tcm_flags) != TCM_F_REQUEST)) {
-               pr_warn("Invalid configuration message discarded\n");
-               return;
-       }
-
-       /* Generate reply for request (if can't, return request) */
-       rep_buf = tipc_cfg_do_cmd(addr->addr.id.node, ntohs(req_hdr->tcm_type),
-                                 buf + sizeof(*req_hdr),
-                                 len - sizeof(*req_hdr),
-                                 BUF_HEADROOM + MAX_H_SIZE + sizeof(*rep_hdr));
-       if (rep_buf) {
-               skb_push(rep_buf, sizeof(*rep_hdr));
-               rep_hdr = (struct tipc_cfg_msg_hdr *)rep_buf->data;
-               memcpy(rep_hdr, req_hdr, sizeof(*rep_hdr));
-               rep_hdr->tcm_len = htonl(rep_buf->len);
-               rep_hdr->tcm_flags &= htons(~TCM_F_REQUEST);
-
-               ret = tipc_conn_sendmsg(&cfgsrv, conid, addr, rep_buf->data,
-                                       rep_buf->len);
-               if (ret < 0)
-                       pr_err("Sending cfg reply message failed, no memory\n");
-
-               kfree_skb(rep_buf);
-       }
-}
-
-static struct sockaddr_tipc cfgsrv_addr __read_mostly = {
-       .family                 = AF_TIPC,
-       .addrtype               = TIPC_ADDR_NAMESEQ,
-       .addr.nameseq.type      = TIPC_CFG_SRV,
-       .addr.nameseq.lower     = 0,
-       .addr.nameseq.upper     = 0,
-       .scope                  = TIPC_ZONE_SCOPE
-};
-
-static struct tipc_server cfgsrv __read_mostly = {
-       .saddr                  = &cfgsrv_addr,
-       .imp                    = TIPC_CRITICAL_IMPORTANCE,
-       .type                   = SOCK_RDM,
-       .max_rcvbuf_size        = 64 * 1024,
-       .name                   = "cfg_server",
-       .tipc_conn_recvmsg      = cfg_conn_msg_event,
-       .tipc_conn_new          = NULL,
-       .tipc_conn_shutdown     = NULL
-};
-
-int tipc_cfg_init(void)
-{
-       return tipc_server_start(&cfgsrv);
-}
-
-void tipc_cfg_reinit(void)
-{
-       tipc_server_stop(&cfgsrv);
-
-       cfgsrv_addr.addr.nameseq.lower = tipc_own_addr;
-       cfgsrv_addr.addr.nameseq.upper = tipc_own_addr;
-       tipc_server_start(&cfgsrv);
-}
-
-void tipc_cfg_stop(void)
-{
-       tipc_server_stop(&cfgsrv);
-}
index 1f252f3fa0586b103fc129059c0df3906b1f9365..47b1bf18161215afbbe7020845c9dd92c79381bd 100644 (file)
@@ -64,9 +64,4 @@ static inline struct sk_buff *tipc_cfg_reply_ultra_string(char *string)
 struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd,
                                const void *req_tlv_area, int req_tlv_space,
                                int headroom);
-
-int  tipc_cfg_init(void);
-void tipc_cfg_reinit(void);
-void tipc_cfg_stop(void);
-
 #endif
index f9e88d8b04ca182b2e8c217e579647fbf9581e4e..50d57429ebcaf82b8d36bcf49f6fa1585664180a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/core.c: TIPC module code
  *
- * Copyright (c) 2003-2006, Ericsson AB
+ * Copyright (c) 2003-2006, 2013, Ericsson AB
  * Copyright (c) 2005-2006, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -50,7 +50,6 @@ int tipc_random __read_mostly;
 u32 tipc_own_addr __read_mostly;
 int tipc_max_ports __read_mostly;
 int tipc_net_id __read_mostly;
-int tipc_remote_management __read_mostly;
 int sysctl_tipc_rmem[3] __read_mostly; /* min/default/max */
 
 /**
@@ -76,40 +75,15 @@ struct sk_buff *tipc_buf_acquire(u32 size)
        return skb;
 }
 
-/**
- * tipc_core_stop_net - shut down TIPC networking sub-systems
- */
-static void tipc_core_stop_net(void)
-{
-       tipc_net_stop();
-       tipc_bearer_cleanup();
-}
-
-/**
- * start_net - start TIPC networking sub-systems
- */
-int tipc_core_start_net(unsigned long addr)
-{
-       int res;
-
-       tipc_net_start(addr);
-       res = tipc_bearer_setup();
-       if (res < 0)
-               goto err;
-       return res;
-
-err:
-       tipc_core_stop_net();
-       return res;
-}
-
 /**
  * tipc_core_stop - switch TIPC from SINGLE NODE to NOT RUNNING mode
  */
 static void tipc_core_stop(void)
 {
+       tipc_handler_stop();
+       tipc_net_stop();
+       tipc_bearer_cleanup();
        tipc_netlink_stop();
-       tipc_cfg_stop();
        tipc_subscr_stop();
        tipc_nametbl_stop();
        tipc_ref_table_stop();
@@ -122,30 +96,59 @@ static void tipc_core_stop(void)
  */
 static int tipc_core_start(void)
 {
-       int res;
+       int err;
 
        get_random_bytes(&tipc_random, sizeof(tipc_random));
 
-       res = tipc_handler_start();
-       if (!res)
-               res = tipc_ref_table_init(tipc_max_ports, tipc_random);
-       if (!res)
-               res = tipc_nametbl_init();
-       if (!res)
-               res = tipc_netlink_start();
-       if (!res)
-               res = tipc_socket_init();
-       if (!res)
-               res = tipc_register_sysctl();
-       if (!res)
-               res = tipc_subscr_start();
-       if (!res)
-               res = tipc_cfg_init();
-       if (res) {
-               tipc_handler_stop();
-               tipc_core_stop();
-       }
-       return res;
+       err = tipc_handler_start();
+       if (err)
+               goto out_handler;
+
+       err = tipc_ref_table_init(tipc_max_ports, tipc_random);
+       if (err)
+               goto out_reftbl;
+
+       err = tipc_nametbl_init();
+       if (err)
+               goto out_nametbl;
+
+       err = tipc_netlink_start();
+       if (err)
+               goto out_netlink;
+
+       err = tipc_socket_init();
+       if (err)
+               goto out_socket;
+
+       err = tipc_register_sysctl();
+       if (err)
+               goto out_sysctl;
+
+       err = tipc_subscr_start();
+       if (err)
+               goto out_subscr;
+
+       err = tipc_bearer_setup();
+       if (err)
+               goto out_bearer;
+
+       return 0;
+out_bearer:
+       tipc_subscr_stop();
+out_subscr:
+       tipc_unregister_sysctl();
+out_sysctl:
+       tipc_socket_stop();
+out_socket:
+       tipc_netlink_stop();
+out_netlink:
+       tipc_nametbl_stop();
+out_nametbl:
+       tipc_ref_table_stop();
+out_reftbl:
+       tipc_handler_stop();
+out_handler:
+       return err;
 }
 
 static int __init tipc_init(void)
@@ -155,7 +158,6 @@ static int __init tipc_init(void)
        pr_info("Activated (version " TIPC_MOD_VER ")\n");
 
        tipc_own_addr = 0;
-       tipc_remote_management = 1;
        tipc_max_ports = CONFIG_TIPC_PORTS;
        tipc_net_id = 4711;
 
@@ -174,8 +176,6 @@ static int __init tipc_init(void)
 
 static void __exit tipc_exit(void)
 {
-       tipc_handler_stop();
-       tipc_core_stop_net();
        tipc_core_stop();
        pr_info("Deactivated\n");
 }
index 1ff477b0450d78bacb9522105f638f6523d625f6..8985bbcb942bdb3d6ef839c3249d4e547c2f75ce 100644 (file)
@@ -79,7 +79,6 @@ int tipc_snprintf(char *buf, int len, const char *fmt, ...);
 extern u32 tipc_own_addr __read_mostly;
 extern int tipc_max_ports __read_mostly;
 extern int tipc_net_id __read_mostly;
-extern int tipc_remote_management __read_mostly;
 extern int sysctl_tipc_rmem[3] __read_mostly;
 
 /*
@@ -90,7 +89,6 @@ extern int tipc_random __read_mostly;
 /*
  * Routines available to privileged subsystems
  */
-int tipc_core_start_net(unsigned long);
 int tipc_handler_start(void);
 void tipc_handler_stop(void);
 int tipc_netlink_start(void);
@@ -192,6 +190,7 @@ static inline void k_term_timer(struct timer_list *timer)
 
 struct tipc_skb_cb {
        void *handle;
+       bool deferred;
 };
 
 #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
index 412ff41b861166e5511ae3ad8c875fa27039ac6b..542fe3413dc4e8d06d97eb2d5a409d2a7b26459a 100644 (file)
@@ -48,7 +48,6 @@
  * struct tipc_link_req - information about an ongoing link setup request
  * @bearer: bearer issuing requests
  * @dest: destination address for request messages
- * @domain: network domain to which links can be established
  * @num_nodes: number of nodes currently discovered (i.e. with an active link)
  * @lock: spinlock for controlling access to requests
  * @buf: request message to be (repeatedly) sent
@@ -58,7 +57,6 @@
 struct tipc_link_req {
        struct tipc_bearer *bearer;
        struct tipc_media_addr dest;
-       u32 domain;
        int num_nodes;
        spinlock_t lock;
        struct sk_buff *buf;
@@ -69,14 +67,13 @@ struct tipc_link_req {
 /**
  * tipc_disc_init_msg - initialize a link setup message
  * @type: message type (request or response)
- * @dest_domain: network domain of node(s) which should respond to message
  * @b_ptr: ptr to bearer issuing message
  */
-static struct sk_buff *tipc_disc_init_msg(u32 type, u32 dest_domain,
-                                         struct tipc_bearer *b_ptr)
+static struct sk_buff *tipc_disc_init_msg(u32 type, struct tipc_bearer *b_ptr)
 {
        struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE);
        struct tipc_msg *msg;
+       u32 dest_domain = b_ptr->domain;
 
        if (buf) {
                msg = buf_msg(buf);
@@ -110,11 +107,11 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
 }
 
 /**
- * tipc_disc_recv_msg - handle incoming link setup message (request or response)
+ * tipc_disc_rcv - handle incoming link setup message (request or response)
  * @buf: buffer containing message
  * @b_ptr: bearer that message arrived on
  */
-void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
+void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr)
 {
        struct tipc_node *n_ptr;
        struct tipc_link *link;
@@ -149,7 +146,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
        }
        if (!tipc_in_scope(dest, tipc_own_addr))
                return;
-       if (!tipc_in_scope(b_ptr->link_req->domain, orig))
+       if (!tipc_in_scope(b_ptr->domain, orig))
                return;
 
        /* Locate structure corresponding to requesting node */
@@ -242,7 +239,7 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr)
        link_fully_up = link_working_working(link);
 
        if ((type == DSC_REQ_MSG) && !link_fully_up) {
-               rbuf = tipc_disc_init_msg(DSC_RESP_MSG, orig, b_ptr);
+               rbuf = tipc_disc_init_msg(DSC_RESP_MSG, b_ptr);
                if (rbuf) {
                        tipc_bearer_send(b_ptr, rbuf, &media_addr);
                        kfree_skb(rbuf);
@@ -306,7 +303,7 @@ static void disc_timeout(struct tipc_link_req *req)
        spin_lock_bh(&req->lock);
 
        /* Stop searching if only desired node has been found */
-       if (tipc_node(req->domain) && req->num_nodes) {
+       if (tipc_node(req->bearer->domain) && req->num_nodes) {
                req->timer_intv = TIPC_LINK_REQ_INACTIVE;
                goto exit;
        }
@@ -342,8 +339,7 @@ exit:
  *
  * Returns 0 if successful, otherwise -errno.
  */
-int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest,
-                    u32 dest_domain)
+int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest)
 {
        struct tipc_link_req *req;
 
@@ -351,7 +347,7 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest,
        if (!req)
                return -ENOMEM;
 
-       req->buf = tipc_disc_init_msg(DSC_REQ_MSG, dest_domain, b_ptr);
+       req->buf = tipc_disc_init_msg(DSC_REQ_MSG, b_ptr);
        if (!req->buf) {
                kfree(req);
                return -ENOMSG;
@@ -359,7 +355,6 @@ int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest,
 
        memcpy(&req->dest, dest, sizeof(*dest));
        req->bearer = b_ptr;
-       req->domain = dest_domain;
        req->num_nodes = 0;
        req->timer_intv = TIPC_LINK_REQ_INIT;
        spin_lock_init(&req->lock);
index 75b67c403aa3629643fd547e4245c1c6dacbc335..07f34729459dcacb93b71d8a56c69263db5f563b 100644 (file)
 
 struct tipc_link_req;
 
-int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest,
-                    u32 dest_domain);
+int tipc_disc_create(struct tipc_bearer *b_ptr, struct tipc_media_addr *dest);
 void tipc_disc_delete(struct tipc_link_req *req);
 void tipc_disc_add_dest(struct tipc_link_req *req);
 void tipc_disc_remove_dest(struct tipc_link_req *req);
-void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr);
+void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr);
 
 #endif
index e4bc8a2967447fbde1f39d0d19146f2c7848ac99..1fabf160501f4f7b8127ef8d8a7583076e9b2eb4 100644 (file)
@@ -58,7 +58,6 @@ unsigned int tipc_k_signal(Handler routine, unsigned long argument)
 
        spin_lock_bh(&qitem_lock);
        if (!handler_enabled) {
-               pr_err("Signal request ignored by handler\n");
                spin_unlock_bh(&qitem_lock);
                return -ENOPROTOOPT;
        }
index d4b5de41b682188f1cf3bcffb08a44f38a9f84ae..c5190ab75290d04202b99a3e923a69fe1a9dad38 100644 (file)
@@ -77,19 +77,19 @@ static const char *link_unk_evt = "Unknown link event ";
 
 static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
                                       struct sk_buff *buf);
-static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf);
-static int  tipc_link_tunnel_rcv(struct tipc_link **l_ptr,
+static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf);
+static int  tipc_link_tunnel_rcv(struct tipc_node *n_ptr,
                                 struct sk_buff **buf);
 static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance);
-static int  link_send_sections_long(struct tipc_port *sender,
-                                   struct iovec const *msg_sect,
-                                   unsigned int len, u32 destnode);
+static int  tipc_link_iovec_long_xmit(struct tipc_port *sender,
+                                     struct iovec const *msg_sect,
+                                     unsigned int len, u32 destnode);
 static void link_state_event(struct tipc_link *l_ptr, u32 event);
 static void link_reset_statistics(struct tipc_link *l_ptr);
 static void link_print(struct tipc_link *l_ptr, const char *str);
-static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf);
-static void tipc_link_send_sync(struct tipc_link *l);
-static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf);
+static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf);
+static void tipc_link_sync_xmit(struct tipc_link *l);
+static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf);
 
 /*
  *  Simple link routines
@@ -147,11 +147,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr)
 /**
  * link_timeout - handle expiration of link timer
  * @l_ptr: pointer to link
- *
- * This routine must not grab "tipc_net_lock" to avoid a potential deadlock conflict
- * with tipc_link_delete().  (There is no risk that the node will be deleted by
- * another thread because tipc_link_delete() always cancels the link timer before
- * tipc_node_delete() is called.)
  */
 static void link_timeout(struct tipc_link *l_ptr)
 {
@@ -213,8 +208,8 @@ static void link_set_timer(struct tipc_link *l_ptr, u32 time)
  * Returns pointer to link.
  */
 struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
-                             struct tipc_bearer *b_ptr,
-                             const struct tipc_media_addr *media_addr)
+                                  struct tipc_bearer *b_ptr,
+                                  const struct tipc_media_addr *media_addr)
 {
        struct tipc_link *l_ptr;
        struct tipc_msg *msg;
@@ -279,41 +274,44 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
 
        k_init_timer(&l_ptr->timer, (Handler)link_timeout,
                     (unsigned long)l_ptr);
-       list_add_tail(&l_ptr->link_list, &b_ptr->links);
 
        link_state_event(l_ptr, STARTING_EVT);
 
        return l_ptr;
 }
 
-/**
- * tipc_link_delete - delete a link
- * @l_ptr: pointer to link
- *
- * Note: 'tipc_net_lock' is write_locked, bearer is locked.
- * This routine must not grab the node lock until after link timer cancellation
- * to avoid a potential deadlock situation.
- */
-void tipc_link_delete(struct tipc_link *l_ptr)
+void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down)
 {
-       if (!l_ptr) {
-               pr_err("Attempt to delete non-existent link\n");
-               return;
-       }
-
-       k_cancel_timer(&l_ptr->timer);
+       struct tipc_link *l_ptr;
+       struct tipc_node *n_ptr;
 
-       tipc_node_lock(l_ptr->owner);
-       tipc_link_reset(l_ptr);
-       tipc_node_detach_link(l_ptr->owner, l_ptr);
-       tipc_link_purge_queues(l_ptr);
-       list_del_init(&l_ptr->link_list);
-       tipc_node_unlock(l_ptr->owner);
-       k_term_timer(&l_ptr->timer);
-       kfree(l_ptr);
+       rcu_read_lock();
+       list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+               spin_lock_bh(&n_ptr->lock);
+               l_ptr = n_ptr->links[bearer_id];
+               if (l_ptr) {
+                       tipc_link_reset(l_ptr);
+                       if (shutting_down || !tipc_node_is_up(n_ptr)) {
+                               tipc_node_detach_link(l_ptr->owner, l_ptr);
+                               tipc_link_reset_fragments(l_ptr);
+                               spin_unlock_bh(&n_ptr->lock);
+
+                               /* Nobody else can access this link now: */
+                               del_timer_sync(&l_ptr->timer);
+                               kfree(l_ptr);
+                       } else {
+                               /* Detach/delete when failover is finished: */
+                               l_ptr->flags |= LINK_STOPPED;
+                               spin_unlock_bh(&n_ptr->lock);
+                               del_timer_sync(&l_ptr->timer);
+                       }
+                       continue;
+               }
+               spin_unlock_bh(&n_ptr->lock);
+       }
+       rcu_read_unlock();
 }
 
-
 /**
  * link_schedule_port - schedule port for deferred sending
  * @l_ptr: pointer to link
@@ -330,8 +328,6 @@ static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz)
        spin_lock_bh(&tipc_port_list_lock);
        p_ptr = tipc_port_lock(origport);
        if (p_ptr) {
-               if (!p_ptr->wakeup)
-                       goto exit;
                if (!list_empty(&p_ptr->wait_list))
                        goto exit;
                p_ptr->congested = 1;
@@ -366,7 +362,7 @@ void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all)
                list_del_init(&p_ptr->wait_list);
                spin_lock_bh(p_ptr->lock);
                p_ptr->congested = 0;
-               p_ptr->wakeup(p_ptr);
+               tipc_port_wakeup(p_ptr);
                win -= p_ptr->waiting_pkts;
                spin_unlock_bh(p_ptr->lock);
        }
@@ -461,6 +457,21 @@ void tipc_link_reset(struct tipc_link *l_ptr)
        link_reset_statistics(l_ptr);
 }
 
+void tipc_link_reset_list(unsigned int bearer_id)
+{
+       struct tipc_link *l_ptr;
+       struct tipc_node *n_ptr;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+               spin_lock_bh(&n_ptr->lock);
+               l_ptr = n_ptr->links[bearer_id];
+               if (l_ptr)
+                       tipc_link_reset(l_ptr);
+               spin_unlock_bh(&n_ptr->lock);
+       }
+       rcu_read_unlock();
+}
 
 static void link_activate(struct tipc_link *l_ptr)
 {
@@ -479,7 +490,10 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
        struct tipc_link *other;
        u32 cont_intv = l_ptr->continuity_interval;
 
-       if (!l_ptr->started && (event != STARTING_EVT))
+       if (l_ptr->flags & LINK_STOPPED)
+               return;
+
+       if (!(l_ptr->flags & LINK_STARTED) && (event != STARTING_EVT))
                return;         /* Not yet. */
 
        /* Check whether changeover is going on */
@@ -499,12 +513,12 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                        if (l_ptr->next_in_no != l_ptr->checkpoint) {
                                l_ptr->checkpoint = l_ptr->next_in_no;
                                if (tipc_bclink_acks_missing(l_ptr->owner)) {
-                                       tipc_link_send_proto_msg(l_ptr, STATE_MSG,
-                                                                0, 0, 0, 0, 0);
+                                       tipc_link_proto_xmit(l_ptr, STATE_MSG,
+                                                            0, 0, 0, 0, 0);
                                        l_ptr->fsm_msg_cnt++;
                                } else if (l_ptr->max_pkt < l_ptr->max_pkt_target) {
-                                       tipc_link_send_proto_msg(l_ptr, STATE_MSG,
-                                                                1, 0, 0, 0, 0);
+                                       tipc_link_proto_xmit(l_ptr, STATE_MSG,
+                                                            1, 0, 0, 0, 0);
                                        l_ptr->fsm_msg_cnt++;
                                }
                                link_set_timer(l_ptr, cont_intv);
@@ -512,7 +526,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                        }
                        l_ptr->state = WORKING_UNKNOWN;
                        l_ptr->fsm_msg_cnt = 0;
-                       tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv / 4);
                        break;
@@ -522,7 +536,8 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                        tipc_link_reset(l_ptr);
                        l_ptr->state = RESET_RESET;
                        l_ptr->fsm_msg_cnt = 0;
-                       tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
+                                            0, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv);
                        break;
@@ -544,7 +559,8 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                        tipc_link_reset(l_ptr);
                        l_ptr->state = RESET_RESET;
                        l_ptr->fsm_msg_cnt = 0;
-                       tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
+                                            0, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv);
                        break;
@@ -554,14 +570,14 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                                l_ptr->fsm_msg_cnt = 0;
                                l_ptr->checkpoint = l_ptr->next_in_no;
                                if (tipc_bclink_acks_missing(l_ptr->owner)) {
-                                       tipc_link_send_proto_msg(l_ptr, STATE_MSG,
-                                                                0, 0, 0, 0, 0);
+                                       tipc_link_proto_xmit(l_ptr, STATE_MSG,
+                                                            0, 0, 0, 0, 0);
                                        l_ptr->fsm_msg_cnt++;
                                }
                                link_set_timer(l_ptr, cont_intv);
                        } else if (l_ptr->fsm_msg_cnt < l_ptr->abort_limit) {
-                               tipc_link_send_proto_msg(l_ptr, STATE_MSG,
-                                                        1, 0, 0, 0, 0);
+                               tipc_link_proto_xmit(l_ptr, STATE_MSG,
+                                                    1, 0, 0, 0, 0);
                                l_ptr->fsm_msg_cnt++;
                                link_set_timer(l_ptr, cont_intv / 4);
                        } else {        /* Link has failed */
@@ -570,8 +586,8 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                                tipc_link_reset(l_ptr);
                                l_ptr->state = RESET_UNKNOWN;
                                l_ptr->fsm_msg_cnt = 0;
-                               tipc_link_send_proto_msg(l_ptr, RESET_MSG,
-                                                        0, 0, 0, 0, 0);
+                               tipc_link_proto_xmit(l_ptr, RESET_MSG,
+                                                    0, 0, 0, 0, 0);
                                l_ptr->fsm_msg_cnt++;
                                link_set_timer(l_ptr, cont_intv);
                        }
@@ -591,24 +607,25 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                        l_ptr->state = WORKING_WORKING;
                        l_ptr->fsm_msg_cnt = 0;
                        link_activate(l_ptr);
-                       tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        if (l_ptr->owner->working_links == 1)
-                               tipc_link_send_sync(l_ptr);
+                               tipc_link_sync_xmit(l_ptr);
                        link_set_timer(l_ptr, cont_intv);
                        break;
                case RESET_MSG:
                        l_ptr->state = RESET_RESET;
                        l_ptr->fsm_msg_cnt = 0;
-                       tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
+                                            1, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv);
                        break;
                case STARTING_EVT:
-                       l_ptr->started = 1;
+                       l_ptr->flags |= LINK_STARTED;
                        /* fall through */
                case TIMEOUT_EVT:
-                       tipc_link_send_proto_msg(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv);
                        break;
@@ -626,16 +643,17 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
                        l_ptr->state = WORKING_WORKING;
                        l_ptr->fsm_msg_cnt = 0;
                        link_activate(l_ptr);
-                       tipc_link_send_proto_msg(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        if (l_ptr->owner->working_links == 1)
-                               tipc_link_send_sync(l_ptr);
+                               tipc_link_sync_xmit(l_ptr);
                        link_set_timer(l_ptr, cont_intv);
                        break;
                case RESET_MSG:
                        break;
                case TIMEOUT_EVT:
-                       tipc_link_send_proto_msg(l_ptr, ACTIVATE_MSG, 0, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG,
+                                            0, 0, 0, 0, 0);
                        l_ptr->fsm_msg_cnt++;
                        link_set_timer(l_ptr, cont_intv);
                        break;
@@ -721,11 +739,11 @@ static void link_add_chain_to_outqueue(struct tipc_link *l_ptr,
 }
 
 /*
- * tipc_link_send_buf() is the 'full path' for messages, called from
- * inside TIPC when the 'fast path' in tipc_send_buf
+ * tipc_link_xmit() is the 'full path' for messages, called from
+ * inside TIPC when the 'fast path' in tipc_send_xmit
  * has failed, and from link_send()
  */
-int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
+int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
        u32 size = msg_size(msg);
@@ -753,7 +771,7 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
 
        /* Fragmentation needed ? */
        if (size > max_packet)
-               return link_send_long_buf(l_ptr, buf);
+               return tipc_link_frag_xmit(l_ptr, buf);
 
        /* Packet can be queued or sent. */
        if (likely(!link_congested(l_ptr))) {
@@ -797,11 +815,11 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
 }
 
 /*
- * tipc_link_send(): same as tipc_link_send_buf(), but the link to use has
- * not been selected yet, and the the owner node is not locked
+ * tipc_link_xmit(): same as __tipc_link_xmit(), but the link to use
+ * has not been selected yet, and the the owner node is not locked
  * Called by TIPC internal users, e.g. the name distributor
  */
-int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
+int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector)
 {
        struct tipc_link *l_ptr;
        struct tipc_node *n_ptr;
@@ -813,7 +831,7 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
                tipc_node_lock(n_ptr);
                l_ptr = n_ptr->active_links[selector & 1];
                if (l_ptr)
-                       res = tipc_link_send_buf(l_ptr, buf);
+                       res = __tipc_link_xmit(l_ptr, buf);
                else
                        kfree_skb(buf);
                tipc_node_unlock(n_ptr);
@@ -825,14 +843,14 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)
 }
 
 /*
- * tipc_link_send_sync - synchronize broadcast link endpoints.
+ * tipc_link_sync_xmit - synchronize broadcast link endpoints.
  *
  * Give a newly added peer node the sequence number where it should
  * start receiving and acking broadcast packets.
  *
  * Called with node locked
  */
-static void tipc_link_send_sync(struct tipc_link *l)
+static void tipc_link_sync_xmit(struct tipc_link *l)
 {
        struct sk_buff *buf;
        struct tipc_msg *msg;
@@ -849,14 +867,14 @@ static void tipc_link_send_sync(struct tipc_link *l)
 }
 
 /*
- * tipc_link_recv_sync - synchronize broadcast link endpoints.
+ * tipc_link_sync_rcv - synchronize broadcast link endpoints.
  * Receive the sequence number where we should start receiving and
  * acking broadcast packets from a newly added peer node, and open
  * up for reception of such packets.
  *
  * Called with node locked
  */
-static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf)
+static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
 
@@ -866,7 +884,7 @@ static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf)
 }
 
 /*
- * tipc_link_send_names - send name table entries to new neighbor
+ * tipc_link_names_xmit - send name table entries to new neighbor
  *
  * Send routine for bulk delivery of name table messages when contact
  * with a new neighbor occurs. No link congestion checking is performed
@@ -874,7 +892,7 @@ static void tipc_link_recv_sync(struct tipc_node *n, struct sk_buff *buf)
  * small enough not to require fragmentation.
  * Called without any locks held.
  */
-void tipc_link_send_names(struct list_head *message_list, u32 dest)
+void tipc_link_names_xmit(struct list_head *message_list, u32 dest)
 {
        struct tipc_node *n_ptr;
        struct tipc_link *l_ptr;
@@ -909,13 +927,13 @@ void tipc_link_send_names(struct list_head *message_list, u32 dest)
 }
 
 /*
- * link_send_buf_fast: Entry for data messages where the
+ * tipc_link_xmit_fast: Entry for data messages where the
  * destination link is known and the header is complete,
  * inclusive total message length. Very time critical.
  * Link is locked. Returns user data length.
  */
-static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
-                             u32 *used_max_pkt)
+static int tipc_link_xmit_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
+                              u32 *used_max_pkt)
 {
        struct tipc_msg *msg = buf_msg(buf);
        int res = msg_data_sz(msg);
@@ -931,18 +949,18 @@ static int link_send_buf_fast(struct tipc_link *l_ptr, struct sk_buff *buf,
                else
                        *used_max_pkt = l_ptr->max_pkt;
        }
-       return tipc_link_send_buf(l_ptr, buf);  /* All other cases */
+       return __tipc_link_xmit(l_ptr, buf);  /* All other cases */
 }
 
 /*
- * tipc_link_send_sections_fast: Entry for messages where the
+ * tipc_link_iovec_xmit_fast: Entry for messages where the
  * destination processor is known and the header is complete,
  * except for total message length.
  * Returns user data length or errno.
  */
-int tipc_link_send_sections_fast(struct tipc_port *sender,
-                                struct iovec const *msg_sect,
-                                unsigned int len, u32 destaddr)
+int tipc_link_iovec_xmit_fast(struct tipc_port *sender,
+                             struct iovec const *msg_sect,
+                             unsigned int len, u32 destaddr)
 {
        struct tipc_msg *hdr = &sender->phdr;
        struct tipc_link *l_ptr;
@@ -968,8 +986,8 @@ again:
                l_ptr = node->active_links[selector];
                if (likely(l_ptr)) {
                        if (likely(buf)) {
-                               res = link_send_buf_fast(l_ptr, buf,
-                                                        &sender->max_pkt);
+                               res = tipc_link_xmit_fast(l_ptr, buf,
+                                                         &sender->max_pkt);
 exit:
                                tipc_node_unlock(node);
                                read_unlock_bh(&tipc_net_lock);
@@ -995,24 +1013,21 @@ exit:
                        if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
                                goto again;
 
-                       return link_send_sections_long(sender, msg_sect, len,
-                                                      destaddr);
+                       return tipc_link_iovec_long_xmit(sender, msg_sect,
+                                                        len, destaddr);
                }
                tipc_node_unlock(node);
        }
        read_unlock_bh(&tipc_net_lock);
 
        /* Couldn't find a link to the destination node */
-       if (buf)
-               return tipc_reject_msg(buf, TIPC_ERR_NO_NODE);
-       if (res >= 0)
-               return tipc_port_reject_sections(sender, hdr, msg_sect,
-                                                len, TIPC_ERR_NO_NODE);
-       return res;
+       kfree_skb(buf);
+       tipc_port_iovec_reject(sender, hdr, msg_sect, len, TIPC_ERR_NO_NODE);
+       return -ENETUNREACH;
 }
 
 /*
- * link_send_sections_long(): Entry for long messages where the
+ * tipc_link_iovec_long_xmit(): Entry for long messages where the
  * destination node is known and the header is complete,
  * inclusive total message length.
  * Link and bearer congestion status have been checked to be ok,
@@ -1025,9 +1040,9 @@ exit:
  *
  * Returns user data length or errno.
  */
-static int link_send_sections_long(struct tipc_port *sender,
-                                  struct iovec const *msg_sect,
-                                  unsigned int len, u32 destaddr)
+static int tipc_link_iovec_long_xmit(struct tipc_port *sender,
+                                    struct iovec const *msg_sect,
+                                    unsigned int len, u32 destaddr)
 {
        struct tipc_link *l_ptr;
        struct tipc_node *node;
@@ -1146,8 +1161,9 @@ error:
        } else {
 reject:
                kfree_skb_list(buf_chain);
-               return tipc_port_reject_sections(sender, hdr, msg_sect,
-                                                len, TIPC_ERR_NO_NODE);
+               tipc_port_iovec_reject(sender, hdr, msg_sect, len,
+                                      TIPC_ERR_NO_NODE);
+               return -ENETUNREACH;
        }
 
        /* Append chain of fragments to send queue & send them */
@@ -1391,6 +1407,12 @@ static int link_recv_buf_validate(struct sk_buff *buf)
        u32 hdr_size;
        u32 min_hdr_size;
 
+       /* If this packet comes from the defer queue, the skb has already
+        * been validated
+        */
+       if (unlikely(TIPC_SKB_CB(buf)->deferred))
+               return 1;
+
        if (unlikely(buf->len < MIN_H_SIZE))
                return 0;
 
@@ -1435,15 +1457,10 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                u32 seq_no;
                u32 ackd;
                u32 released = 0;
-               int type;
 
                head = head->next;
                buf->next = NULL;
 
-               /* Ensure bearer is still enabled */
-               if (unlikely(!b_ptr->active))
-                       goto discard;
-
                /* Ensure message is well-formed */
                if (unlikely(!link_recv_buf_validate(buf)))
                        goto discard;
@@ -1457,9 +1474,9 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
 
                if (unlikely(msg_non_seq(msg))) {
                        if (msg_user(msg) ==  LINK_CONFIG)
-                               tipc_disc_recv_msg(buf, b_ptr);
+                               tipc_disc_rcv(buf, b_ptr);
                        else
-                               tipc_bclink_recv_pkt(buf);
+                               tipc_bclink_rcv(buf);
                        continue;
                }
 
@@ -1483,7 +1500,7 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                if ((n_ptr->block_setup & WAIT_PEER_DOWN) &&
                        msg_user(msg) == LINK_PROTOCOL &&
                        (msg_type(msg) == RESET_MSG ||
-                                       msg_type(msg) == ACTIVATE_MSG) &&
+                        msg_type(msg) == ACTIVATE_MSG) &&
                        !msg_redundant_link(msg))
                        n_ptr->block_setup &= ~WAIT_PEER_DOWN;
 
@@ -1502,7 +1519,6 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                while ((crs != l_ptr->next_out) &&
                       less_eq(buf_seqno(crs), ackd)) {
                        struct sk_buff *next = crs->next;
-
                        kfree_skb(crs);
                        crs = next;
                        released++;
@@ -1515,18 +1531,19 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
                /* Try sending any messages link endpoint has pending */
                if (unlikely(l_ptr->next_out))
                        tipc_link_push_queue(l_ptr);
+
                if (unlikely(!list_empty(&l_ptr->waiting_ports)))
                        tipc_link_wakeup_ports(l_ptr, 0);
+
                if (unlikely(++l_ptr->unacked_window >= TIPC_MIN_LINK_WIN)) {
                        l_ptr->stats.sent_acks++;
-                       tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
                }
 
-               /* Now (finally!) process the incoming message */
-protocol_check:
+               /* Process the incoming packet */
                if (unlikely(!link_working_working(l_ptr))) {
                        if (msg_user(msg) == LINK_PROTOCOL) {
-                               link_recv_proto_msg(l_ptr, buf);
+                               tipc_link_proto_rcv(l_ptr, buf);
                                head = link_insert_deferred_queue(l_ptr, head);
                                tipc_node_unlock(n_ptr);
                                continue;
@@ -1555,67 +1572,65 @@ protocol_check:
                l_ptr->next_in_no++;
                if (unlikely(l_ptr->oldest_deferred_in))
                        head = link_insert_deferred_queue(l_ptr, head);
-deliver:
-               if (likely(msg_isdata(msg))) {
-                       tipc_node_unlock(n_ptr);
-                       tipc_port_recv_msg(buf);
-                       continue;
+
+               /* Deliver packet/message to correct user: */
+               if (unlikely(msg_user(msg) ==  CHANGEOVER_PROTOCOL)) {
+                       if (!tipc_link_tunnel_rcv(n_ptr, &buf)) {
+                               tipc_node_unlock(n_ptr);
+                               continue;
+                       }
+                       msg = buf_msg(buf);
+               } else if (msg_user(msg) == MSG_FRAGMENTER) {
+                       int rc;
+
+                       l_ptr->stats.recv_fragments++;
+                       rc = tipc_link_frag_rcv(&l_ptr->reasm_head,
+                                               &l_ptr->reasm_tail,
+                                               &buf);
+                       if (rc == LINK_REASM_COMPLETE) {
+                               l_ptr->stats.recv_fragmented++;
+                               msg = buf_msg(buf);
+                       } else {
+                               if (rc == LINK_REASM_ERROR)
+                                       tipc_link_reset(l_ptr);
+                               tipc_node_unlock(n_ptr);
+                               continue;
+                       }
                }
+
                switch (msg_user(msg)) {
-                       int ret;
+               case TIPC_LOW_IMPORTANCE:
+               case TIPC_MEDIUM_IMPORTANCE:
+               case TIPC_HIGH_IMPORTANCE:
+               case TIPC_CRITICAL_IMPORTANCE:
+                       tipc_node_unlock(n_ptr);
+                       tipc_port_rcv(buf);
+                       continue;
                case MSG_BUNDLER:
                        l_ptr->stats.recv_bundles++;
                        l_ptr->stats.recv_bundled += msg_msgcnt(msg);
                        tipc_node_unlock(n_ptr);
-                       tipc_link_recv_bundle(buf);
+                       tipc_link_bundle_rcv(buf);
                        continue;
                case NAME_DISTRIBUTOR:
                        n_ptr->bclink.recv_permitted = true;
                        tipc_node_unlock(n_ptr);
-                       tipc_named_recv(buf);
-                       continue;
-               case BCAST_PROTOCOL:
-                       tipc_link_recv_sync(n_ptr, buf);
-                       tipc_node_unlock(n_ptr);
+                       tipc_named_rcv(buf);
                        continue;
                case CONN_MANAGER:
                        tipc_node_unlock(n_ptr);
-                       tipc_port_recv_proto_msg(buf);
-                       continue;
-               case MSG_FRAGMENTER:
-                       l_ptr->stats.recv_fragments++;
-                       ret = tipc_link_recv_fragment(&l_ptr->reasm_head,
-                                                     &l_ptr->reasm_tail,
-                                                     &buf);
-                       if (ret == LINK_REASM_COMPLETE) {
-                               l_ptr->stats.recv_fragmented++;
-                               msg = buf_msg(buf);
-                               goto deliver;
-                       }
-                       if (ret == LINK_REASM_ERROR)
-                               tipc_link_reset(l_ptr);
-                       tipc_node_unlock(n_ptr);
+                       tipc_port_proto_rcv(buf);
                        continue;
-               case CHANGEOVER_PROTOCOL:
-                       type = msg_type(msg);
-                       if (tipc_link_tunnel_rcv(&l_ptr, &buf)) {
-                               msg = buf_msg(buf);
-                               seq_no = msg_seqno(msg);
-                               if (type == ORIGINAL_MSG)
-                                       goto deliver;
-                               goto protocol_check;
-                       }
+               case BCAST_PROTOCOL:
+                       tipc_link_sync_rcv(n_ptr, buf);
                        break;
                default:
                        kfree_skb(buf);
-                       buf = NULL;
                        break;
                }
                tipc_node_unlock(n_ptr);
-               tipc_net_route_msg(buf);
                continue;
 unlock_discard:
-
                tipc_node_unlock(n_ptr);
 discard:
                kfree_skb(buf);
@@ -1682,7 +1697,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
        u32 seq_no = buf_seqno(buf);
 
        if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) {
-               link_recv_proto_msg(l_ptr, buf);
+               tipc_link_proto_rcv(l_ptr, buf);
                return;
        }
 
@@ -1703,8 +1718,9 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
                                &l_ptr->newest_deferred_in, buf)) {
                l_ptr->deferred_inqueue_sz++;
                l_ptr->stats.deferred_recv++;
+               TIPC_SKB_CB(buf)->deferred = true;
                if ((l_ptr->deferred_inqueue_sz % 16) == 1)
-                       tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
+                       tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0, 0);
        } else
                l_ptr->stats.duplicates++;
 }
@@ -1712,9 +1728,8 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,
 /*
  * Send protocol message to the other endpoint.
  */
-void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ,
-                             int probe_msg, u32 gap, u32 tolerance,
-                             u32 priority, u32 ack_mtu)
+void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg,
+                         u32 gap, u32 tolerance, u32 priority, u32 ack_mtu)
 {
        struct sk_buff *buf = NULL;
        struct tipc_msg *msg = l_ptr->pmsg;
@@ -1813,7 +1828,7 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ,
  * Note that network plane id propagates through the network, and may
  * change at any time. The node with lowest address rules
  */
-static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf)
+static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
 {
        u32 rec_gap = 0;
        u32 max_pkt_info;
@@ -1932,8 +1947,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf)
                                                      msg_last_bcast(msg));
 
                if (rec_gap || (msg_probe(msg))) {
-                       tipc_link_send_proto_msg(l_ptr, STATE_MSG,
-                                                0, rec_gap, 0, 0, max_pkt_ack);
+                       tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, rec_gap, 0,
+                                            0, max_pkt_ack);
                }
                if (msg_seq_gap(msg)) {
                        l_ptr->stats.recv_nacks++;
@@ -1972,7 +1987,7 @@ static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr,
        }
        skb_copy_to_linear_data(buf, tunnel_hdr, INT_H_SIZE);
        skb_copy_to_linear_data_offset(buf, INT_H_SIZE, msg, length);
-       tipc_link_send_buf(tunnel, buf);
+       __tipc_link_xmit(tunnel, buf);
 }
 
 
@@ -2005,7 +2020,7 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr)
                if (buf) {
                        skb_copy_to_linear_data(buf, &tunnel_hdr, INT_H_SIZE);
                        msg_set_size(&tunnel_hdr, INT_H_SIZE);
-                       tipc_link_send_buf(tunnel, buf);
+                       __tipc_link_xmit(tunnel, buf);
                } else {
                        pr_warn("%sunable to send changeover msg\n",
                                link_co_err);
@@ -2039,7 +2054,7 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr)
        }
 }
 
-/* tipc_link_dup_send_queue(): A second link has become active. Tunnel a
+/* tipc_link_dup_queue_xmit(): A second link has become active. Tunnel a
  * duplicate of the first link's send queue via the new link. This way, we
  * are guaranteed that currently queued packets from a socket are delivered
  * before future traffic from the same socket, even if this is using the
@@ -2048,7 +2063,7 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr)
  * and sequence order is preserved per sender/receiver socket pair.
  * Owner node is locked.
  */
-void tipc_link_dup_send_queue(struct tipc_link *l_ptr,
+void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr,
                              struct tipc_link *tunnel)
 {
        struct sk_buff *iter;
@@ -2078,7 +2093,7 @@ void tipc_link_dup_send_queue(struct tipc_link *l_ptr,
                skb_copy_to_linear_data(outbuf, &tunnel_hdr, INT_H_SIZE);
                skb_copy_to_linear_data_offset(outbuf, INT_H_SIZE, iter->data,
                                               length);
-               tipc_link_send_buf(tunnel, outbuf);
+               __tipc_link_xmit(tunnel, outbuf);
                if (!tipc_link_is_up(l_ptr))
                        return;
                iter = iter->next;
@@ -2105,89 +2120,114 @@ static struct sk_buff *buf_extract(struct sk_buff *skb, u32 from_pos)
        return eb;
 }
 
-/*  tipc_link_tunnel_rcv(): Receive a tunneled packet, sent
- *  via other link as result of a failover (ORIGINAL_MSG) or
- *  a new active link (DUPLICATE_MSG). Failover packets are
- *  returned to the active link for delivery upwards.
+
+
+/* tipc_link_dup_rcv(): Receive a tunnelled DUPLICATE_MSG packet.
+ * Owner node is locked.
+ */
+static void tipc_link_dup_rcv(struct tipc_link *l_ptr,
+                             struct sk_buff *t_buf)
+{
+       struct sk_buff *buf;
+
+       if (!tipc_link_is_up(l_ptr))
+               return;
+
+       buf = buf_extract(t_buf, INT_H_SIZE);
+       if (buf == NULL) {
+               pr_warn("%sfailed to extract inner dup pkt\n", link_co_err);
+               return;
+       }
+
+       /* Add buffer to deferred queue, if applicable: */
+       link_handle_out_of_seq_msg(l_ptr, buf);
+}
+
+/*  tipc_link_failover_rcv(): Receive a tunnelled ORIGINAL_MSG packet
  *  Owner node is locked.
  */
-static int tipc_link_tunnel_rcv(struct tipc_link **l_ptr,
-                               struct sk_buff **buf)
+static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr,
+                                             struct sk_buff *t_buf)
 {
-       struct sk_buff *tunnel_buf = *buf;
-       struct tipc_link *dest_link;
+       struct tipc_msg *t_msg = buf_msg(t_buf);
+       struct sk_buff *buf = NULL;
        struct tipc_msg *msg;
-       struct tipc_msg *tunnel_msg = buf_msg(tunnel_buf);
-       u32 msg_typ = msg_type(tunnel_msg);
-       u32 msg_count = msg_msgcnt(tunnel_msg);
-       u32 bearer_id = msg_bearer_id(tunnel_msg);
 
-       if (bearer_id >= MAX_BEARERS)
-               goto exit;
-       dest_link = (*l_ptr)->owner->links[bearer_id];
-       if (!dest_link)
-               goto exit;
-       if (dest_link == *l_ptr) {
-               pr_err("Unexpected changeover message on link <%s>\n",
-                      (*l_ptr)->name);
-               goto exit;
-       }
-       *l_ptr = dest_link;
-       msg = msg_get_wrapped(tunnel_msg);
+       if (tipc_link_is_up(l_ptr))
+               tipc_link_reset(l_ptr);
 
-       if (msg_typ == DUPLICATE_MSG) {
-               if (less(msg_seqno(msg), mod(dest_link->next_in_no)))
-                       goto exit;
-               *buf = buf_extract(tunnel_buf, INT_H_SIZE);
-               if (*buf == NULL) {
-                       pr_warn("%sduplicate msg dropped\n", link_co_err);
+       /* First failover packet? */
+       if (l_ptr->exp_msg_count == START_CHANGEOVER)
+               l_ptr->exp_msg_count = msg_msgcnt(t_msg);
+
+       /* Should there be an inner packet? */
+       if (l_ptr->exp_msg_count) {
+               l_ptr->exp_msg_count--;
+               buf = buf_extract(t_buf, INT_H_SIZE);
+               if (buf == NULL) {
+                       pr_warn("%sno inner failover pkt\n", link_co_err);
                        goto exit;
                }
-               kfree_skb(tunnel_buf);
-               return 1;
-       }
+               msg = buf_msg(buf);
 
-       /* First original message ?: */
-       if (tipc_link_is_up(dest_link)) {
-               pr_info("%s<%s>, changeover initiated by peer\n", link_rst_msg,
-                       dest_link->name);
-               tipc_link_reset(dest_link);
-               dest_link->exp_msg_count = msg_count;
-               if (!msg_count)
-                       goto exit;
-       } else if (dest_link->exp_msg_count == START_CHANGEOVER) {
-               dest_link->exp_msg_count = msg_count;
-               if (!msg_count)
+               if (less(msg_seqno(msg), l_ptr->reset_checkpoint)) {
+                       kfree_skb(buf);
+                       buf = NULL;
                        goto exit;
+               }
+               if (msg_user(msg) == MSG_FRAGMENTER) {
+                       l_ptr->stats.recv_fragments++;
+                       tipc_link_frag_rcv(&l_ptr->reasm_head,
+                                          &l_ptr->reasm_tail,
+                                          &buf);
+               }
        }
+exit:
+       if ((l_ptr->exp_msg_count == 0) && (l_ptr->flags & LINK_STOPPED)) {
+               tipc_node_detach_link(l_ptr->owner, l_ptr);
+               kfree(l_ptr);
+       }
+       return buf;
+}
+
+/*  tipc_link_tunnel_rcv(): Receive a tunnelled packet, sent
+ *  via other link as result of a failover (ORIGINAL_MSG) or
+ *  a new active link (DUPLICATE_MSG). Failover packets are
+ *  returned to the active link for delivery upwards.
+ *  Owner node is locked.
+ */
+static int tipc_link_tunnel_rcv(struct tipc_node *n_ptr,
+                               struct sk_buff **buf)
+{
+       struct sk_buff *t_buf = *buf;
+       struct tipc_link *l_ptr;
+       struct tipc_msg *t_msg = buf_msg(t_buf);
+       u32 bearer_id = msg_bearer_id(t_msg);
+
+       *buf = NULL;
 
-       /* Receive original message */
-       if (dest_link->exp_msg_count == 0) {
-               pr_warn("%sgot too many tunnelled messages\n", link_co_err);
+       if (bearer_id >= MAX_BEARERS)
                goto exit;
-       }
-       dest_link->exp_msg_count--;
-       if (less(msg_seqno(msg), dest_link->reset_checkpoint)) {
+
+       l_ptr = n_ptr->links[bearer_id];
+       if (!l_ptr)
                goto exit;
-       } else {
-               *buf = buf_extract(tunnel_buf, INT_H_SIZE);
-               if (*buf != NULL) {
-                       kfree_skb(tunnel_buf);
-                       return 1;
-               } else {
-                       pr_warn("%soriginal msg dropped\n", link_co_err);
-               }
-       }
+
+       if (msg_type(t_msg) == DUPLICATE_MSG)
+               tipc_link_dup_rcv(l_ptr, t_buf);
+       else if (msg_type(t_msg) == ORIGINAL_MSG)
+               *buf = tipc_link_failover_rcv(l_ptr, t_buf);
+       else
+               pr_warn("%sunknown tunnel pkt received\n", link_co_err);
 exit:
-       *buf = NULL;
-       kfree_skb(tunnel_buf);
-       return 0;
+       kfree_skb(t_buf);
+       return *buf != NULL;
 }
 
 /*
  *  Bundler functionality:
  */
-void tipc_link_recv_bundle(struct sk_buff *buf)
+void tipc_link_bundle_rcv(struct sk_buff *buf)
 {
        u32 msgcount = msg_msgcnt(buf_msg(buf));
        u32 pos = INT_H_SIZE;
@@ -2210,11 +2250,11 @@ void tipc_link_recv_bundle(struct sk_buff *buf)
  */
 
 /*
- * link_send_long_buf: Entry for buffers needing fragmentation.
+ * tipc_link_frag_xmit: Entry for buffers needing fragmentation.
  * The buffer is complete, inclusive total message length.
  * Returns user data length.
  */
-static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
+static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf)
 {
        struct sk_buff *buf_chain = NULL;
        struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain;
@@ -2277,12 +2317,11 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf)
        return dsz;
 }
 
-/*
- * tipc_link_recv_fragment(): Called with node lock on. Returns
+/* tipc_link_frag_rcv(): Called with node lock on. Returns
  * the reassembled buffer if message is complete.
  */
-int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail,
-                           struct sk_buff **fbuf)
+int tipc_link_frag_rcv(struct sk_buff **head, struct sk_buff **tail,
+                      struct sk_buff **fbuf)
 {
        struct sk_buff *frag = *fbuf;
        struct tipc_msg *msg = buf_msg(frag);
@@ -2296,6 +2335,7 @@ int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail,
                        goto out_free;
                *head = frag;
                skb_frag_list_init(*head);
+               *fbuf = NULL;
                return 0;
        } else if (*head &&
                   skb_try_coalesce(*head, frag, &headstolen, &delta)) {
@@ -2315,10 +2355,12 @@ int tipc_link_recv_fragment(struct sk_buff **head, struct sk_buff **tail,
                *tail = *head = NULL;
                return LINK_REASM_COMPLETE;
        }
+       *fbuf = NULL;
        return 0;
 out_free:
        pr_warn_ratelimited("Link unable to reassemble fragmented message\n");
        kfree_skb(*fbuf);
+       *fbuf = NULL;
        return LINK_REASM_ERROR;
 }
 
@@ -2352,35 +2394,41 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window)
        l_ptr->queue_limit[MSG_FRAGMENTER] = 4000;
 }
 
-/**
- * link_find_link - locate link by name
- * @name: ptr to link name string
- * @node: ptr to area to be filled with ptr to associated node
- *
+/* tipc_link_find_owner - locate owner node of link by link's name
+ * @name: pointer to link name string
+ * @bearer_id: pointer to index in 'node->links' array where the link was found.
  * Caller must hold 'tipc_net_lock' to ensure node and bearer are not deleted;
  * this also prevents link deletion.
  *
- * Returns pointer to link (or 0 if invalid link name).
+ * Returns pointer to node owning the link, or 0 if no matching link is found.
  */
-static struct tipc_link *link_find_link(const char *name,
-                                       struct tipc_node **node)
+static struct tipc_node *tipc_link_find_owner(const char *link_name,
+                                             unsigned int *bearer_id)
 {
        struct tipc_link *l_ptr;
        struct tipc_node *n_ptr;
+       struct tipc_node *found_node = 0;
        int i;
 
-       list_for_each_entry(n_ptr, &tipc_node_list, list) {
+       *bearer_id = 0;
+       rcu_read_lock();
+       list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+               tipc_node_lock(n_ptr);
                for (i = 0; i < MAX_BEARERS; i++) {
                        l_ptr = n_ptr->links[i];
-                       if (l_ptr && !strcmp(l_ptr->name, name))
-                               goto found;
+                       if (l_ptr && !strcmp(l_ptr->name, link_name)) {
+                               *bearer_id = i;
+                               found_node = n_ptr;
+                               break;
+                       }
                }
+               tipc_node_unlock(n_ptr);
+               if (found_node)
+                       break;
        }
-       l_ptr = NULL;
-       n_ptr = NULL;
-found:
-       *node = n_ptr;
-       return l_ptr;
+       rcu_read_unlock();
+
+       return found_node;
 }
 
 /**
@@ -2422,32 +2470,33 @@ static int link_cmd_set_value(const char *name, u32 new_value, u16 cmd)
        struct tipc_link *l_ptr;
        struct tipc_bearer *b_ptr;
        struct tipc_media *m_ptr;
+       int bearer_id;
        int res = 0;
 
-       l_ptr = link_find_link(name, &node);
-       if (l_ptr) {
-               /*
-                * acquire node lock for tipc_link_send_proto_msg().
-                * see "TIPC locking policy" in net.c.
-                */
+       node = tipc_link_find_owner(name, &bearer_id);
+       if (node) {
                tipc_node_lock(node);
-               switch (cmd) {
-               case TIPC_CMD_SET_LINK_TOL:
-                       link_set_supervision_props(l_ptr, new_value);
-                       tipc_link_send_proto_msg(l_ptr,
-                               STATE_MSG, 0, 0, new_value, 0, 0);
-                       break;
-               case TIPC_CMD_SET_LINK_PRI:
-                       l_ptr->priority = new_value;
-                       tipc_link_send_proto_msg(l_ptr,
-                               STATE_MSG, 0, 0, 0, new_value, 0);
-                       break;
-               case TIPC_CMD_SET_LINK_WINDOW:
-                       tipc_link_set_queue_limits(l_ptr, new_value);
-                       break;
-               default:
-                       res = -EINVAL;
-                       break;
+               l_ptr = node->links[bearer_id];
+
+               if (l_ptr) {
+                       switch (cmd) {
+                       case TIPC_CMD_SET_LINK_TOL:
+                               link_set_supervision_props(l_ptr, new_value);
+                               tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0,
+                                                    new_value, 0, 0);
+                               break;
+                       case TIPC_CMD_SET_LINK_PRI:
+                               l_ptr->priority = new_value;
+                               tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0,
+                                                    0, new_value, 0);
+                               break;
+                       case TIPC_CMD_SET_LINK_WINDOW:
+                               tipc_link_set_queue_limits(l_ptr, new_value);
+                               break;
+                       default:
+                               res = -EINVAL;
+                               break;
+                       }
                }
                tipc_node_unlock(node);
                return res;
@@ -2542,6 +2591,7 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
        char *link_name;
        struct tipc_link *l_ptr;
        struct tipc_node *node;
+       unsigned int bearer_id;
 
        if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
                return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
@@ -2552,15 +2602,19 @@ struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_
                        return tipc_cfg_reply_error_string("link not found");
                return tipc_cfg_reply_none();
        }
-
        read_lock_bh(&tipc_net_lock);
-       l_ptr = link_find_link(link_name, &node);
-       if (!l_ptr) {
+       node = tipc_link_find_owner(link_name, &bearer_id);
+       if (!node) {
                read_unlock_bh(&tipc_net_lock);
                return tipc_cfg_reply_error_string("link not found");
        }
-
        tipc_node_lock(node);
+       l_ptr = node->links[bearer_id];
+       if (!l_ptr) {
+               tipc_node_unlock(node);
+               read_unlock_bh(&tipc_net_lock);
+               return tipc_cfg_reply_error_string("link not found");
+       }
        link_reset_statistics(l_ptr);
        tipc_node_unlock(node);
        read_unlock_bh(&tipc_net_lock);
@@ -2590,18 +2644,27 @@ static int tipc_link_stats(const char *name, char *buf, const u32 buf_size)
        struct tipc_node *node;
        char *status;
        u32 profile_total = 0;
+       unsigned int bearer_id;
        int ret;
 
        if (!strcmp(name, tipc_bclink_name))
                return tipc_bclink_stats(buf, buf_size);
 
        read_lock_bh(&tipc_net_lock);
-       l = link_find_link(name, &node);
-       if (!l) {
+       node = tipc_link_find_owner(name, &bearer_id);
+       if (!node) {
                read_unlock_bh(&tipc_net_lock);
                return 0;
        }
        tipc_node_lock(node);
+
+       l = node->links[bearer_id];
+       if (!l) {
+               tipc_node_unlock(node);
+               read_unlock_bh(&tipc_net_lock);
+               return 0;
+       }
+
        s = &l->stats;
 
        if (tipc_link_is_active(l))
index 3b6aa65b608c119311d3ef25429fbce2764f9a46..8c0b49b5b2ee6b0751f248cf740254a33e424c6a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/link.h: Include file for TIPC link code
  *
- * Copyright (c) 1995-2006, Ericsson AB
+ * Copyright (c) 1995-2006, 2013, Ericsson AB
  * Copyright (c) 2004-2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
 #include "msg.h"
 #include "node.h"
 
-/*
- * Link reassembly status codes
+/* Link reassembly status codes
  */
 #define LINK_REASM_ERROR       -1
 #define LINK_REASM_COMPLETE    1
 
-/*
- * Out-of-range value for link sequence numbers
+/* Out-of-range value for link sequence numbers
  */
 #define INVALID_LINK_SEQ 0x10000
 
-/*
- * Link states
+/* Link working states
  */
 #define WORKING_WORKING 560810u
 #define WORKING_UNKNOWN 560811u
 #define RESET_UNKNOWN   560812u
 #define RESET_RESET     560813u
 
-/*
- * Starting value for maximum packet size negotiation on unicast links
+/* Link endpoint execution states
+ */
+#define LINK_STARTED    0x0001
+#define LINK_STOPPED    0x0002
+
+/* Starting value for maximum packet size negotiation on unicast links
  * (unless bearer MTU is less)
  */
 #define MAX_PKT_DEFAULT 1500
@@ -102,8 +103,7 @@ struct tipc_stats {
  * @media_addr: media address to use when sending messages over link
  * @timer: link timer
  * @owner: pointer to peer node
- * @link_list: adjacent links in bearer's list of links
- * @started: indicates if link has been started
+ * @flags: execution state flags for link endpoint instance
  * @checkpoint: reference point for triggering link continuity checking
  * @peer_session: link session # being used by peer end of link
  * @peer_bearer_id: bearer id used by link's peer endpoint
@@ -149,10 +149,9 @@ struct tipc_link {
        struct tipc_media_addr media_addr;
        struct timer_list timer;
        struct tipc_node *owner;
-       struct list_head link_list;
 
        /* Management and link supervision data */
-       int started;
+       unsigned int flags;
        u32 checkpoint;
        u32 peer_session;
        u32 peer_bearer_id;
@@ -215,10 +214,9 @@ struct tipc_port;
 struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
                              struct tipc_bearer *b_ptr,
                              const struct tipc_media_addr *media_addr);
-void tipc_link_delete(struct tipc_link *l_ptr);
+void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down);
 void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
-void tipc_link_dup_send_queue(struct tipc_link *l_ptr,
-                             struct tipc_link *dest);
+void tipc_link_dup_queue_xmit(struct tipc_link *l_ptr, struct tipc_link *dest);
 void tipc_link_reset_fragments(struct tipc_link *l_ptr);
 int tipc_link_is_up(struct tipc_link *l_ptr);
 int tipc_link_is_active(struct tipc_link *l_ptr);
@@ -231,23 +229,24 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area,
 struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area,
                                          int req_tlv_space);
 void tipc_link_reset(struct tipc_link *l_ptr);
-int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector);
-void tipc_link_send_names(struct list_head *message_list, u32 dest);
+void tipc_link_reset_list(unsigned int bearer_id);
+int tipc_link_xmit(struct sk_buff *buf, u32 dest, u32 selector);
+void tipc_link_names_xmit(struct list_head *message_list, u32 dest);
+int __tipc_link_xmit(struct tipc_link *l_ptr, struct sk_buff *buf);
 int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf);
 u32 tipc_link_get_max_pkt(u32 dest, u32 selector);
-int tipc_link_send_sections_fast(struct tipc_port *sender,
-                                struct iovec const *msg_sect,
-                                unsigned int len, u32 destnode);
-void tipc_link_recv_bundle(struct sk_buff *buf);
-int  tipc_link_recv_fragment(struct sk_buff **reasm_head,
-                            struct sk_buff **reasm_tail,
-                            struct sk_buff **fbuf);
-void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ, int prob,
-                             u32 gap, u32 tolerance, u32 priority,
-                             u32 acked_mtu);
+int tipc_link_iovec_xmit_fast(struct tipc_port *sender,
+                             struct iovec const *msg_sect,
+                             unsigned int len, u32 destnode);
+void tipc_link_bundle_rcv(struct sk_buff *buf);
+int tipc_link_frag_rcv(struct sk_buff **reasm_head,
+                      struct sk_buff **reasm_tail,
+                      struct sk_buff **fbuf);
+void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
+                         u32 gap, u32 tolerance, u32 priority, u32 acked_mtu);
 void tipc_link_push_queue(struct tipc_link *l_ptr);
 u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,
-                  struct sk_buff *buf);
+                       struct sk_buff *buf);
 void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all);
 void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window);
 void tipc_link_retransmit(struct tipc_link *l_ptr,
index e0d08055754ea656ab1afdd5dee59a51f16bb163..aff8041dc1573e3fea829e286e2675e322350b2e 100644 (file)
@@ -131,16 +131,24 @@ static void named_cluster_distribute(struct sk_buff *buf)
 {
        struct sk_buff *buf_copy;
        struct tipc_node *n_ptr;
+       struct tipc_link *l_ptr;
 
-       list_for_each_entry(n_ptr, &tipc_node_list, list) {
-               if (tipc_node_active_links(n_ptr)) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
+               spin_lock_bh(&n_ptr->lock);
+               l_ptr = n_ptr->active_links[n_ptr->addr & 1];
+               if (l_ptr) {
                        buf_copy = skb_copy(buf, GFP_ATOMIC);
-                       if (!buf_copy)
+                       if (!buf_copy) {
+                               spin_unlock_bh(&n_ptr->lock);
                                break;
+                       }
                        msg_set_destnode(buf_msg(buf_copy), n_ptr->addr);
-                       tipc_link_send(buf_copy, n_ptr->addr, n_ptr->addr);
+                       __tipc_link_xmit(l_ptr, buf_copy);
                }
+               spin_unlock_bh(&n_ptr->lock);
        }
+       rcu_read_unlock();
 
        kfree_skb(buf);
 }
@@ -262,7 +270,7 @@ void tipc_named_node_up(unsigned long nodearg)
        named_distribute(&message_list, node, &publ_zone, max_item_buf);
        read_unlock_bh(&tipc_nametbl_lock);
 
-       tipc_link_send_names(&message_list, node);
+       tipc_link_names_xmit(&message_list, node);
 }
 
 /**
@@ -293,9 +301,9 @@ static void named_purge_publ(struct publication *publ)
 }
 
 /**
- * tipc_named_recv - process name table update message sent by another node
+ * tipc_named_rcv - process name table update message sent by another node
  */
-void tipc_named_recv(struct sk_buff *buf)
+void tipc_named_rcv(struct sk_buff *buf)
 {
        struct publication *publ;
        struct tipc_msg *msg = buf_msg(buf);
index 1e41bdd4f2553a13a8a8f6ebeb75604ab9997fdb..9b312ccfd43e7da41bcab4ca33d5f0f4d5be86cf 100644 (file)
@@ -42,7 +42,7 @@
 void tipc_named_publish(struct publication *publ);
 void tipc_named_withdraw(struct publication *publ);
 void tipc_named_node_up(unsigned long node);
-void tipc_named_recv(struct sk_buff *buf);
+void tipc_named_rcv(struct sk_buff *buf);
 void tipc_named_reinit(void);
 
 #endif
index 92a1533af4e0a689f93f30c5b560368f1a548e37..042e8e3cabc09f84aa5dce626c57a30faf3ca32d 100644 (file)
@@ -941,20 +941,48 @@ int tipc_nametbl_init(void)
        return 0;
 }
 
-void tipc_nametbl_stop(void)
+/**
+ * tipc_purge_publications - remove all publications for a given type
+ *
+ * tipc_nametbl_lock must be held when calling this function
+ */
+static void tipc_purge_publications(struct name_seq *seq)
 {
-       u32 i;
+       struct publication *publ, *safe;
+       struct sub_seq *sseq;
+       struct name_info *info;
 
-       if (!table.types)
+       if (!seq->sseqs) {
+               nameseq_delete_empty(seq);
                return;
+       }
+       sseq = seq->sseqs;
+       info = sseq->info;
+       list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
+               tipc_nametbl_remove_publ(publ->type, publ->lower, publ->node,
+                                        publ->ref, publ->key);
+       }
+}
+
+void tipc_nametbl_stop(void)
+{
+       u32 i;
+       struct name_seq *seq;
+       struct hlist_head *seq_head;
+       struct hlist_node *safe;
 
-       /* Verify name table is empty, then release it */
+       /* Verify name table is empty and purge any lingering
+        * publications, then release the name table
+        */
        write_lock_bh(&tipc_nametbl_lock);
        for (i = 0; i < TIPC_NAMETBL_SIZE; i++) {
                if (hlist_empty(&table.types[i]))
                        continue;
-               pr_err("nametbl_stop(): orphaned hash chain detected\n");
-               break;
+               seq_head = &table.types[i];
+               hlist_for_each_entry_safe(seq, safe, seq_head, ns_list) {
+                       tipc_purge_publications(seq);
+               }
+               continue;
        }
        kfree(table.types);
        table.types = NULL;
index 7d305ecc09c2bf053376bb147c5cf917113022ae..0374a817631e47fc87a6f9d9ec04c34009063e53 100644 (file)
@@ -146,19 +146,19 @@ void tipc_net_route_msg(struct sk_buff *buf)
        if (tipc_in_scope(dnode, tipc_own_addr)) {
                if (msg_isdata(msg)) {
                        if (msg_mcast(msg))
-                               tipc_port_recv_mcast(buf, NULL);
+                               tipc_port_mcast_rcv(buf, NULL);
                        else if (msg_destport(msg))
-                               tipc_port_recv_msg(buf);
+                               tipc_port_rcv(buf);
                        else
                                net_route_named_msg(buf);
                        return;
                }
                switch (msg_user(msg)) {
                case NAME_DISTRIBUTOR:
-                       tipc_named_recv(buf);
+                       tipc_named_rcv(buf);
                        break;
                case CONN_MANAGER:
-                       tipc_port_recv_proto_msg(buf);
+                       tipc_port_proto_rcv(buf);
                        break;
                default:
                        kfree_skb(buf);
@@ -168,7 +168,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
 
        /* Handle message for another node */
        skb_trim(buf, msg_size(msg));
-       tipc_link_send(buf, dnode, msg_link_selector(msg));
+       tipc_link_xmit(buf, dnode, msg_link_selector(msg));
 }
 
 void tipc_net_start(u32 addr)
@@ -182,8 +182,6 @@ void tipc_net_start(u32 addr)
        tipc_bclink_init();
        write_unlock_bh(&tipc_net_lock);
 
-       tipc_cfg_reinit();
-
        pr_info("Started in network mode\n");
        pr_info("Own node address %s, network identity %u\n",
                tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
@@ -191,15 +189,14 @@ void tipc_net_start(u32 addr)
 
 void tipc_net_stop(void)
 {
-       struct tipc_node *node, *t_node;
-
        if (!tipc_own_addr)
                return;
+
        write_lock_bh(&tipc_net_lock);
        tipc_bearer_stop();
        tipc_bclink_stop();
-       list_for_each_entry_safe(node, t_node, &tipc_node_list, list)
-               tipc_node_delete(node);
+       tipc_node_stop();
        write_unlock_bh(&tipc_net_lock);
+
        pr_info("Left network mode\n");
 }
index 9f72a6376362e613cb87185acbb3581174c45592..3aaf73de9e2d017e96b3cc1124d5c9420d827abd 100644 (file)
@@ -83,8 +83,6 @@ static struct genl_ops tipc_genl_ops[] = {
        },
 };
 
-static int tipc_genl_family_registered;
-
 int tipc_netlink_start(void)
 {
        int res;
@@ -94,16 +92,10 @@ int tipc_netlink_start(void)
                pr_err("Failed to register netlink interface\n");
                return res;
        }
-
-       tipc_genl_family_registered = 1;
        return 0;
 }
 
 void tipc_netlink_stop(void)
 {
-       if (!tipc_genl_family_registered)
-               return;
-
        genl_unregister_family(&tipc_genl_family);
-       tipc_genl_family_registered = 0;
 }
index efe4d41bf11bacb258e3096dc4619e97828c2904..1d3a4999a70ff96a751f3908d0d8e274af63a962 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/node.c: TIPC node management routines
  *
  * Copyright (c) 2000-2006, 2012 Ericsson AB
- * Copyright (c) 2005-2006, 2010-2011, Wind River Systems
+ * Copyright (c) 2005-2006, 2010-2014, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 static void node_lost_contact(struct tipc_node *n_ptr);
 static void node_established_contact(struct tipc_node *n_ptr);
 
-static DEFINE_SPINLOCK(node_create_lock);
-
 static struct hlist_head node_htable[NODE_HTABLE_SIZE];
 LIST_HEAD(tipc_node_list);
 static u32 tipc_num_nodes;
-
-static atomic_t tipc_num_links = ATOMIC_INIT(0);
+static u32 tipc_num_links;
+static DEFINE_SPINLOCK(node_list_lock);
 
 /*
  * A trivial power-of-two bitmask technique is used for speed, since this
@@ -73,37 +71,26 @@ struct tipc_node *tipc_node_find(u32 addr)
        if (unlikely(!in_own_cluster_exact(addr)))
                return NULL;
 
-       hlist_for_each_entry(node, &node_htable[tipc_hashfn(addr)], hash) {
-               if (node->addr == addr)
+       rcu_read_lock();
+       hlist_for_each_entry_rcu(node, &node_htable[tipc_hashfn(addr)], hash) {
+               if (node->addr == addr) {
+                       rcu_read_unlock();
                        return node;
+               }
        }
+       rcu_read_unlock();
        return NULL;
 }
 
-/**
- * tipc_node_create - create neighboring node
- *
- * Currently, this routine is called by neighbor discovery code, which holds
- * net_lock for reading only.  We must take node_create_lock to ensure a node
- * isn't created twice if two different bearers discover the node at the same
- * time.  (It would be preferable to switch to holding net_lock in write mode,
- * but this is a non-trivial change.)
- */
 struct tipc_node *tipc_node_create(u32 addr)
 {
        struct tipc_node *n_ptr, *temp_node;
 
-       spin_lock_bh(&node_create_lock);
-
-       n_ptr = tipc_node_find(addr);
-       if (n_ptr) {
-               spin_unlock_bh(&node_create_lock);
-               return n_ptr;
-       }
+       spin_lock_bh(&node_list_lock);
 
        n_ptr = kzalloc(sizeof(*n_ptr), GFP_ATOMIC);
        if (!n_ptr) {
-               spin_unlock_bh(&node_create_lock);
+               spin_unlock_bh(&node_list_lock);
                pr_warn("Node creation failed, no memory\n");
                return NULL;
        }
@@ -114,31 +101,41 @@ struct tipc_node *tipc_node_create(u32 addr)
        INIT_LIST_HEAD(&n_ptr->list);
        INIT_LIST_HEAD(&n_ptr->nsub);
 
-       hlist_add_head(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
+       hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]);
 
-       list_for_each_entry(temp_node, &tipc_node_list, list) {
+       list_for_each_entry_rcu(temp_node, &tipc_node_list, list) {
                if (n_ptr->addr < temp_node->addr)
                        break;
        }
-       list_add_tail(&n_ptr->list, &temp_node->list);
+       list_add_tail_rcu(&n_ptr->list, &temp_node->list);
        n_ptr->block_setup = WAIT_PEER_DOWN;
        n_ptr->signature = INVALID_NODE_SIG;
 
        tipc_num_nodes++;
 
-       spin_unlock_bh(&node_create_lock);
+       spin_unlock_bh(&node_list_lock);
        return n_ptr;
 }
 
-void tipc_node_delete(struct tipc_node *n_ptr)
+static void tipc_node_delete(struct tipc_node *n_ptr)
 {
-       list_del(&n_ptr->list);
-       hlist_del(&n_ptr->hash);
-       kfree(n_ptr);
+       list_del_rcu(&n_ptr->list);
+       hlist_del_rcu(&n_ptr->hash);
+       kfree_rcu(n_ptr, rcu);
 
        tipc_num_nodes--;
 }
 
+void tipc_node_stop(void)
+{
+       struct tipc_node *node, *t_node;
+
+       spin_lock_bh(&node_list_lock);
+       list_for_each_entry_safe(node, t_node, &tipc_node_list, list)
+               tipc_node_delete(node);
+       spin_unlock_bh(&node_list_lock);
+}
+
 /**
  * tipc_node_link_up - handle addition of link
  *
@@ -162,7 +159,7 @@ void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
                pr_info("New link <%s> becomes standby\n", l_ptr->name);
                return;
        }
-       tipc_link_dup_send_queue(active[0], l_ptr);
+       tipc_link_dup_queue_xmit(active[0], l_ptr);
        if (l_ptr->priority == active[0]->priority) {
                active[0] = l_ptr;
                return;
@@ -243,15 +240,25 @@ int tipc_node_is_up(struct tipc_node *n_ptr)
 void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 {
        n_ptr->links[l_ptr->b_ptr->identity] = l_ptr;
-       atomic_inc(&tipc_num_links);
+       spin_lock_bh(&node_list_lock);
+       tipc_num_links++;
+       spin_unlock_bh(&node_list_lock);
        n_ptr->link_cnt++;
 }
 
 void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr)
 {
-       n_ptr->links[l_ptr->b_ptr->identity] = NULL;
-       atomic_dec(&tipc_num_links);
-       n_ptr->link_cnt--;
+       int i;
+
+       for (i = 0; i < MAX_BEARERS; i++) {
+               if (l_ptr != n_ptr->links[i])
+                       continue;
+               n_ptr->links[i] = NULL;
+               spin_lock_bh(&node_list_lock);
+               tipc_num_links--;
+               spin_unlock_bh(&node_list_lock);
+               n_ptr->link_cnt--;
+       }
 }
 
 static void node_established_contact(struct tipc_node *n_ptr)
@@ -335,27 +342,28 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
                return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
                                                   " (network address)");
 
-       read_lock_bh(&tipc_net_lock);
+       spin_lock_bh(&node_list_lock);
        if (!tipc_num_nodes) {
-               read_unlock_bh(&tipc_net_lock);
+               spin_unlock_bh(&node_list_lock);
                return tipc_cfg_reply_none();
        }
 
        /* For now, get space for all other nodes */
        payload_size = TLV_SPACE(sizeof(node_info)) * tipc_num_nodes;
        if (payload_size > 32768u) {
-               read_unlock_bh(&tipc_net_lock);
+               spin_unlock_bh(&node_list_lock);
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (too many nodes)");
        }
+       spin_unlock_bh(&node_list_lock);
+
        buf = tipc_cfg_reply_alloc(payload_size);
-       if (!buf) {
-               read_unlock_bh(&tipc_net_lock);
+       if (!buf)
                return NULL;
-       }
 
        /* Add TLVs for all nodes in scope */
-       list_for_each_entry(n_ptr, &tipc_node_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
                if (!tipc_in_scope(domain, n_ptr->addr))
                        continue;
                node_info.addr = htonl(n_ptr->addr);
@@ -363,8 +371,7 @@ struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space)
                tipc_cfg_append_tlv(buf, TIPC_TLV_NODE_INFO,
                                    &node_info, sizeof(node_info));
        }
-
-       read_unlock_bh(&tipc_net_lock);
+       rcu_read_unlock();
        return buf;
 }
 
@@ -387,21 +394,19 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
        if (!tipc_own_addr)
                return tipc_cfg_reply_none();
 
-       read_lock_bh(&tipc_net_lock);
-
+       spin_lock_bh(&node_list_lock);
        /* Get space for all unicast links + broadcast link */
-       payload_size = TLV_SPACE(sizeof(link_info)) *
-               (atomic_read(&tipc_num_links) + 1);
+       payload_size = TLV_SPACE((sizeof(link_info)) * (tipc_num_links + 1));
        if (payload_size > 32768u) {
-               read_unlock_bh(&tipc_net_lock);
+               spin_unlock_bh(&node_list_lock);
                return tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
                                                   " (too many links)");
        }
+       spin_unlock_bh(&node_list_lock);
+
        buf = tipc_cfg_reply_alloc(payload_size);
-       if (!buf) {
-               read_unlock_bh(&tipc_net_lock);
+       if (!buf)
                return NULL;
-       }
 
        /* Add TLV for broadcast link */
        link_info.dest = htonl(tipc_cluster_mask(tipc_own_addr));
@@ -410,7 +415,8 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
        tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
 
        /* Add TLVs for any other links in scope */
-       list_for_each_entry(n_ptr, &tipc_node_list, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(n_ptr, &tipc_node_list, list) {
                u32 i;
 
                if (!tipc_in_scope(domain, n_ptr->addr))
@@ -427,7 +433,6 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
                }
                tipc_node_unlock(n_ptr);
        }
-
-       read_unlock_bh(&tipc_net_lock);
+       rcu_read_unlock();
        return buf;
 }
index 63e2e8ead2fe5d08d50a4d26f0337b79a9961c8b..7cbb8cec1a932f881cd636a71edb0342070530ae 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/node.h: Include file for TIPC node management routines
  *
  * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, 2010-2011, Wind River Systems
+ * Copyright (c) 2005, 2010-2014, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,6 +66,7 @@
  * @link_cnt: number of links to node
  * @signature: node instance identifier
  * @bclink: broadcast-related info
+ * @rcu: rcu struct for tipc_node
  *    @acked: sequence # of last outbound b'cast message acknowledged by node
  *    @last_in: sequence # of last in-sequence b'cast message received from node
  *    @last_sent: sequence # of last b'cast message sent by node
@@ -89,6 +90,7 @@ struct tipc_node {
        int working_links;
        int block_setup;
        u32 signature;
+       struct rcu_head rcu;
        struct {
                u32 acked;
                u32 last_in;
@@ -107,7 +109,7 @@ extern struct list_head tipc_node_list;
 
 struct tipc_node *tipc_node_find(u32 addr);
 struct tipc_node *tipc_node_create(u32 addr);
-void tipc_node_delete(struct tipc_node *n_ptr);
+void tipc_node_stop(void);
 void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
 void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
 void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr);
index b742b2654525e2b4c7bd7974c0b7ae6f0356156f..5c14c7801ee65095d809d502cab9f78d33d51e5e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/port.c: TIPC port code
  *
- * Copyright (c) 1992-2007, Ericsson AB
+ * Copyright (c) 1992-2007, 2014, Ericsson AB
  * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -38,6 +38,7 @@
 #include "config.h"
 #include "port.h"
 #include "name_table.h"
+#include "socket.h"
 
 /* Connection management: */
 #define PROBING_INTERVAL 3600000       /* [ms] => 1 h */
@@ -54,17 +55,6 @@ static struct sk_buff *port_build_self_abort_msg(struct tipc_port *, u32 err);
 static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *, u32 err);
 static void port_timeout(unsigned long ref);
 
-
-static u32 port_peernode(struct tipc_port *p_ptr)
-{
-       return msg_destnode(&p_ptr->phdr);
-}
-
-static u32 port_peerport(struct tipc_port *p_ptr)
-{
-       return msg_destport(&p_ptr->phdr);
-}
-
 /**
  * tipc_port_peer_msg - verify message was sent by connected port's peer
  *
@@ -76,33 +66,32 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg)
        u32 peernode;
        u32 orignode;
 
-       if (msg_origport(msg) != port_peerport(p_ptr))
+       if (msg_origport(msg) != tipc_port_peerport(p_ptr))
                return 0;
 
        orignode = msg_orignode(msg);
-       peernode = port_peernode(p_ptr);
+       peernode = tipc_port_peernode(p_ptr);
        return (orignode == peernode) ||
                (!orignode && (peernode == tipc_own_addr)) ||
                (!peernode && (orignode == tipc_own_addr));
 }
 
 /**
- * tipc_multicast - send a multicast message to local and remote destinations
+ * tipc_port_mcast_xmit - send a multicast message to local and remote
+ * destinations
  */
-int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
-                  struct iovec const *msg_sect, unsigned int len)
+int tipc_port_mcast_xmit(struct tipc_port *oport,
+                        struct tipc_name_seq const *seq,
+                        struct iovec const *msg_sect,
+                        unsigned int len)
 {
        struct tipc_msg *hdr;
        struct sk_buff *buf;
        struct sk_buff *ibuf = NULL;
        struct tipc_port_list dports = {0, NULL, };
-       struct tipc_port *oport = tipc_port_deref(ref);
        int ext_targets;
        int res;
 
-       if (unlikely(!oport))
-               return -EINVAL;
-
        /* Create multicast message */
        hdr = &oport->phdr;
        msg_set_type(hdr, TIPC_MCAST_MSG);
@@ -131,7 +120,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
                                return -ENOMEM;
                        }
                }
-               res = tipc_bclink_send_msg(buf);
+               res = tipc_bclink_xmit(buf);
                if ((res < 0) && (dports.count != 0))
                        kfree_skb(ibuf);
        } else {
@@ -140,7 +129,7 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
 
        if (res >= 0) {
                if (ibuf)
-                       tipc_port_recv_mcast(ibuf, &dports);
+                       tipc_port_mcast_rcv(ibuf, &dports);
        } else {
                tipc_port_list_free(&dports);
        }
@@ -148,11 +137,11 @@ int tipc_multicast(u32 ref, struct tipc_name_seq const *seq,
 }
 
 /**
- * tipc_port_recv_mcast - deliver multicast message to all destination ports
+ * tipc_port_mcast_rcv - deliver multicast message to all destination ports
  *
  * If there is no port list, perform a lookup to create one
  */
-void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp)
+void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp)
 {
        struct tipc_msg *msg;
        struct tipc_port_list dports = {0, NULL, };
@@ -176,7 +165,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp)
                msg_set_destnode(msg, tipc_own_addr);
                if (dp->count == 1) {
                        msg_set_destport(msg, dp->ports[0]);
-                       tipc_port_recv_msg(buf);
+                       tipc_port_rcv(buf);
                        tipc_port_list_free(dp);
                        return;
                }
@@ -191,7 +180,7 @@ void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp)
                        if ((index == 0) && (cnt != 0))
                                item = item->next;
                        msg_set_destport(buf_msg(b), item->ports[index]);
-                       tipc_port_recv_msg(b);
+                       tipc_port_rcv(b);
                }
        }
 exit:
@@ -199,40 +188,32 @@ exit:
        tipc_port_list_free(dp);
 }
 
-/**
- * tipc_createport - create a generic TIPC port
+
+void tipc_port_wakeup(struct tipc_port *port)
+{
+       tipc_sock_wakeup(tipc_port_to_sock(port));
+}
+
+/* tipc_port_init - intiate TIPC port and lock it
  *
- * Returns pointer to (locked) TIPC port, or NULL if unable to create it
+ * Returns obtained reference if initialization is successful, zero otherwise
  */
-struct tipc_port *tipc_createport(struct sock *sk,
-                                 u32 (*dispatcher)(struct tipc_port *,
-                                 struct sk_buff *),
-                                 void (*wakeup)(struct tipc_port *),
-                                 const u32 importance)
+u32 tipc_port_init(struct tipc_port *p_ptr,
+                  const unsigned int importance)
 {
-       struct tipc_port *p_ptr;
        struct tipc_msg *msg;
        u32 ref;
 
-       p_ptr = kzalloc(sizeof(*p_ptr), GFP_ATOMIC);
-       if (!p_ptr) {
-               pr_warn("Port creation failed, no memory\n");
-               return NULL;
-       }
        ref = tipc_ref_acquire(p_ptr, &p_ptr->lock);
        if (!ref) {
-               pr_warn("Port creation failed, ref. table exhausted\n");
-               kfree(p_ptr);
-               return NULL;
+               pr_warn("Port registration failed, ref. table exhausted\n");
+               return 0;
        }
 
-       p_ptr->sk = sk;
        p_ptr->max_pkt = MAX_PKT_DEFAULT;
        p_ptr->ref = ref;
        INIT_LIST_HEAD(&p_ptr->wait_list);
        INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
-       p_ptr->dispatcher = dispatcher;
-       p_ptr->wakeup = wakeup;
        k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref);
        INIT_LIST_HEAD(&p_ptr->publications);
        INIT_LIST_HEAD(&p_ptr->port_list);
@@ -248,10 +229,10 @@ struct tipc_port *tipc_createport(struct sock *sk,
        msg_set_origport(msg, ref);
        list_add_tail(&p_ptr->port_list, &ports);
        spin_unlock_bh(&tipc_port_list_lock);
-       return p_ptr;
+       return ref;
 }
 
-int tipc_deleteport(struct tipc_port *p_ptr)
+void tipc_port_destroy(struct tipc_port *p_ptr)
 {
        struct sk_buff *buf = NULL;
 
@@ -272,67 +253,7 @@ int tipc_deleteport(struct tipc_port *p_ptr)
        list_del(&p_ptr->wait_list);
        spin_unlock_bh(&tipc_port_list_lock);
        k_term_timer(&p_ptr->timer);
-       kfree(p_ptr);
        tipc_net_route_msg(buf);
-       return 0;
-}
-
-static int port_unreliable(struct tipc_port *p_ptr)
-{
-       return msg_src_droppable(&p_ptr->phdr);
-}
-
-int tipc_portunreliable(u32 ref, unsigned int *isunreliable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       *isunreliable = port_unreliable(p_ptr);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-int tipc_set_portunreliable(u32 ref, unsigned int isunreliable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       msg_set_src_droppable(&p_ptr->phdr, (isunreliable != 0));
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-static int port_unreturnable(struct tipc_port *p_ptr)
-{
-       return msg_dest_droppable(&p_ptr->phdr);
-}
-
-int tipc_portunreturnable(u32 ref, unsigned int *isunrejectable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       *isunrejectable = port_unreturnable(p_ptr);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-int tipc_set_portunreturnable(u32 ref, unsigned int isunrejectable)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       msg_set_dest_droppable(&p_ptr->phdr, (isunrejectable != 0));
-       tipc_port_unlock(p_ptr);
-       return 0;
 }
 
 /*
@@ -350,8 +271,8 @@ static struct sk_buff *port_build_proto_msg(struct tipc_port *p_ptr,
        if (buf) {
                msg = buf_msg(buf);
                tipc_msg_init(msg, CONN_MANAGER, type, INT_H_SIZE,
-                             port_peernode(p_ptr));
-               msg_set_destport(msg, port_peerport(p_ptr));
+                             tipc_port_peernode(p_ptr));
+               msg_set_destport(msg, tipc_port_peerport(p_ptr));
                msg_set_origport(msg, p_ptr->ref);
                msg_set_msgcnt(msg, ack);
        }
@@ -422,17 +343,17 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
        /* send returned message & dispose of rejected message */
        src_node = msg_prevnode(msg);
        if (in_own_node(src_node))
-               tipc_port_recv_msg(rbuf);
+               tipc_port_rcv(rbuf);
        else
-               tipc_link_send(rbuf, src_node, msg_link_selector(rmsg));
+               tipc_link_xmit(rbuf, src_node, msg_link_selector(rmsg));
 exit:
        kfree_skb(buf);
        return data_sz;
 }
 
-int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
-                             struct iovec const *msg_sect, unsigned int len,
-                             int err)
+int tipc_port_iovec_reject(struct tipc_port *p_ptr, struct tipc_msg *hdr,
+                          struct iovec const *msg_sect, unsigned int len,
+                          int err)
 {
        struct sk_buff *buf;
        int res;
@@ -519,7 +440,7 @@ static struct sk_buff *port_build_peer_abort_msg(struct tipc_port *p_ptr, u32 er
        return buf;
 }
 
-void tipc_port_recv_proto_msg(struct sk_buff *buf)
+void tipc_port_proto_rcv(struct sk_buff *buf)
 {
        struct tipc_msg *msg = buf_msg(buf);
        struct tipc_port *p_ptr;
@@ -547,13 +468,12 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
        /* Process protocol message sent by peer */
        switch (msg_type(msg)) {
        case CONN_ACK:
-               wakeable = tipc_port_congested(p_ptr) && p_ptr->congested &&
-                       p_ptr->wakeup;
+               wakeable = tipc_port_congested(p_ptr) && p_ptr->congested;
                p_ptr->acked += msg_msgcnt(msg);
                if (!tipc_port_congested(p_ptr)) {
                        p_ptr->congested = 0;
                        if (wakeable)
-                               p_ptr->wakeup(p_ptr);
+                               tipc_port_wakeup(p_ptr);
                }
                break;
        case CONN_PROBE:
@@ -584,8 +504,8 @@ static int port_print(struct tipc_port *p_ptr, char *buf, int len, int full_id)
                ret = tipc_snprintf(buf, len, "%-10u:", p_ptr->ref);
 
        if (p_ptr->connected) {
-               u32 dport = port_peerport(p_ptr);
-               u32 destnode = port_peernode(p_ptr);
+               u32 dport = tipc_port_peerport(p_ptr);
+               u32 destnode = tipc_port_peernode(p_ptr);
 
                ret += tipc_snprintf(buf + ret, len - ret,
                                     " connected to <%u.%u.%u:%u>",
@@ -673,34 +593,6 @@ void tipc_acknowledge(u32 ref, u32 ack)
        tipc_net_route_msg(buf);
 }
 
-int tipc_portimportance(u32 ref, unsigned int *importance)
-{
-       struct tipc_port *p_ptr;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       *importance = (unsigned int)msg_importance(&p_ptr->phdr);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-int tipc_set_portimportance(u32 ref, unsigned int imp)
-{
-       struct tipc_port *p_ptr;
-
-       if (imp > TIPC_CRITICAL_IMPORTANCE)
-               return -EINVAL;
-
-       p_ptr = tipc_port_lock(ref);
-       if (!p_ptr)
-               return -EINVAL;
-       msg_set_importance(&p_ptr->phdr, (u32)imp);
-       tipc_port_unlock(p_ptr);
-       return 0;
-}
-
-
 int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
                 struct tipc_name_seq const *seq)
 {
@@ -760,7 +652,7 @@ int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
        return res;
 }
 
-int tipc_connect(u32 ref, struct tipc_portid const *peer)
+int tipc_port_connect(u32 ref, struct tipc_portid const *peer)
 {
        struct tipc_port *p_ptr;
        int res;
@@ -768,17 +660,17 @@ int tipc_connect(u32 ref, struct tipc_portid const *peer)
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr)
                return -EINVAL;
-       res = __tipc_connect(ref, p_ptr, peer);
+       res = __tipc_port_connect(ref, p_ptr, peer);
        tipc_port_unlock(p_ptr);
        return res;
 }
 
 /*
- * __tipc_connect - connect to a remote peer
+ * __tipc_port_connect - connect to a remote peer
  *
  * Port must be locked.
  */
-int __tipc_connect(u32 ref, struct tipc_port *p_ptr,
+int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
                        struct tipc_portid const *peer)
 {
        struct tipc_msg *msg;
@@ -815,7 +707,7 @@ exit:
  *
  * Port must be locked.
  */
-int __tipc_disconnect(struct tipc_port *tp_ptr)
+int __tipc_port_disconnect(struct tipc_port *tp_ptr)
 {
        if (tp_ptr->connected) {
                tp_ptr->connected = 0;
@@ -828,10 +720,10 @@ int __tipc_disconnect(struct tipc_port *tp_ptr)
 }
 
 /*
- * tipc_disconnect(): Disconnect port form peer.
+ * tipc_port_disconnect(): Disconnect port form peer.
  *                    This is a node local operation.
  */
-int tipc_disconnect(u32 ref)
+int tipc_port_disconnect(u32 ref)
 {
        struct tipc_port *p_ptr;
        int res;
@@ -839,15 +731,15 @@ int tipc_disconnect(u32 ref)
        p_ptr = tipc_port_lock(ref);
        if (!p_ptr)
                return -EINVAL;
-       res = __tipc_disconnect(p_ptr);
+       res = __tipc_port_disconnect(p_ptr);
        tipc_port_unlock(p_ptr);
        return res;
 }
 
 /*
- * tipc_shutdown(): Send a SHUTDOWN msg to peer and disconnect
+ * tipc_port_shutdown(): Send a SHUTDOWN msg to peer and disconnect
  */
-int tipc_shutdown(u32 ref)
+int tipc_port_shutdown(u32 ref)
 {
        struct tipc_port *p_ptr;
        struct sk_buff *buf = NULL;
@@ -859,13 +751,13 @@ int tipc_shutdown(u32 ref)
        buf = port_build_peer_abort_msg(p_ptr, TIPC_CONN_SHUTDOWN);
        tipc_port_unlock(p_ptr);
        tipc_net_route_msg(buf);
-       return tipc_disconnect(ref);
+       return tipc_port_disconnect(ref);
 }
 
 /**
- * tipc_port_recv_msg - receive message from lower layer and deliver to port user
+ * tipc_port_rcv - receive message from lower layer and deliver to port user
  */
-int tipc_port_recv_msg(struct sk_buff *buf)
+int tipc_port_rcv(struct sk_buff *buf)
 {
        struct tipc_port *p_ptr;
        struct tipc_msg *msg = buf_msg(buf);
@@ -882,7 +774,7 @@ int tipc_port_recv_msg(struct sk_buff *buf)
        /* validate destination & pass to port, otherwise reject message */
        p_ptr = tipc_port_lock(destport);
        if (likely(p_ptr)) {
-               err = p_ptr->dispatcher(p_ptr, buf);
+               err = tipc_sk_rcv(&tipc_port_to_sock(p_ptr)->sk, buf);
                tipc_port_unlock(p_ptr);
                if (likely(!err))
                        return dsz;
@@ -894,43 +786,43 @@ int tipc_port_recv_msg(struct sk_buff *buf)
 }
 
 /*
- *  tipc_port_recv_sections(): Concatenate and deliver sectioned
- *                        message for this node.
+ *  tipc_port_iovec_rcv: Concatenate and deliver sectioned
+ *                       message for this node.
  */
-static int tipc_port_recv_sections(struct tipc_port *sender,
-                                  struct iovec const *msg_sect,
-                                  unsigned int len)
+static int tipc_port_iovec_rcv(struct tipc_port *sender,
+                              struct iovec const *msg_sect,
+                              unsigned int len)
 {
        struct sk_buff *buf;
        int res;
 
        res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf);
        if (likely(buf))
-               tipc_port_recv_msg(buf);
+               tipc_port_rcv(buf);
        return res;
 }
 
 /**
  * tipc_send - send message sections on connection
  */
-int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
+int tipc_send(struct tipc_port *p_ptr,
+             struct iovec const *msg_sect,
+             unsigned int len)
 {
-       struct tipc_port *p_ptr;
        u32 destnode;
        int res;
 
-       p_ptr = tipc_port_deref(ref);
-       if (!p_ptr || !p_ptr->connected)
+       if (!p_ptr->connected)
                return -EINVAL;
 
        p_ptr->congested = 1;
        if (!tipc_port_congested(p_ptr)) {
-               destnode = port_peernode(p_ptr);
+               destnode = tipc_port_peernode(p_ptr);
                if (likely(!in_own_node(destnode)))
-                       res = tipc_link_send_sections_fast(p_ptr, msg_sect,
-                                                          len, destnode);
+                       res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len,
+                                                       destnode);
                else
-                       res = tipc_port_recv_sections(p_ptr, msg_sect, len);
+                       res = tipc_port_iovec_rcv(p_ptr, msg_sect, len);
 
                if (likely(res != -ELINKCONG)) {
                        p_ptr->congested = 0;
@@ -939,7 +831,7 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
                        return res;
                }
        }
-       if (port_unreliable(p_ptr)) {
+       if (tipc_port_unreliable(p_ptr)) {
                p_ptr->congested = 0;
                return len;
        }
@@ -949,17 +841,18 @@ int tipc_send(u32 ref, struct iovec const *msg_sect, unsigned int len)
 /**
  * tipc_send2name - send message sections to port name
  */
-int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
-                  struct iovec const *msg_sect, unsigned int len)
+int tipc_send2name(struct tipc_port *p_ptr,
+                  struct tipc_name const *name,
+                  unsigned int domain,
+                  struct iovec const *msg_sect,
+                  unsigned int len)
 {
-       struct tipc_port *p_ptr;
        struct tipc_msg *msg;
        u32 destnode = domain;
        u32 destport;
        int res;
 
-       p_ptr = tipc_port_deref(ref);
-       if (!p_ptr || p_ptr->connected)
+       if (p_ptr->connected)
                return -EINVAL;
 
        msg = &p_ptr->phdr;
@@ -974,39 +867,39 @@ int tipc_send2name(u32 ref, struct tipc_name const *name, unsigned int domain,
 
        if (likely(destport || destnode)) {
                if (likely(in_own_node(destnode)))
-                       res = tipc_port_recv_sections(p_ptr, msg_sect, len);
+                       res = tipc_port_iovec_rcv(p_ptr, msg_sect, len);
                else if (tipc_own_addr)
-                       res = tipc_link_send_sections_fast(p_ptr, msg_sect,
-                                                          len, destnode);
+                       res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len,
+                                                       destnode);
                else
-                       res = tipc_port_reject_sections(p_ptr, msg, msg_sect,
-                                                       len, TIPC_ERR_NO_NODE);
+                       res = tipc_port_iovec_reject(p_ptr, msg, msg_sect,
+                                                    len, TIPC_ERR_NO_NODE);
                if (likely(res != -ELINKCONG)) {
                        if (res > 0)
                                p_ptr->sent++;
                        return res;
                }
-               if (port_unreliable(p_ptr)) {
+               if (tipc_port_unreliable(p_ptr))
                        return len;
-               }
+
                return -ELINKCONG;
        }
-       return tipc_port_reject_sections(p_ptr, msg, msg_sect, len,
-                                        TIPC_ERR_NO_NAME);
+       return tipc_port_iovec_reject(p_ptr, msg, msg_sect, len,
+                                     TIPC_ERR_NO_NAME);
 }
 
 /**
  * tipc_send2port - send message sections to port identity
  */
-int tipc_send2port(u32 ref, struct tipc_portid const *dest,
-                  struct iovec const *msg_sect, unsigned int len)
+int tipc_send2port(struct tipc_port *p_ptr,
+                  struct tipc_portid const *dest,
+                  struct iovec const *msg_sect,
+                  unsigned int len)
 {
-       struct tipc_port *p_ptr;
        struct tipc_msg *msg;
        int res;
 
-       p_ptr = tipc_port_deref(ref);
-       if (!p_ptr || p_ptr->connected)
+       if (p_ptr->connected)
                return -EINVAL;
 
        msg = &p_ptr->phdr;
@@ -1017,20 +910,20 @@ int tipc_send2port(u32 ref, struct tipc_portid const *dest,
        msg_set_hdr_sz(msg, BASIC_H_SIZE);
 
        if (in_own_node(dest->node))
-               res =  tipc_port_recv_sections(p_ptr, msg_sect, len);
+               res =  tipc_port_iovec_rcv(p_ptr, msg_sect, len);
        else if (tipc_own_addr)
-               res = tipc_link_send_sections_fast(p_ptr, msg_sect, len,
-                                                  dest->node);
+               res = tipc_link_iovec_xmit_fast(p_ptr, msg_sect, len,
+                                               dest->node);
        else
-               res = tipc_port_reject_sections(p_ptr, msg, msg_sect, len,
+               res = tipc_port_iovec_reject(p_ptr, msg, msg_sect, len,
                                                TIPC_ERR_NO_NODE);
        if (likely(res != -ELINKCONG)) {
                if (res > 0)
                        p_ptr->sent++;
                return res;
        }
-       if (port_unreliable(p_ptr)) {
+       if (tipc_port_unreliable(p_ptr))
                return len;
-       }
+
        return -ELINKCONG;
 }
index 34f12bd4074e49ff8b4c7809bfe0bc706941ec7c..a00397393bd1d9179bd779339500e34bd710aa5b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/port.h: Include file for TIPC port code
  *
- * Copyright (c) 1994-2007, Ericsson AB
+ * Copyright (c) 1994-2007, 2014, Ericsson AB
  * Copyright (c) 2004-2007, 2010-2013, Wind River Systems
  * All rights reserved.
  *
@@ -48,7 +48,6 @@
 
 /**
  * struct tipc_port - TIPC port structure
- * @sk: pointer to socket handle
  * @lock: pointer to spinlock for controlling access to port
  * @connected: non-zero if port is currently connected to a peer port
  * @conn_type: TIPC type used when connection was established
@@ -60,8 +59,6 @@
  * @ref: unique reference to port in TIPC object registry
  * @phdr: preformatted message header used when sending messages
  * @port_list: adjacent ports in TIPC's global list of ports
- * @dispatcher: ptr to routine which handles received messages
- * @wakeup: ptr to routine to call when port is no longer congested
  * @wait_list: adjacent ports in list of ports waiting on link congestion
  * @waiting_pkts:
  * @sent: # of non-empty messages sent by port
@@ -74,7 +71,6 @@
  * @subscription: "node down" subscription used to terminate failed connections
  */
 struct tipc_port {
-       struct sock *sk;
        spinlock_t *lock;
        int connected;
        u32 conn_type;
@@ -86,8 +82,6 @@ struct tipc_port {
        u32 ref;
        struct tipc_msg phdr;
        struct list_head port_list;
-       u32 (*dispatcher)(struct tipc_port *, struct sk_buff *);
-       void (*wakeup)(struct tipc_port *);
        struct list_head wait_list;
        u32 waiting_pkts;
        u32 sent;
@@ -106,68 +100,71 @@ struct tipc_port_list;
 /*
  * TIPC port manipulation routines
  */
-struct tipc_port *tipc_createport(struct sock *sk,
-                                 u32 (*dispatcher)(struct tipc_port *,
-                                 struct sk_buff *),
-                                 void (*wakeup)(struct tipc_port *),
-                                 const u32 importance);
+u32 tipc_port_init(struct tipc_port *p_ptr,
+                  const unsigned int importance);
 
 int tipc_reject_msg(struct sk_buff *buf, u32 err);
 
 void tipc_acknowledge(u32 port_ref, u32 ack);
 
-int tipc_deleteport(struct tipc_port *p_ptr);
-
-int tipc_portimportance(u32 portref, unsigned int *importance);
-int tipc_set_portimportance(u32 portref, unsigned int importance);
-
-int tipc_portunreliable(u32 portref, unsigned int *isunreliable);
-int tipc_set_portunreliable(u32 portref, unsigned int isunreliable);
-
-int tipc_portunreturnable(u32 portref, unsigned int *isunreturnable);
-int tipc_set_portunreturnable(u32 portref, unsigned int isunreturnable);
+void tipc_port_destroy(struct tipc_port *p_ptr);
 
 int tipc_publish(struct tipc_port *p_ptr, unsigned int scope,
                 struct tipc_name_seq const *name_seq);
+
 int tipc_withdraw(struct tipc_port *p_ptr, unsigned int scope,
                  struct tipc_name_seq const *name_seq);
 
-int tipc_connect(u32 portref, struct tipc_portid const *port);
+int tipc_port_connect(u32 portref, struct tipc_portid const *port);
 
-int tipc_disconnect(u32 portref);
+int tipc_port_disconnect(u32 portref);
 
-int tipc_shutdown(u32 ref);
+int tipc_port_shutdown(u32 ref);
 
+void tipc_port_wakeup(struct tipc_port *port);
 
 /*
  * The following routines require that the port be locked on entry
  */
-int __tipc_disconnect(struct tipc_port *tp_ptr);
-int __tipc_connect(u32 ref, struct tipc_port *p_ptr,
+int __tipc_port_disconnect(struct tipc_port *tp_ptr);
+int __tipc_port_connect(u32 ref, struct tipc_port *p_ptr,
                   struct tipc_portid const *peer);
 int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
 
 /*
  * TIPC messaging routines
  */
-int tipc_port_recv_msg(struct sk_buff *buf);
-int tipc_send(u32 portref, struct iovec const *msg_sect, unsigned int len);
-
-int tipc_send2name(u32 portref, struct tipc_name const *name, u32 domain,
-                  struct iovec const *msg_sect, unsigned int len);
+int tipc_port_rcv(struct sk_buff *buf);
+
+int tipc_send(struct tipc_port *port,
+             struct iovec const *msg_sect,
+             unsigned int len);
+
+int tipc_send2name(struct tipc_port *port,
+                  struct tipc_name const *name,
+                  u32 domain,
+                  struct iovec const *msg_sect,
+                  unsigned int len);
+
+int tipc_send2port(struct tipc_port *port,
+                  struct tipc_portid const *dest,
+                  struct iovec const *msg_sect,
+                  unsigned int len);
+
+int tipc_port_mcast_xmit(struct tipc_port *port,
+                        struct tipc_name_seq const *seq,
+                        struct iovec const *msg,
+                        unsigned int len);
+
+int tipc_port_iovec_reject(struct tipc_port *p_ptr,
+                          struct tipc_msg *hdr,
+                          struct iovec const *msg_sect,
+                          unsigned int len,
+                          int err);
 
-int tipc_send2port(u32 portref, struct tipc_portid const *dest,
-                  struct iovec const *msg_sect, unsigned int len);
-
-int tipc_multicast(u32 portref, struct tipc_name_seq const *seq,
-                  struct iovec const *msg, unsigned int len);
-
-int tipc_port_reject_sections(struct tipc_port *p_ptr, struct tipc_msg *hdr,
-                             struct iovec const *msg_sect, unsigned int len,
-                             int err);
 struct sk_buff *tipc_port_get_ports(void);
-void tipc_port_recv_proto_msg(struct sk_buff *buf);
-void tipc_port_recv_mcast(struct sk_buff *buf, struct tipc_port_list *dp);
+void tipc_port_proto_rcv(struct sk_buff *buf);
+void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp);
 void tipc_port_reinit(void);
 
 /**
@@ -188,14 +185,53 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr)
        spin_unlock_bh(p_ptr->lock);
 }
 
-static inline struct tipc_port *tipc_port_deref(u32 ref)
+static inline int tipc_port_congested(struct tipc_port *p_ptr)
 {
-       return (struct tipc_port *)tipc_ref_deref(ref);
+       return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
 }
 
-static inline int tipc_port_congested(struct tipc_port *p_ptr)
+
+static inline u32 tipc_port_peernode(struct tipc_port *p_ptr)
 {
-       return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
+       return msg_destnode(&p_ptr->phdr);
+}
+
+static inline u32 tipc_port_peerport(struct tipc_port *p_ptr)
+{
+       return msg_destport(&p_ptr->phdr);
+}
+
+static inline  bool tipc_port_unreliable(struct tipc_port *port)
+{
+       return msg_src_droppable(&port->phdr) != 0;
+}
+
+static inline void tipc_port_set_unreliable(struct tipc_port *port,
+                                           bool unreliable)
+{
+       msg_set_src_droppable(&port->phdr, unreliable ? 1 : 0);
+}
+
+static inline bool tipc_port_unreturnable(struct tipc_port *port)
+{
+       return msg_dest_droppable(&port->phdr) != 0;
+}
+
+static inline void tipc_port_set_unreturnable(struct tipc_port *port,
+                                            bool unreturnable)
+{
+       msg_set_dest_droppable(&port->phdr, unreturnable ? 1 : 0);
+}
+
+
+static inline int tipc_port_importance(struct tipc_port *port)
+{
+       return msg_importance(&port->phdr);
+}
+
+static inline void tipc_port_set_importance(struct tipc_port *port, int imp)
+{
+       msg_set_importance(&port->phdr, (u32)imp);
 }
 
 #endif
index 2a2a938dc22cb3c14def50169afffa37ea5bec86..3d4ecd754eeef578e708e8219d8dc636093ccdfe 100644 (file)
@@ -89,7 +89,7 @@ struct ref_table {
 
 static struct ref_table tipc_ref_table;
 
-static DEFINE_RWLOCK(ref_table_lock);
+static DEFINE_SPINLOCK(ref_table_lock);
 
 /**
  * tipc_ref_table_init - create reference table for objects
@@ -126,9 +126,6 @@ int tipc_ref_table_init(u32 requested_size, u32 start)
  */
 void tipc_ref_table_stop(void)
 {
-       if (!tipc_ref_table.entries)
-               return;
-
        vfree(tipc_ref_table.entries);
        tipc_ref_table.entries = NULL;
 }
@@ -162,7 +159,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
        }
 
        /* take a free entry, if available; otherwise initialize a new entry */
-       write_lock_bh(&ref_table_lock);
+       spin_lock_bh(&ref_table_lock);
        if (tipc_ref_table.first_free) {
                index = tipc_ref_table.first_free;
                entry = &(tipc_ref_table.entries[index]);
@@ -178,7 +175,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
        } else {
                ref = 0;
        }
-       write_unlock_bh(&ref_table_lock);
+       spin_unlock_bh(&ref_table_lock);
 
        /*
         * Grab the lock so no one else can modify this entry
@@ -219,7 +216,7 @@ void tipc_ref_discard(u32 ref)
        index = ref & index_mask;
        entry = &(tipc_ref_table.entries[index]);
 
-       write_lock_bh(&ref_table_lock);
+       spin_lock_bh(&ref_table_lock);
 
        if (!entry->object) {
                pr_err("Attempt to discard ref. to non-existent obj\n");
@@ -245,7 +242,7 @@ void tipc_ref_discard(u32 ref)
        tipc_ref_table.last_free = index;
 
 exit:
-       write_unlock_bh(&ref_table_lock);
+       spin_unlock_bh(&ref_table_lock);
 }
 
 /**
@@ -267,20 +264,3 @@ void *tipc_ref_lock(u32 ref)
        }
        return NULL;
 }
-
-
-/**
- * tipc_ref_deref - return pointer referenced object (without locking it)
- */
-void *tipc_ref_deref(u32 ref)
-{
-       if (likely(tipc_ref_table.entries)) {
-               struct reference *entry;
-
-               entry = &tipc_ref_table.entries[ref &
-                                               tipc_ref_table.index_mask];
-               if (likely(entry->ref == ref))
-                       return entry->object;
-       }
-       return NULL;
-}
index 5bc8e7ab84de8192ca71c97a0ae415474f8e266c..d01aa1df63b86e391ed61a2fb2b31ff245fdc87e 100644 (file)
@@ -44,6 +44,5 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock);
 void tipc_ref_discard(u32 ref);
 
 void *tipc_ref_lock(u32 ref);
-void *tipc_ref_deref(u32 ref);
 
 #endif
index b635ca347a870dc55187c221b3df1f2dc295a333..646a930eefbf8fa9a86cfe7011848143aafa49b8 100644 (file)
@@ -87,7 +87,6 @@ static void tipc_clean_outqueues(struct tipc_conn *con);
 static void tipc_conn_kref_release(struct kref *kref)
 {
        struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
-       struct tipc_server *s = con->server;
 
        if (con->sock) {
                tipc_sock_release_local(con->sock);
@@ -95,10 +94,6 @@ static void tipc_conn_kref_release(struct kref *kref)
        }
 
        tipc_clean_outqueues(con);
-
-       if (con->conid)
-               s->tipc_conn_shutdown(con->conid, con->usr_data);
-
        kfree(con);
 }
 
@@ -181,6 +176,9 @@ static void tipc_close_conn(struct tipc_conn *con)
        struct tipc_server *s = con->server;
 
        if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
+               if (con->conid)
+                       s->tipc_conn_shutdown(con->conid, con->usr_data);
+
                spin_lock_bh(&s->idr_lock);
                idr_remove(&s->conn_idr, con->conid);
                s->idr_in_use--;
@@ -429,10 +427,12 @@ int tipc_conn_sendmsg(struct tipc_server *s, int conid,
        list_add_tail(&e->list, &con->outqueue);
        spin_unlock_bh(&con->outqueue_lock);
 
-       if (test_bit(CF_CONNECTED, &con->flags))
+       if (test_bit(CF_CONNECTED, &con->flags)) {
                if (!queue_work(s->send_wq, &con->swork))
                        conn_put(con);
-
+       } else {
+               conn_put(con);
+       }
        return 0;
 }
 
@@ -573,7 +573,6 @@ int tipc_server_start(struct tipc_server *s)
                kmem_cache_destroy(s->rcvbuf_cache);
                return ret;
        }
-       s->enabled = 1;
        return ret;
 }
 
@@ -583,10 +582,6 @@ void tipc_server_stop(struct tipc_server *s)
        int total = 0;
        int id;
 
-       if (!s->enabled)
-               return;
-
-       s->enabled = 0;
        spin_lock_bh(&s->idr_lock);
        for (id = 0; total < s->idr_in_use; id++) {
                con = idr_find(&s->conn_idr, id);
index 98b23f20bc0f5cbb1631111177bd0d88adfcaa68..be817b0b547e87148a103284adc5285a66147c28 100644 (file)
@@ -56,7 +56,6 @@
  * @name: server name
  * @imp: message importance
  * @type: socket type
- * @enabled: identify whether server is launched or not
  */
 struct tipc_server {
        struct idr conn_idr;
@@ -74,7 +73,6 @@ struct tipc_server {
        const char name[TIPC_SERVER_NAME_LEN];
        int imp;
        int type;
-       int enabled;
 };
 
 int tipc_conn_sendmsg(struct tipc_server *s, int conid,
index aab4948f0affa995adc2603bd09db4b5d354b266..29b7f26a12cf6b29c0bac4c65354385fad036391 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * net/tipc/socket.c: TIPC socket API
  *
- * Copyright (c) 2001-2007, 2012 Ericsson AB
+ * Copyright (c) 2001-2007, 2012-2014, Ericsson AB
  * Copyright (c) 2004-2008, 2010-2013, Wind River Systems
  * All rights reserved.
  *
 #include "port.h"
 
 #include <linux/export.h>
-#include <net/sock.h>
 
 #define SS_LISTENING   -1      /* socket is listening */
 #define SS_READY       -2      /* socket is connectionless */
 
 #define CONN_TIMEOUT_DEFAULT   8000    /* default connect timeout = 8s */
 
-struct tipc_sock {
-       struct sock sk;
-       struct tipc_port *p;
-       struct tipc_portid peer_name;
-       unsigned int conn_timeout;
-};
-
-#define tipc_sk(sk) ((struct tipc_sock *)(sk))
-#define tipc_sk_port(sk) (tipc_sk(sk)->p)
-
 static int backlog_rcv(struct sock *sk, struct sk_buff *skb);
-static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf);
-static void wakeupdispatch(struct tipc_port *tport);
 static void tipc_data_ready(struct sock *sk, int len);
 static void tipc_write_space(struct sock *sk);
-static int release(struct socket *sock);
-static int accept(struct socket *sock, struct socket *new_sock, int flags);
+static int tipc_release(struct socket *sock);
+static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
 
 static const struct proto_ops packet_ops;
 static const struct proto_ops stream_ops;
@@ -70,8 +57,6 @@ static const struct proto_ops msg_ops;
 static struct proto tipc_proto;
 static struct proto tipc_proto_kern;
 
-static int sockets_enabled;
-
 /*
  * Revised TIPC socket locking policy:
  *
@@ -117,6 +102,8 @@ static int sockets_enabled;
  *   - port reference
  */
 
+#include "socket.h"
+
 /**
  * advance_rx_queue - discard first buffer in socket receive queue
  *
@@ -152,13 +139,15 @@ static void reject_rx_queue(struct sock *sk)
  *
  * Returns 0 on success, errno otherwise
  */
-static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
-                         int kern)
+static int tipc_sk_create(struct net *net, struct socket *sock,
+                         int protocol, int kern)
 {
        const struct proto_ops *ops;
        socket_state state;
        struct sock *sk;
-       struct tipc_port *tp_ptr;
+       struct tipc_sock *tsk;
+       struct tipc_port *port;
+       u32 ref;
 
        /* Validate arguments */
        if (unlikely(protocol != 0))
@@ -191,10 +180,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
        if (sk == NULL)
                return -ENOMEM;
 
-       /* Allocate TIPC port for socket to use */
-       tp_ptr = tipc_createport(sk, &dispatch, &wakeupdispatch,
-                                TIPC_LOW_IMPORTANCE);
-       if (unlikely(!tp_ptr)) {
+       tsk = tipc_sk(sk);
+       port = &tsk->port;
+
+       ref = tipc_port_init(port, TIPC_LOW_IMPORTANCE);
+       if (!ref) {
+               pr_warn("Socket registration failed, ref. table exhausted\n");
                sk_free(sk);
                return -ENOMEM;
        }
@@ -208,17 +199,14 @@ static int tipc_sk_create(struct net *net, struct socket *sock, int protocol,
        sk->sk_rcvbuf = sysctl_tipc_rmem[1];
        sk->sk_data_ready = tipc_data_ready;
        sk->sk_write_space = tipc_write_space;
-       tipc_sk(sk)->p = tp_ptr;
        tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT;
-
-       spin_unlock_bh(tp_ptr->lock);
+       tipc_port_unlock(port);
 
        if (sock->state == SS_READY) {
-               tipc_set_portunreturnable(tp_ptr->ref, 1);
+               tipc_port_set_unreturnable(port, true);
                if (sock->type == SOCK_DGRAM)
-                       tipc_set_portunreliable(tp_ptr->ref, 1);
+                       tipc_port_set_unreliable(port, true);
        }
-
        return 0;
 }
 
@@ -256,7 +244,7 @@ int tipc_sock_create_local(int type, struct socket **res)
  */
 void tipc_sock_release_local(struct socket *sock)
 {
-       release(sock);
+       tipc_release(sock);
        sock->ops = NULL;
        sock_release(sock);
 }
@@ -282,7 +270,7 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
        if (ret < 0)
                return ret;
 
-       ret = accept(sock, *newsock, flags);
+       ret = tipc_accept(sock, *newsock, flags);
        if (ret < 0) {
                sock_release(*newsock);
                return ret;
@@ -292,7 +280,7 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
 }
 
 /**
- * release - destroy a TIPC socket
+ * tipc_release - destroy a TIPC socket
  * @sock: socket to destroy
  *
  * This routine cleans up any messages that are still queued on the socket.
@@ -307,10 +295,11 @@ int tipc_sock_accept_local(struct socket *sock, struct socket **newsock,
  *
  * Returns 0 on success, errno otherwise
  */
-static int release(struct socket *sock)
+static int tipc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport;
+       struct tipc_sock *tsk;
+       struct tipc_port *port;
        struct sk_buff *buf;
        int res;
 
@@ -321,7 +310,8 @@ static int release(struct socket *sock)
        if (sk == NULL)
                return 0;
 
-       tport = tipc_sk_port(sk);
+       tsk = tipc_sk(sk);
+       port = &tsk->port;
        lock_sock(sk);
 
        /*
@@ -338,17 +328,16 @@ static int release(struct socket *sock)
                        if ((sock->state == SS_CONNECTING) ||
                            (sock->state == SS_CONNECTED)) {
                                sock->state = SS_DISCONNECTING;
-                               tipc_disconnect(tport->ref);
+                               tipc_port_disconnect(port->ref);
                        }
                        tipc_reject_msg(buf, TIPC_ERR_NO_PORT);
                }
        }
 
-       /*
-        * Delete TIPC port; this ensures no more messages are queued
-        * (also disconnects an active connection & sends a 'FIN-' to peer)
+       /* Destroy TIPC port; also disconnects an active connection and
+        * sends a 'FIN-' to peer.
         */
-       res = tipc_deleteport(tport);
+       tipc_port_destroy(port);
 
        /* Discard any remaining (connection-based) messages in receive queue */
        __skb_queue_purge(&sk->sk_receive_queue);
@@ -364,7 +353,7 @@ static int release(struct socket *sock)
 }
 
 /**
- * bind - associate or disassocate TIPC name(s) with a socket
+ * tipc_bind - associate or disassocate TIPC name(s) with a socket
  * @sock: socket structure
  * @uaddr: socket address describing name(s) and desired operation
  * @uaddr_len: size of socket address data structure
@@ -378,16 +367,17 @@ static int release(struct socket *sock)
  * NOTE: This routine doesn't need to take the socket lock since it doesn't
  *       access any non-constant socket information.
  */
-static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
+static int tipc_bind(struct socket *sock, struct sockaddr *uaddr,
+                    int uaddr_len)
 {
        struct sock *sk = sock->sk;
        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
-       struct tipc_port *tport = tipc_sk_port(sock->sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        int res = -EINVAL;
 
        lock_sock(sk);
        if (unlikely(!uaddr_len)) {
-               res = tipc_withdraw(tport, 0, NULL);
+               res = tipc_withdraw(&tsk->port, 0, NULL);
                goto exit;
        }
 
@@ -415,15 +405,15 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
        }
 
        res = (addr->scope > 0) ?
-               tipc_publish(tport, addr->scope, &addr->addr.nameseq) :
-               tipc_withdraw(tport, -addr->scope, &addr->addr.nameseq);
+               tipc_publish(&tsk->port, addr->scope, &addr->addr.nameseq) :
+               tipc_withdraw(&tsk->port, -addr->scope, &addr->addr.nameseq);
 exit:
        release_sock(sk);
        return res;
 }
 
 /**
- * get_name - get port ID of socket or peer socket
+ * tipc_getname - get port ID of socket or peer socket
  * @sock: socket structure
  * @uaddr: area for returned socket address
  * @uaddr_len: area for returned length of socket address
@@ -435,21 +425,21 @@ exit:
  *       accesses socket information that is unchanging (or which changes in
  *       a completely predictable manner).
  */
-static int get_name(struct socket *sock, struct sockaddr *uaddr,
-                   int *uaddr_len, int peer)
+static int tipc_getname(struct socket *sock, struct sockaddr *uaddr,
+                       int *uaddr_len, int peer)
 {
        struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
-       struct tipc_sock *tsock = tipc_sk(sock->sk);
+       struct tipc_sock *tsk = tipc_sk(sock->sk);
 
        memset(addr, 0, sizeof(*addr));
        if (peer) {
                if ((sock->state != SS_CONNECTED) &&
                        ((peer != 2) || (sock->state != SS_DISCONNECTING)))
                        return -ENOTCONN;
-               addr->addr.id.ref = tsock->peer_name.ref;
-               addr->addr.id.node = tsock->peer_name.node;
+               addr->addr.id.ref = tipc_port_peerport(&tsk->port);
+               addr->addr.id.node = tipc_port_peernode(&tsk->port);
        } else {
-               addr->addr.id.ref = tsock->p->ref;
+               addr->addr.id.ref = tsk->port.ref;
                addr->addr.id.node = tipc_own_addr;
        }
 
@@ -463,7 +453,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
 }
 
 /**
- * poll - read and possibly block on pollmask
+ * tipc_poll - read and possibly block on pollmask
  * @file: file structure associated with the socket
  * @sock: socket for which to calculate the poll bits
  * @wait: ???
@@ -502,22 +492,23 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
  * imply that the operation will succeed, merely that it should be performed
  * and will not block.
  */
-static unsigned int poll(struct file *file, struct socket *sock,
-                        poll_table *wait)
+static unsigned int tipc_poll(struct file *file, struct socket *sock,
+                             poll_table *wait)
 {
        struct sock *sk = sock->sk;
+       struct tipc_sock *tsk = tipc_sk(sk);
        u32 mask = 0;
 
        sock_poll_wait(file, sk_sleep(sk), wait);
 
        switch ((int)sock->state) {
        case SS_UNCONNECTED:
-               if (!tipc_sk_port(sk)->congested)
+               if (!tsk->port.congested)
                        mask |= POLLOUT;
                break;
        case SS_READY:
        case SS_CONNECTED:
-               if (!tipc_sk_port(sk)->congested)
+               if (!tsk->port.congested)
                        mask |= POLLOUT;
                /* fall thru' */
        case SS_CONNECTING:
@@ -567,7 +558,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m)
 static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        DEFINE_WAIT(wait);
        int done;
 
@@ -583,14 +574,15 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
                        return sock_intr_errno(*timeo_p);
 
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-               done = sk_wait_event(sk, timeo_p, !tport->congested);
+               done = sk_wait_event(sk, timeo_p, !tsk->port.congested);
                finish_wait(sk_sleep(sk), &wait);
        } while (!done);
        return 0;
 }
 
+
 /**
- * send_msg - send message in connectionless manner
+ * tipc_sendmsg - send message in connectionless manner
  * @iocb: if NULL, indicates that socket lock is already held
  * @sock: socket structure
  * @m: message to send
@@ -603,11 +595,12 @@ static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p)
  *
  * Returns the number of bytes sent on success, or errno otherwise
  */
-static int send_msg(struct kiocb *iocb, struct socket *sock,
-                   struct msghdr *m, size_t total_len)
+static int tipc_sendmsg(struct kiocb *iocb, struct socket *sock,
+                       struct msghdr *m, size_t total_len)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        int needs_conn;
        long timeo;
@@ -634,13 +627,13 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
                        res = -EISCONN;
                        goto exit;
                }
-               if (tport->published) {
+               if (tsk->port.published) {
                        res = -EOPNOTSUPP;
                        goto exit;
                }
                if (dest->addrtype == TIPC_ADDR_NAME) {
-                       tport->conn_type = dest->addr.name.name.type;
-                       tport->conn_instance = dest->addr.name.name.instance;
+                       tsk->port.conn_type = dest->addr.name.name.type;
+                       tsk->port.conn_instance = dest->addr.name.name.instance;
                }
 
                /* Abort any pending connection attempts (very unlikely) */
@@ -653,13 +646,13 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
                        res = dest_name_check(dest, m);
                        if (res)
                                break;
-                       res = tipc_send2name(tport->ref,
+                       res = tipc_send2name(port,
                                             &dest->addr.name.name,
                                             dest->addr.name.domain,
                                             m->msg_iov,
                                             total_len);
                } else if (dest->addrtype == TIPC_ADDR_ID) {
-                       res = tipc_send2port(tport->ref,
+                       res = tipc_send2port(port,
                                             &dest->addr.id,
                                             m->msg_iov,
                                             total_len);
@@ -671,10 +664,10 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
                        res = dest_name_check(dest, m);
                        if (res)
                                break;
-                       res = tipc_multicast(tport->ref,
-                                            &dest->addr.nameseq,
-                                            m->msg_iov,
-                                            total_len);
+                       res = tipc_port_mcast_xmit(port,
+                                                  &dest->addr.nameseq,
+                                                  m->msg_iov,
+                                                  total_len);
                }
                if (likely(res != -ELINKCONG)) {
                        if (needs_conn && (res >= 0))
@@ -695,7 +688,8 @@ exit:
 static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        DEFINE_WAIT(wait);
        int done;
 
@@ -714,14 +708,14 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
 
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                done = sk_wait_event(sk, timeo_p,
-                                    (!tport->congested || !tport->connected));
+                                    (!port->congested || !port->connected));
                finish_wait(sk_sleep(sk), &wait);
        } while (!done);
        return 0;
 }
 
 /**
- * send_packet - send a connection-oriented message
+ * tipc_send_packet - send a connection-oriented message
  * @iocb: if NULL, indicates that socket lock is already held
  * @sock: socket structure
  * @m: message to send
@@ -731,18 +725,18 @@ static int tipc_wait_for_sndpkt(struct socket *sock, long *timeo_p)
  *
  * Returns the number of bytes sent on success, or errno otherwise
  */
-static int send_packet(struct kiocb *iocb, struct socket *sock,
-                      struct msghdr *m, size_t total_len)
+static int tipc_send_packet(struct kiocb *iocb, struct socket *sock,
+                           struct msghdr *m, size_t total_len)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_tipc *, dest, m->msg_name);
        int res = -EINVAL;
        long timeo;
 
        /* Handle implied connection establishment */
        if (unlikely(dest))
-               return send_msg(iocb, sock, m, total_len);
+               return tipc_sendmsg(iocb, sock, m, total_len);
 
        if (total_len > TIPC_MAX_USER_MSG_SIZE)
                return -EMSGSIZE;
@@ -760,7 +754,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
 
        timeo = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT);
        do {
-               res = tipc_send(tport->ref, m->msg_iov, total_len);
+               res = tipc_send(&tsk->port, m->msg_iov, total_len);
                if (likely(res != -ELINKCONG))
                        break;
                res = tipc_wait_for_sndpkt(sock, &timeo);
@@ -774,7 +768,7 @@ exit:
 }
 
 /**
- * send_stream - send stream-oriented data
+ * tipc_send_stream - send stream-oriented data
  * @iocb: (unused)
  * @sock: socket structure
  * @m: data to send
@@ -785,11 +779,11 @@ exit:
  * Returns the number of bytes sent on success (or partial success),
  * or errno if no data sent
  */
-static int send_stream(struct kiocb *iocb, struct socket *sock,
-                      struct msghdr *m, size_t total_len)
+static int tipc_send_stream(struct kiocb *iocb, struct socket *sock,
+                           struct msghdr *m, size_t total_len)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
        struct msghdr my_msg;
        struct iovec my_iov;
        struct iovec *curr_iov;
@@ -806,7 +800,7 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
        /* Handle special cases where there is no connection */
        if (unlikely(sock->state != SS_CONNECTED)) {
                if (sock->state == SS_UNCONNECTED)
-                       res = send_packet(NULL, sock, m, total_len);
+                       res = tipc_send_packet(NULL, sock, m, total_len);
                else
                        res = sock->state == SS_DISCONNECTING ? -EPIPE : -ENOTCONN;
                goto exit;
@@ -837,21 +831,22 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
        my_msg.msg_name = NULL;
        bytes_sent = 0;
 
-       hdr_size = msg_hdr_sz(&tport->phdr);
+       hdr_size = msg_hdr_sz(&tsk->port.phdr);
 
        while (curr_iovlen--) {
                curr_start = curr_iov->iov_base;
                curr_left = curr_iov->iov_len;
 
                while (curr_left) {
-                       bytes_to_send = tport->max_pkt - hdr_size;
+                       bytes_to_send = tsk->port.max_pkt - hdr_size;
                        if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE)
                                bytes_to_send = TIPC_MAX_USER_MSG_SIZE;
                        if (curr_left < bytes_to_send)
                                bytes_to_send = curr_left;
                        my_iov.iov_base = curr_start;
                        my_iov.iov_len = bytes_to_send;
-                       res = send_packet(NULL, sock, &my_msg, bytes_to_send);
+                       res = tipc_send_packet(NULL, sock, &my_msg,
+                                              bytes_to_send);
                        if (res < 0) {
                                if (bytes_sent)
                                        res = bytes_sent;
@@ -872,27 +867,25 @@ exit:
 
 /**
  * auto_connect - complete connection setup to a remote port
- * @sock: socket structure
+ * @tsk: tipc socket structure
  * @msg: peer's response message
  *
  * Returns 0 on success, errno otherwise
  */
-static int auto_connect(struct socket *sock, struct tipc_msg *msg)
+static int auto_connect(struct tipc_sock *tsk, struct tipc_msg *msg)
 {
-       struct tipc_sock *tsock = tipc_sk(sock->sk);
-       struct tipc_port *p_ptr;
+       struct tipc_port *port = &tsk->port;
+       struct socket *sock = tsk->sk.sk_socket;
+       struct tipc_portid peer;
 
-       tsock->peer_name.ref = msg_origport(msg);
-       tsock->peer_name.node = msg_orignode(msg);
-       p_ptr = tipc_port_deref(tsock->p->ref);
-       if (!p_ptr)
-               return -EINVAL;
+       peer.ref = msg_origport(msg);
+       peer.node = msg_orignode(msg);
 
-       __tipc_connect(tsock->p->ref, p_ptr, &tsock->peer_name);
+       __tipc_port_connect(port->ref, port, &peer);
 
        if (msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)
                return -EINVAL;
-       msg_set_importance(&p_ptr->phdr, (u32)msg_importance(msg));
+       msg_set_importance(&port->phdr, (u32)msg_importance(msg));
        sock->state = SS_CONNECTED;
        return 0;
 }
@@ -999,7 +992,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
 
        for (;;) {
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
+               if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
                        if (sock->state == SS_DISCONNECTING) {
                                err = -ENOTCONN;
                                break;
@@ -1023,7 +1016,7 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
 }
 
 /**
- * recv_msg - receive packet-oriented message
+ * tipc_recvmsg - receive packet-oriented message
  * @iocb: (unused)
  * @m: descriptor for message info
  * @buf_len: total size of user buffer area
@@ -1034,11 +1027,12 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long timeo)
  *
  * Returns size of returned message data, errno otherwise
  */
-static int recv_msg(struct kiocb *iocb, struct socket *sock,
-                   struct msghdr *m, size_t buf_len, int flags)
+static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
+                       struct msghdr *m, size_t buf_len, int flags)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1081,7 +1075,7 @@ restart:
        set_orig_addr(m, msg);
 
        /* Capture ancillary data (optional) */
-       res = anc_data_recv(m, msg, tport);
+       res = anc_data_recv(m, msg, port);
        if (res)
                goto exit;
 
@@ -1107,8 +1101,8 @@ restart:
        /* Consume received message (optional) */
        if (likely(!(flags & MSG_PEEK))) {
                if ((sock->state != SS_READY) &&
-                   (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
-                       tipc_acknowledge(tport->ref, tport->conn_unacked);
+                   (++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                       tipc_acknowledge(port->ref, port->conn_unacked);
                advance_rx_queue(sk);
        }
 exit:
@@ -1117,7 +1111,7 @@ exit:
 }
 
 /**
- * recv_stream - receive stream-oriented data
+ * tipc_recv_stream - receive stream-oriented data
  * @iocb: (unused)
  * @m: descriptor for message info
  * @buf_len: total size of user buffer area
@@ -1128,11 +1122,12 @@ exit:
  *
  * Returns size of returned message data, errno otherwise
  */
-static int recv_stream(struct kiocb *iocb, struct socket *sock,
-                      struct msghdr *m, size_t buf_len, int flags)
+static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock,
+                           struct msghdr *m, size_t buf_len, int flags)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        struct tipc_msg *msg;
        long timeo;
@@ -1177,7 +1172,7 @@ restart:
        /* Optionally capture sender's address & ancillary data of first msg */
        if (sz_copied == 0) {
                set_orig_addr(m, msg);
-               res = anc_data_recv(m, msg, tport);
+               res = anc_data_recv(m, msg, port);
                if (res)
                        goto exit;
        }
@@ -1215,8 +1210,8 @@ restart:
 
        /* Consume received message (optional) */
        if (likely(!(flags & MSG_PEEK))) {
-               if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
-                       tipc_acknowledge(tport->ref, tport->conn_unacked);
+               if (unlikely(++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
+                       tipc_acknowledge(port->ref, port->conn_unacked);
                advance_rx_queue(sk);
        }
 
@@ -1268,17 +1263,19 @@ static void tipc_data_ready(struct sock *sk, int len)
 
 /**
  * filter_connect - Handle all incoming messages for a connection-based socket
- * @tsock: TIPC socket
+ * @tsk: TIPC socket
  * @msg: message
  *
  * Returns TIPC error status code and socket error status code
  * once it encounters some errors
  */
-static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
+static u32 filter_connect(struct tipc_sock *tsk, struct sk_buff **buf)
 {
-       struct socket *sock = tsock->sk.sk_socket;
+       struct sock *sk = &tsk->sk;
+       struct tipc_port *port = &tsk->port;
+       struct socket *sock = sk->sk_socket;
        struct tipc_msg *msg = buf_msg(*buf);
-       struct sock *sk = &tsock->sk;
+
        u32 retval = TIPC_ERR_NO_PORT;
        int res;
 
@@ -1288,10 +1285,10 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
        switch ((int)sock->state) {
        case SS_CONNECTED:
                /* Accept only connection-based messages sent by peer */
-               if (msg_connected(msg) && tipc_port_peer_msg(tsock->p, msg)) {
+               if (msg_connected(msg) && tipc_port_peer_msg(port, msg)) {
                        if (unlikely(msg_errcode(msg))) {
                                sock->state = SS_DISCONNECTING;
-                               __tipc_disconnect(tsock->p);
+                               __tipc_port_disconnect(port);
                        }
                        retval = TIPC_OK;
                }
@@ -1308,7 +1305,7 @@ static u32 filter_connect(struct tipc_sock *tsock, struct sk_buff **buf)
                if (unlikely(!msg_connected(msg)))
                        break;
 
-               res = auto_connect(sock, msg);
+               res = auto_connect(tsk, msg);
                if (res) {
                        sock->state = SS_DISCONNECTING;
                        sk->sk_err = -res;
@@ -1387,6 +1384,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf)
 static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
 {
        struct socket *sock = sk->sk_socket;
+       struct tipc_sock *tsk = tipc_sk(sk);
        struct tipc_msg *msg = buf_msg(buf);
        unsigned int limit = rcvbuf_limit(sk, buf);
        u32 res = TIPC_OK;
@@ -1399,7 +1397,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
                if (msg_connected(msg))
                        return TIPC_ERR_NO_PORT;
        } else {
-               res = filter_connect(tipc_sk(sk), &buf);
+               res = filter_connect(tsk, &buf);
                if (res != TIPC_OK || buf == NULL)
                        return res;
        }
@@ -1437,17 +1435,16 @@ static int backlog_rcv(struct sock *sk, struct sk_buff *buf)
 }
 
 /**
- * dispatch - handle incoming message
- * @tport: TIPC port that received message
+ * tipc_sk_rcv - handle incoming message
+ * @sk:  socket receiving message
  * @buf: message
  *
  * Called with port lock already taken.
  *
  * Returns TIPC error status code (TIPC_OK if message is not to be rejected)
  */
-static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
+u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf)
 {
-       struct sock *sk = tport->sk;
        u32 res;
 
        /*
@@ -1470,19 +1467,6 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
        return res;
 }
 
-/**
- * wakeupdispatch - wake up port after congestion
- * @tport: port to wakeup
- *
- * Called with port lock already taken.
- */
-static void wakeupdispatch(struct tipc_port *tport)
-{
-       struct sock *sk = tport->sk;
-
-       sk->sk_write_space(sk);
-}
-
 static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
 {
        struct sock *sk = sock->sk;
@@ -1506,7 +1490,7 @@ static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
 }
 
 /**
- * connect - establish a connection to another TIPC port
+ * tipc_connect - establish a connection to another TIPC port
  * @sock: socket structure
  * @dest: socket address for destination port
  * @destlen: size of socket address data structure
@@ -1514,8 +1498,8 @@ static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
  *
  * Returns 0 on success, errno otherwise
  */
-static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
-                  int flags)
+static int tipc_connect(struct socket *sock, struct sockaddr *dest,
+                       int destlen, int flags)
 {
        struct sock *sk = sock->sk;
        struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest;
@@ -1556,7 +1540,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
                if (!timeout)
                        m.msg_flags = MSG_DONTWAIT;
 
-               res = send_msg(NULL, sock, &m, 0);
+               res = tipc_sendmsg(NULL, sock, &m, 0);
                if ((res < 0) && (res != -EWOULDBLOCK))
                        goto exit;
 
@@ -1587,13 +1571,13 @@ exit:
 }
 
 /**
- * listen - allow socket to listen for incoming connections
+ * tipc_listen - allow socket to listen for incoming connections
  * @sock: socket structure
  * @len: (unused)
  *
  * Returns 0 on success, errno otherwise
  */
-static int listen(struct socket *sock, int len)
+static int tipc_listen(struct socket *sock, int len)
 {
        struct sock *sk = sock->sk;
        int res;
@@ -1625,7 +1609,7 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
        for (;;) {
                prepare_to_wait_exclusive(sk_sleep(sk), &wait,
                                          TASK_INTERRUPTIBLE);
-               if (skb_queue_empty(&sk->sk_receive_queue)) {
+               if (timeo && skb_queue_empty(&sk->sk_receive_queue)) {
                        release_sock(sk);
                        timeo = schedule_timeout(timeo);
                        lock_sock(sk);
@@ -1648,20 +1632,20 @@ static int tipc_wait_for_accept(struct socket *sock, long timeo)
 }
 
 /**
- * accept - wait for connection request
+ * tipc_accept - wait for connection request
  * @sock: listening socket
  * @newsock: new socket that is to be connected
  * @flags: file-related flags associated with socket
  *
  * Returns 0 on success, errno otherwise
  */
-static int accept(struct socket *sock, struct socket *new_sock, int flags)
+static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags)
 {
        struct sock *new_sk, *sk = sock->sk;
        struct sk_buff *buf;
-       struct tipc_sock *new_tsock;
-       struct tipc_port *new_tport;
+       struct tipc_port *new_port;
        struct tipc_msg *msg;
+       struct tipc_portid peer;
        u32 new_ref;
        long timeo;
        int res;
@@ -1672,7 +1656,6 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
                res = -EINVAL;
                goto exit;
        }
-
        timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
        res = tipc_wait_for_accept(sock, timeo);
        if (res)
@@ -1685,9 +1668,8 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
                goto exit;
 
        new_sk = new_sock->sk;
-       new_tsock = tipc_sk(new_sk);
-       new_tport = new_tsock->p;
-       new_ref = new_tport->ref;
+       new_port = &tipc_sk(new_sk)->port;
+       new_ref = new_port->ref;
        msg = buf_msg(buf);
 
        /* we lock on new_sk; but lockdep sees the lock on sk */
@@ -1700,15 +1682,15 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
        reject_rx_queue(new_sk);
 
        /* Connect new socket to it's peer */
-       new_tsock->peer_name.ref = msg_origport(msg);
-       new_tsock->peer_name.node = msg_orignode(msg);
-       tipc_connect(new_ref, &new_tsock->peer_name);
+       peer.ref = msg_origport(msg);
+       peer.node = msg_orignode(msg);
+       tipc_port_connect(new_ref, &peer);
        new_sock->state = SS_CONNECTED;
 
-       tipc_set_portimportance(new_ref, msg_importance(msg));
+       tipc_port_set_importance(new_port, msg_importance(msg));
        if (msg_named(msg)) {
-               new_tport->conn_type = msg_nametype(msg);
-               new_tport->conn_instance = msg_nameinst(msg);
+               new_port->conn_type = msg_nametype(msg);
+               new_port->conn_instance = msg_nameinst(msg);
        }
 
        /*
@@ -1719,21 +1701,20 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags)
                struct msghdr m = {NULL,};
 
                advance_rx_queue(sk);
-               send_packet(NULL, new_sock, &m, 0);
+               tipc_send_packet(NULL, new_sock, &m, 0);
        } else {
                __skb_dequeue(&sk->sk_receive_queue);
                __skb_queue_head(&new_sk->sk_receive_queue, buf);
                skb_set_owner_r(buf, new_sk);
        }
        release_sock(new_sk);
-
 exit:
        release_sock(sk);
        return res;
 }
 
 /**
- * shutdown - shutdown socket connection
+ * tipc_shutdown - shutdown socket connection
  * @sock: socket structure
  * @how: direction to close (must be SHUT_RDWR)
  *
@@ -1741,10 +1722,11 @@ exit:
  *
  * Returns 0 on success, errno otherwise
  */
-static int shutdown(struct socket *sock, int how)
+static int tipc_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        struct sk_buff *buf;
        int res;
 
@@ -1765,10 +1747,10 @@ restart:
                                kfree_skb(buf);
                                goto restart;
                        }
-                       tipc_disconnect(tport->ref);
+                       tipc_port_disconnect(port->ref);
                        tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN);
                } else {
-                       tipc_shutdown(tport->ref);
+                       tipc_port_shutdown(port->ref);
                }
 
                sock->state = SS_DISCONNECTING;
@@ -1794,7 +1776,7 @@ restart:
 }
 
 /**
- * setsockopt - set socket option
+ * tipc_setsockopt - set socket option
  * @sock: socket structure
  * @lvl: option level
  * @opt: option identifier
@@ -1806,11 +1788,12 @@ restart:
  *
  * Returns 0 on success, errno otherwise
  */
-static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
-                     unsigned int ol)
+static int tipc_setsockopt(struct socket *sock, int lvl, int opt,
+                          char __user *ov, unsigned int ol)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        u32 value;
        int res;
 
@@ -1828,16 +1811,16 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               res = tipc_set_portimportance(tport->ref, value);
+               tipc_port_set_importance(port, value);
                break;
        case TIPC_SRC_DROPPABLE:
                if (sock->type != SOCK_STREAM)
-                       res = tipc_set_portunreliable(tport->ref, value);
+                       tipc_port_set_unreliable(port, value);
                else
                        res = -ENOPROTOOPT;
                break;
        case TIPC_DEST_DROPPABLE:
-               res = tipc_set_portunreturnable(tport->ref, value);
+               tipc_port_set_unreturnable(port, value);
                break;
        case TIPC_CONN_TIMEOUT:
                tipc_sk(sk)->conn_timeout = value;
@@ -1853,7 +1836,7 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
 }
 
 /**
- * getsockopt - get socket option
+ * tipc_getsockopt - get socket option
  * @sock: socket structure
  * @lvl: option level
  * @opt: option identifier
@@ -1865,11 +1848,12 @@ static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
  *
  * Returns 0 on success, errno otherwise
  */
-static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
-                     int __user *ol)
+static int tipc_getsockopt(struct socket *sock, int lvl, int opt,
+                          char __user *ov, int __user *ol)
 {
        struct sock *sk = sock->sk;
-       struct tipc_port *tport = tipc_sk_port(sk);
+       struct tipc_sock *tsk = tipc_sk(sk);
+       struct tipc_port *port = &tsk->port;
        int len;
        u32 value;
        int res;
@@ -1886,13 +1870,13 @@ static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
 
        switch (opt) {
        case TIPC_IMPORTANCE:
-               res = tipc_portimportance(tport->ref, &value);
+               value = tipc_port_importance(port);
                break;
        case TIPC_SRC_DROPPABLE:
-               res = tipc_portunreliable(tport->ref, &value);
+               value = tipc_port_unreliable(port);
                break;
        case TIPC_DEST_DROPPABLE:
-               res = tipc_portunreturnable(tport->ref, &value);
+               value = tipc_port_unreturnable(port);
                break;
        case TIPC_CONN_TIMEOUT:
                value = tipc_sk(sk)->conn_timeout;
@@ -1927,20 +1911,20 @@ static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov,
 static const struct proto_ops msg_ops = {
        .owner          = THIS_MODULE,
        .family         = AF_TIPC,
-       .release        = release,
-       .bind           = bind,
-       .connect        = connect,
+       .release        = tipc_release,
+       .bind           = tipc_bind,
+       .connect        = tipc_connect,
        .socketpair     = sock_no_socketpair,
        .accept         = sock_no_accept,
-       .getname        = get_name,
-       .poll           = poll,
+       .getname        = tipc_getname,
+       .poll           = tipc_poll,
        .ioctl          = sock_no_ioctl,
        .listen         = sock_no_listen,
-       .shutdown       = shutdown,
-       .setsockopt     = setsockopt,
-       .getsockopt     = getsockopt,
-       .sendmsg        = send_msg,
-       .recvmsg        = recv_msg,
+       .shutdown       = tipc_shutdown,
+       .setsockopt     = tipc_setsockopt,
+       .getsockopt     = tipc_getsockopt,
+       .sendmsg        = tipc_sendmsg,
+       .recvmsg        = tipc_recvmsg,
        .mmap           = sock_no_mmap,
        .sendpage       = sock_no_sendpage
 };
@@ -1948,20 +1932,20 @@ static const struct proto_ops msg_ops = {
 static const struct proto_ops packet_ops = {
        .owner          = THIS_MODULE,
        .family         = AF_TIPC,
-       .release        = release,
-       .bind           = bind,
-       .connect        = connect,
+       .release        = tipc_release,
+       .bind           = tipc_bind,
+       .connect        = tipc_connect,
        .socketpair     = sock_no_socketpair,
-       .accept         = accept,
-       .getname        = get_name,
-       .poll           = poll,
+       .accept         = tipc_accept,
+       .getname        = tipc_getname,
+       .poll           = tipc_poll,
        .ioctl          = sock_no_ioctl,
-       .listen         = listen,
-       .shutdown       = shutdown,
-       .setsockopt     = setsockopt,
-       .getsockopt     = getsockopt,
-       .sendmsg        = send_packet,
-       .recvmsg        = recv_msg,
+       .listen         = tipc_listen,
+       .shutdown       = tipc_shutdown,
+       .setsockopt     = tipc_setsockopt,
+       .getsockopt     = tipc_getsockopt,
+       .sendmsg        = tipc_send_packet,
+       .recvmsg        = tipc_recvmsg,
        .mmap           = sock_no_mmap,
        .sendpage       = sock_no_sendpage
 };
@@ -1969,20 +1953,20 @@ static const struct proto_ops packet_ops = {
 static const struct proto_ops stream_ops = {
        .owner          = THIS_MODULE,
        .family         = AF_TIPC,
-       .release        = release,
-       .bind           = bind,
-       .connect        = connect,
+       .release        = tipc_release,
+       .bind           = tipc_bind,
+       .connect        = tipc_connect,
        .socketpair     = sock_no_socketpair,
-       .accept         = accept,
-       .getname        = get_name,
-       .poll           = poll,
+       .accept         = tipc_accept,
+       .getname        = tipc_getname,
+       .poll           = tipc_poll,
        .ioctl          = sock_no_ioctl,
-       .listen         = listen,
-       .shutdown       = shutdown,
-       .setsockopt     = setsockopt,
-       .getsockopt     = getsockopt,
-       .sendmsg        = send_stream,
-       .recvmsg        = recv_stream,
+       .listen         = tipc_listen,
+       .shutdown       = tipc_shutdown,
+       .setsockopt     = tipc_setsockopt,
+       .getsockopt     = tipc_getsockopt,
+       .sendmsg        = tipc_send_stream,
+       .recvmsg        = tipc_recv_stream,
        .mmap           = sock_no_mmap,
        .sendpage       = sock_no_sendpage
 };
@@ -2027,8 +2011,6 @@ int tipc_socket_init(void)
                proto_unregister(&tipc_proto);
                goto out;
        }
-
-       sockets_enabled = 1;
  out:
        return res;
 }
@@ -2038,10 +2020,6 @@ int tipc_socket_init(void)
  */
 void tipc_socket_stop(void)
 {
-       if (!sockets_enabled)
-               return;
-
-       sockets_enabled = 0;
        sock_unregister(tipc_family_ops.family);
        proto_unregister(&tipc_proto);
 }
diff --git a/net/tipc/socket.h b/net/tipc/socket.h
new file mode 100644 (file)
index 0000000..74e5c7f
--- /dev/null
@@ -0,0 +1,72 @@
+/* net/tipc/socket.h: Include file for TIPC socket code
+ *
+ * Copyright (c) 2014, Ericsson AB
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TIPC_SOCK_H
+#define _TIPC_SOCK_H
+
+#include "port.h"
+#include <net/sock.h>
+
+/**
+ * struct tipc_sock - TIPC socket structure
+ * @sk: socket - interacts with 'port' and with user via the socket API
+ * @port: port - interacts with 'sk' and with the rest of the TIPC stack
+ * @peer_name: the peer of the connection, if any
+ * @conn_timeout: the time we can wait for an unresponded setup request
+ */
+
+struct tipc_sock {
+       struct sock sk;
+       struct tipc_port port;
+       unsigned int conn_timeout;
+};
+
+static inline struct tipc_sock *tipc_sk(const struct sock *sk)
+{
+       return container_of(sk, struct tipc_sock, sk);
+}
+
+static inline struct tipc_sock *tipc_port_to_sock(const struct tipc_port *port)
+{
+       return container_of(port, struct tipc_sock, port);
+}
+
+static inline void tipc_sock_wakeup(struct tipc_sock *tsk)
+{
+       tsk->sk.sk_write_space(&tsk->sk);
+}
+
+u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf);
+
+#endif
index 7cb0bd5b1176872dcd09ca830a8a01c5b1ec37c6..642437231ad5d2da2e7c9de5bd4494b082f3472e 100644 (file)
@@ -96,20 +96,16 @@ static void subscr_send_event(struct tipc_subscription *sub, u32 found_lower,
 {
        struct tipc_subscriber *subscriber = sub->subscriber;
        struct kvec msg_sect;
-       int ret;
 
        msg_sect.iov_base = (void *)&sub->evt;
        msg_sect.iov_len = sizeof(struct tipc_event);
-
        sub->evt.event = htohl(event, sub->swap);
        sub->evt.found_lower = htohl(found_lower, sub->swap);
        sub->evt.found_upper = htohl(found_upper, sub->swap);
        sub->evt.port.ref = htohl(port_ref, sub->swap);
        sub->evt.port.node = htohl(node, sub->swap);
-       ret = tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL,
-                               msg_sect.iov_base, msg_sect.iov_len);
-       if (ret < 0)
-               pr_err("Sending subscription event failed, no memory\n");
+       tipc_conn_sendmsg(&topsrv, subscriber->conid, NULL, msg_sect.iov_base,
+                         msg_sect.iov_len);
 }
 
 /**
@@ -153,14 +149,6 @@ static void subscr_timeout(struct tipc_subscription *sub)
        /* The spin lock per subscriber is used to protect its members */
        spin_lock_bh(&subscriber->lock);
 
-       /* Validate if the connection related to the subscriber is
-        * closed (in case subscriber is terminating)
-        */
-       if (subscriber->conid == 0) {
-               spin_unlock_bh(&subscriber->lock);
-               return;
-       }
-
        /* Validate timeout (in case subscription is being cancelled) */
        if (sub->timeout == TIPC_WAIT_FOREVER) {
                spin_unlock_bh(&subscriber->lock);
@@ -215,9 +203,6 @@ static void subscr_release(struct tipc_subscriber *subscriber)
 
        spin_lock_bh(&subscriber->lock);
 
-       /* Invalidate subscriber reference */
-       subscriber->conid = 0;
-
        /* Destroy any existing subscriptions for subscriber */
        list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
                                 subscription_list) {
@@ -278,9 +263,9 @@ static void subscr_cancel(struct tipc_subscr *s,
  *
  * Called with subscriber lock held.
  */
-static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
-                                            struct tipc_subscriber *subscriber)
-{
+static int subscr_subscribe(struct tipc_subscr *s,
+                           struct tipc_subscriber *subscriber,
+                           struct tipc_subscription **sub_p) {
        struct tipc_subscription *sub;
        int swap;
 
@@ -291,23 +276,21 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
        if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
                s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
                subscr_cancel(s, subscriber);
-               return NULL;
+               return 0;
        }
 
        /* Refuse subscription if global limit exceeded */
        if (atomic_read(&subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
                pr_warn("Subscription rejected, limit reached (%u)\n",
                        TIPC_MAX_SUBSCRIPTIONS);
-               subscr_terminate(subscriber);
-               return NULL;
+               return -EINVAL;
        }
 
        /* Allocate subscription object */
        sub = kmalloc(sizeof(*sub), GFP_ATOMIC);
        if (!sub) {
                pr_warn("Subscription rejected, no memory\n");
-               subscr_terminate(subscriber);
-               return NULL;
+               return -ENOMEM;
        }
 
        /* Initialize subscription object */
@@ -321,8 +304,7 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
            (sub->seq.lower > sub->seq.upper)) {
                pr_warn("Subscription rejected, illegal request\n");
                kfree(sub);
-               subscr_terminate(subscriber);
-               return NULL;
+               return -EINVAL;
        }
        INIT_LIST_HEAD(&sub->nameseq_list);
        list_add(&sub->subscription_list, &subscriber->subscription_list);
@@ -335,8 +317,8 @@ static struct tipc_subscription *subscr_subscribe(struct tipc_subscr *s,
                             (Handler)subscr_timeout, (unsigned long)sub);
                k_start_timer(&sub->timer, sub->timeout);
        }
-
-       return sub;
+       *sub_p = sub;
+       return 0;
 }
 
 /* Handle one termination request for the subscriber */
@@ -350,10 +332,14 @@ static void subscr_conn_msg_event(int conid, struct sockaddr_tipc *addr,
                                  void *usr_data, void *buf, size_t len)
 {
        struct tipc_subscriber *subscriber = usr_data;
-       struct tipc_subscription *sub;
+       struct tipc_subscription *sub = NULL;
 
        spin_lock_bh(&subscriber->lock);
-       sub = subscr_subscribe((struct tipc_subscr *)buf, subscriber);
+       if (subscr_subscribe((struct tipc_subscr *)buf, subscriber, &sub) < 0) {
+               spin_unlock_bh(&subscriber->lock);
+               subscr_terminate(subscriber);
+               return;
+       }
        if (sub)
                tipc_nametbl_subscribe(sub);
        spin_unlock_bh(&subscriber->lock);
index 29fc8bee97022f456f8b64b8ff6ff54a977962dd..94404f19f9deebbb7c55b7a1660dd011510ba3fd 100644 (file)
@@ -163,9 +163,8 @@ static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
 
 static inline unsigned int unix_hash_fold(__wsum n)
 {
-       unsigned int hash = (__force unsigned int)n;
+       unsigned int hash = (__force unsigned int)csum_fold(n);
 
-       hash ^= hash>>16;
        hash ^= hash>>8;
        return hash&(UNIX_HASH_SIZE-1);
 }
@@ -1788,8 +1787,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
 
        err = mutex_lock_interruptible(&u->readlock);
-       if (err) {
-               err = sock_intr_errno(sock_rcvtimeo(sk, noblock));
+       if (unlikely(err)) {
+               /* recvmsg() in non blocking mode is supposed to return -EAGAIN
+                * sk_rcvtimeo is not honored by mutex_lock_interruptible()
+                */
+               err = noblock ? -EAGAIN : -ERESTARTSYS;
                goto out;
        }
 
@@ -1914,6 +1916,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
        struct unix_sock *u = unix_sk(sk);
        DECLARE_SOCKADDR(struct sockaddr_un *, sunaddr, msg->msg_name);
        int copied = 0;
+       int noblock = flags & MSG_DONTWAIT;
        int check_creds = 0;
        int target;
        int err = 0;
@@ -1929,7 +1932,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
 
        target = sock_rcvlowat(sk, flags&MSG_WAITALL, size);
-       timeo = sock_rcvtimeo(sk, flags&MSG_DONTWAIT);
+       timeo = sock_rcvtimeo(sk, noblock);
 
        /* Lock the socket to prevent queue disordering
         * while sleeps in memcpy_tomsg
@@ -1941,8 +1944,11 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
        }
 
        err = mutex_lock_interruptible(&u->readlock);
-       if (err) {
-               err = sock_intr_errno(timeo);
+       if (unlikely(err)) {
+               /* recvmsg() in non blocking mode is supposed to return -EAGAIN
+                * sk_rcvtimeo is not honored by mutex_lock_interruptible()
+                */
+               err = noblock ? -EAGAIN : -ERESTARTSYS;
                goto out;
        }
 
index 8659d5cee2a6ba01b4f17830608795768c92d107..9c9501a35fb5c6a43a142132306998405e086774 100644 (file)
@@ -768,6 +768,4 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
        case NUM_NL80211_IFTYPES:
                WARN_ON(1);
        }
-
-       return;
 }
index 276cf938f7646f44201c698ece575258c3606776..086cddd03ba6edd79d1609ecf713146bc756c1ff 100644 (file)
@@ -788,8 +788,6 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
        default:
                break;
        }
-
-       wdev->beacon_interval = 0;
 }
 
 static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
index 39fc1d70da6980a1e9457884e96ee3da582ce259..e5872ff2c27ca8989ca6da7cfdf4d7041c29a72e 100644 (file)
@@ -11,6 +11,7 @@
 #include <net/ip.h>
 #include <net/dsfield.h>
 #include <linux/if_vlan.h>
+#include <linux/mpls.h>
 #include "core.h"
 #include "rdev-ops.h"
 
@@ -717,6 +718,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb,
        case htons(ETH_P_IPV6):
                dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;
                break;
+       case htons(ETH_P_MPLS_UC):
+       case htons(ETH_P_MPLS_MC): {
+               struct mpls_label mpls_tmp, *mpls;
+
+               mpls = skb_header_pointer(skb, sizeof(struct ethhdr),
+                                         sizeof(*mpls), &mpls_tmp);
+               if (!mpls)
+                       return 0;
+
+               return (ntohl(mpls->entry) & MPLS_LS_TC_MASK)
+                       >> MPLS_LS_TC_SHIFT;
+       }
+       case htons(ETH_P_80221):
+               /* 802.21 is always network control traffic */
+               return 7;
        default:
                return 0;
        }
index 6c7ac016ce3a7e780bf4f6361c61189d0d9b9f9e..85d1d476461257b3e248bd870cd9f7217fa21657 100644 (file)
 
 static struct kmem_cache *secpath_cachep __read_mostly;
 
+static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
+static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO];
+
+int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo)
+{
+       int err = 0;
+
+       if (unlikely(afinfo == NULL))
+               return -EINVAL;
+       if (unlikely(afinfo->family >= NPROTO))
+               return -EAFNOSUPPORT;
+       spin_lock_bh(&xfrm_input_afinfo_lock);
+       if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
+               err = -ENOBUFS;
+       else
+               rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo);
+       spin_unlock_bh(&xfrm_input_afinfo_lock);
+       return err;
+}
+EXPORT_SYMBOL(xfrm_input_register_afinfo);
+
+int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo)
+{
+       int err = 0;
+
+       if (unlikely(afinfo == NULL))
+               return -EINVAL;
+       if (unlikely(afinfo->family >= NPROTO))
+               return -EAFNOSUPPORT;
+       spin_lock_bh(&xfrm_input_afinfo_lock);
+       if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) {
+               if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo))
+                       err = -EINVAL;
+               else
+                       RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL);
+       }
+       spin_unlock_bh(&xfrm_input_afinfo_lock);
+       synchronize_rcu();
+       return err;
+}
+EXPORT_SYMBOL(xfrm_input_unregister_afinfo);
+
+static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
+{
+       struct xfrm_input_afinfo *afinfo;
+
+       if (unlikely(family >= NPROTO))
+               return NULL;
+       rcu_read_lock();
+       afinfo = rcu_dereference(xfrm_input_afinfo[family]);
+       if (unlikely(!afinfo))
+               rcu_read_unlock();
+       return afinfo;
+}
+
+static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo)
+{
+       rcu_read_unlock();
+}
+
+static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
+                      int err)
+{
+       int ret;
+       struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
+
+       if (!afinfo)
+               return -EAFNOSUPPORT;
+
+       ret = afinfo->callback(skb, protocol, err);
+       xfrm_input_put_afinfo(afinfo);
+
+       return ret;
+}
+
 void __secpath_destroy(struct sec_path *sp)
 {
        int i;
@@ -108,7 +183,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
        int err;
        __be32 seq;
        __be32 seq_hi;
-       struct xfrm_state *x;
+       struct xfrm_state *x = NULL;
        xfrm_address_t *daddr;
        struct xfrm_mode *inner_mode;
        unsigned int family;
@@ -120,9 +195,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                async = 1;
                x = xfrm_input_state(skb);
                seq = XFRM_SKB_CB(skb)->seq.input.low;
+               family = x->outer_mode->afinfo->family;
                goto resume;
        }
 
+       daddr = (xfrm_address_t *)(skb_network_header(skb) +
+                                  XFRM_SPI_SKB_CB(skb)->daddroff);
+       family = XFRM_SPI_SKB_CB(skb)->family;
+
        /* Allocate new secpath or COW existing one. */
        if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
                struct sec_path *sp;
@@ -137,10 +217,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
                skb->sp = sp;
        }
 
-       daddr = (xfrm_address_t *)(skb_network_header(skb) +
-                                  XFRM_SPI_SKB_CB(skb)->daddroff);
-       family = XFRM_SPI_SKB_CB(skb)->family;
-
        seq = 0;
        if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
                XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
@@ -162,6 +238,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 
                skb->sp->xvec[skb->sp->len++] = x;
 
+               if (xfrm_tunnel_check(skb, x, family)) {
+                       XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
+                       goto drop;
+               }
+
                spin_lock(&x->lock);
                if (unlikely(x->km.state == XFRM_STATE_ACQ)) {
                        XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
@@ -201,7 +282,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 
                if (nexthdr == -EINPROGRESS)
                        return 0;
-
 resume:
                spin_lock(&x->lock);
                if (nexthdr <= 0) {
@@ -263,6 +343,10 @@ resume:
                }
        } while (!err);
 
+       err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
+       if (err)
+               goto drop;
+
        nf_reset(skb);
 
        if (decaps) {
@@ -276,6 +360,7 @@ resume:
 drop_unlock:
        spin_unlock(&x->lock);
 drop:
+       xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
        kfree_skb(skb);
        return 0;
 }
index 4b98b25793c5c23fa1799463b45ad71a030fceb9..f02f511b710741e1779d389ac69bfc75a17ab42f 100644 (file)
@@ -39,8 +39,6 @@
 #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ))
 #define XFRM_MAX_QUEUE_LEN     100
 
-static struct dst_entry *xfrm_policy_sk_bundles;
-
 static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
 static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
                                                __read_mostly;
@@ -661,7 +659,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
                hlist_add_head(&policy->bydst, chain);
        xfrm_pol_hold(policy);
        net->xfrm.policy_count[dir]++;
-       atomic_inc(&flow_cache_genid);
+       atomic_inc(&net->xfrm.flow_cache_genid);
 
        /* After previous checking, family can either be AF_INET or AF_INET6 */
        if (policy->family == AF_INET)
@@ -1158,7 +1156,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
        if (hlist_unhashed(&pol->bydst))
                return NULL;
 
-       hlist_del(&pol->bydst);
+       hlist_del_init(&pol->bydst);
        hlist_del(&pol->byidx);
        list_del(&pol->walk.all);
        net->xfrm.policy_count[dir]--;
@@ -2109,13 +2107,6 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
                                goto no_transform;
                        }
 
-                       dst_hold(&xdst->u.dst);
-
-                       spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
-                       xdst->u.dst.next = xfrm_policy_sk_bundles;
-                       xfrm_policy_sk_bundles = &xdst->u.dst;
-                       spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
-
                        route = xdst->route;
                }
        }
@@ -2549,33 +2540,15 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
        return dst;
 }
 
-static void __xfrm_garbage_collect(struct net *net)
-{
-       struct dst_entry *head, *next;
-
-       spin_lock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
-       head = xfrm_policy_sk_bundles;
-       xfrm_policy_sk_bundles = NULL;
-       spin_unlock_bh(&net->xfrm.xfrm_policy_sk_bundle_lock);
-
-       while (head) {
-               next = head->next;
-               dst_free(head);
-               head = next;
-       }
-}
-
 void xfrm_garbage_collect(struct net *net)
 {
-       flow_cache_flush();
-       __xfrm_garbage_collect(net);
+       flow_cache_flush(net);
 }
 EXPORT_SYMBOL(xfrm_garbage_collect);
 
 static void xfrm_garbage_collect_deferred(struct net *net)
 {
-       flow_cache_flush_deferred();
-       __xfrm_garbage_collect(net);
+       flow_cache_flush_deferred(net);
 }
 
 static void xfrm_init_pmtu(struct dst_entry *dst)
@@ -2940,15 +2913,19 @@ static int __net_init xfrm_net_init(struct net *net)
        rv = xfrm_sysctl_init(net);
        if (rv < 0)
                goto out_sysctl;
+       rv = flow_cache_init(net);
+       if (rv < 0)
+               goto out;
 
        /* Initialize the per-net locks here */
        spin_lock_init(&net->xfrm.xfrm_state_lock);
        rwlock_init(&net->xfrm.xfrm_policy_lock);
-       spin_lock_init(&net->xfrm.xfrm_policy_sk_bundle_lock);
        mutex_init(&net->xfrm.xfrm_cfg_mutex);
 
        return 0;
 
+out:
+       xfrm_sysctl_fini(net);
 out_sysctl:
        xfrm_policy_fini(net);
 out_policy:
@@ -2961,6 +2938,7 @@ out_statistics:
 
 static void __net_exit xfrm_net_exit(struct net *net)
 {
+       flow_cache_fini(net);
        xfrm_sysctl_fini(net);
        xfrm_policy_fini(net);
        xfrm_state_fini(net);
index a26b7aa794755f970756cadb3c817bfc500956d2..8e9c781a6bbaaba83e4af4a31ac7a07a70dd6c71 100644 (file)
@@ -161,6 +161,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
 int __xfrm_state_delete(struct xfrm_state *x);
 
 int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
+bool km_is_alive(const struct km_event *c);
 void km_state_expired(struct xfrm_state *x, int hard, u32 portid);
 
 static DEFINE_SPINLOCK(xfrm_type_lock);
@@ -788,6 +789,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
        struct xfrm_state *best = NULL;
        u32 mark = pol->mark.v & pol->mark.m;
        unsigned short encap_family = tmpl->encap_family;
+       struct km_event c;
 
        to_put = NULL;
 
@@ -832,6 +834,17 @@ found:
                        error = -EEXIST;
                        goto out;
                }
+
+               c.net = net;
+               /* If the KMs have no listeners (yet...), avoid allocating an SA
+                * for each and every packet - garbage collection might not
+                * handle the flood.
+                */
+               if (!km_is_alive(&c)) {
+                       error = -ESRCH;
+                       goto out;
+               }
+
                x = xfrm_state_alloc(net);
                if (x == NULL) {
                        error = -ENOMEM;
@@ -1135,10 +1148,9 @@ out:
 EXPORT_SYMBOL(xfrm_state_add);
 
 #ifdef CONFIG_XFRM_MIGRATE
-static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
+static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig)
 {
        struct net *net = xs_net(orig);
-       int err = -ENOMEM;
        struct xfrm_state *x = xfrm_state_alloc(net);
        if (!x)
                goto out;
@@ -1159,6 +1171,11 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
        }
        x->props.aalgo = orig->props.aalgo;
 
+       if (orig->aead) {
+               x->aead = xfrm_algo_aead_clone(orig->aead);
+               if (!x->aead)
+                       goto error;
+       }
        if (orig->ealg) {
                x->ealg = xfrm_algo_clone(orig->ealg);
                if (!x->ealg)
@@ -1187,20 +1204,21 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
        }
 
        if (orig->replay_esn) {
-               err = xfrm_replay_clone(x, orig);
-               if (err)
+               if (xfrm_replay_clone(x, orig))
                        goto error;
        }
 
        memcpy(&x->mark, &orig->mark, sizeof(x->mark));
 
-       err = xfrm_init_state(x);
-       if (err)
+       if (xfrm_init_state(x) < 0)
                goto error;
 
        x->props.flags = orig->props.flags;
        x->props.extra_flags = orig->props.extra_flags;
 
+       x->tfcpad = orig->tfcpad;
+       x->replay_maxdiff = orig->replay_maxdiff;
+       x->replay_maxage = orig->replay_maxage;
        x->curlft.add_time = orig->curlft.add_time;
        x->km.state = orig->km.state;
        x->km.seq = orig->km.seq;
@@ -1210,16 +1228,15 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp)
  error:
        xfrm_state_put(x);
 out:
-       if (errp)
-               *errp = err;
        return NULL;
 }
 
-/* net->xfrm.xfrm_state_lock is held */
 struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
 {
        unsigned int h;
-       struct xfrm_state *x;
+       struct xfrm_state *x = NULL;
+
+       spin_lock_bh(&net->xfrm.xfrm_state_lock);
 
        if (m->reqid) {
                h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1236,7 +1253,7 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                             m->old_family))
                                continue;
                        xfrm_state_hold(x);
-                       return x;
+                       break;
                }
        } else {
                h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr,
@@ -1251,11 +1268,13 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                             m->old_family))
                                continue;
                        xfrm_state_hold(x);
-                       return x;
+                       break;
                }
        }
 
-       return NULL;
+       spin_unlock_bh(&net->xfrm.xfrm_state_lock);
+
+       return x;
 }
 EXPORT_SYMBOL(xfrm_migrate_state_find);
 
@@ -1263,9 +1282,8 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
                                      struct xfrm_migrate *m)
 {
        struct xfrm_state *xc;
-       int err;
 
-       xc = xfrm_state_clone(x, &err);
+       xc = xfrm_state_clone(x);
        if (!xc)
                return NULL;
 
@@ -1278,7 +1296,7 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
                   state is to be updated as it is a part of triplet */
                xfrm_state_insert(xc);
        } else {
-               if ((err = xfrm_state_add(xc)) < 0)
+               if (xfrm_state_add(xc) < 0)
                        goto error;
        }
 
@@ -1451,7 +1469,7 @@ xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n,
 {
        int err = 0;
        struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family);
-       struct net *net = xs_net(*dst);
+       struct net *net = xs_net(*src);
 
        if (!afinfo)
                return -EAFNOSUPPORT;
@@ -1590,6 +1608,23 @@ unlock:
 }
 EXPORT_SYMBOL(xfrm_alloc_spi);
 
+static bool __xfrm_state_filter_match(struct xfrm_state *x,
+                                     struct xfrm_address_filter *filter)
+{
+       if (filter) {
+               if ((filter->family == AF_INET ||
+                    filter->family == AF_INET6) &&
+                   x->props.family != filter->family)
+                       return false;
+
+               return addr_match(&x->props.saddr, &filter->saddr,
+                                 filter->splen) &&
+                      addr_match(&x->id.daddr, &filter->daddr,
+                                 filter->dplen);
+       }
+       return true;
+}
+
 int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
                    int (*func)(struct xfrm_state *, int, void*),
                    void *data)
@@ -1612,6 +1647,8 @@ int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk,
                state = container_of(x, struct xfrm_state, km);
                if (!xfrm_id_proto_match(state->id.proto, walk->proto))
                        continue;
+               if (!__xfrm_state_filter_match(state, walk->filter))
+                       continue;
                err = func(state, walk->seq, data);
                if (err) {
                        list_move_tail(&walk->all, &x->all);
@@ -1630,17 +1667,21 @@ out:
 }
 EXPORT_SYMBOL(xfrm_state_walk);
 
-void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
+void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto,
+                         struct xfrm_address_filter *filter)
 {
        INIT_LIST_HEAD(&walk->all);
        walk->proto = proto;
        walk->state = XFRM_STATE_DEAD;
        walk->seq = 0;
+       walk->filter = filter;
 }
 EXPORT_SYMBOL(xfrm_state_walk_init);
 
 void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net)
 {
+       kfree(walk->filter);
+
        if (list_empty(&walk->all))
                return;
 
@@ -1793,6 +1834,24 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address
 }
 EXPORT_SYMBOL(km_report);
 
+bool km_is_alive(const struct km_event *c)
+{
+       struct xfrm_mgr *km;
+       bool is_alive = false;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(km, &xfrm_km_list, list) {
+               if (km->is_alive && km->is_alive(c)) {
+                       is_alive = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       return is_alive;
+}
+EXPORT_SYMBOL(km_is_alive);
+
 int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
 {
        int err;
index 1ae3ec7c18b0de977b1b781c8fee72d8357543bc..8f131c10a6f3d6793c6d0a049108ab66ccaa8664 100644 (file)
 #include <linux/in6.h>
 #endif
 
-static inline int aead_len(struct xfrm_algo_aead *alg)
-{
-       return sizeof(*alg) + ((alg->alg_key_len + 7) / 8);
-}
-
 static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type)
 {
        struct nlattr *rt = attrs[type];
@@ -142,7 +137,8 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
        if (!rt)
                return 0;
 
-       if (p->id.proto != IPPROTO_ESP)
+       /* As only ESP and AH support ESN feature. */
+       if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
                return -EINVAL;
 
        if (p->replay_window != 0)
@@ -886,6 +882,7 @@ static int xfrm_dump_sa_done(struct netlink_callback *cb)
        return 0;
 }
 
+static const struct nla_policy xfrma_policy[XFRMA_MAX+1];
 static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct net *net = sock_net(skb->sk);
@@ -901,8 +898,31 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
        info.nlmsg_flags = NLM_F_MULTI;
 
        if (!cb->args[0]) {
+               struct nlattr *attrs[XFRMA_MAX+1];
+               struct xfrm_address_filter *filter = NULL;
+               u8 proto = 0;
+               int err;
+
                cb->args[0] = 1;
-               xfrm_state_walk_init(walk, 0);
+
+               err = nlmsg_parse(cb->nlh, 0, attrs, XFRMA_MAX,
+                                 xfrma_policy);
+               if (err < 0)
+                       return err;
+
+               if (attrs[XFRMA_ADDRESS_FILTER]) {
+                       filter = kmalloc(sizeof(*filter), GFP_KERNEL);
+                       if (filter == NULL)
+                               return -ENOMEM;
+
+                       memcpy(filter, nla_data(attrs[XFRMA_ADDRESS_FILTER]),
+                              sizeof(*filter));
+               }
+
+               if (attrs[XFRMA_PROTO])
+                       proto = nla_get_u8(attrs[XFRMA_PROTO]);
+
+               xfrm_state_walk_init(walk, proto, filter);
        }
 
        (void) xfrm_state_walk(net, walk, dump_one_state, &info);
@@ -1226,7 +1246,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs
                return 0;
 
        uctx = nla_data(rt);
-       return security_xfrm_policy_alloc(&pol->security, uctx);
+       return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL);
 }
 
 static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
@@ -1631,7 +1651,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
                if (rt) {
                        struct xfrm_user_sec_ctx *uctx = nla_data(rt);
 
-                       err = security_xfrm_policy_alloc(&ctx, uctx);
+                       err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
                        if (err)
                                return err;
                }
@@ -1933,7 +1953,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
                if (rt) {
                        struct xfrm_user_sec_ctx *uctx = nla_data(rt);
 
-                       err = security_xfrm_policy_alloc(&ctx, uctx);
+                       err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
                        if (err)
                                return err;
                }
@@ -2308,6 +2328,8 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
        [XFRMA_TFCPAD]          = { .type = NLA_U32 },
        [XFRMA_REPLAY_ESN_VAL]  = { .len = sizeof(struct xfrm_replay_state_esn) },
        [XFRMA_SA_EXTRA_FLAGS]  = { .type = NLA_U32 },
+       [XFRMA_PROTO]           = { .type = NLA_U8 },
+       [XFRMA_ADDRESS_FILTER]  = { .len = sizeof(struct xfrm_address_filter) },
 };
 
 static const struct xfrm_link {
@@ -2981,6 +3003,11 @@ static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr,
        return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC);
 }
 
+static bool xfrm_is_alive(const struct km_event *c)
+{
+       return (bool)xfrm_acquire_is_on(c->net);
+}
+
 static struct xfrm_mgr netlink_mgr = {
        .id             = "netlink",
        .notify         = xfrm_send_state_notify,
@@ -2990,6 +3017,7 @@ static struct xfrm_mgr netlink_mgr = {
        .report         = xfrm_send_report,
        .migrate        = xfrm_send_migrate,
        .new_mapping    = xfrm_send_mapping,
+       .is_alive       = xfrm_is_alive,
 };
 
 static int __net_init xfrm_user_net_init(struct net *net)
index 49392ecbef17baf113bb9e3771384d06413bbb25..79c059e708600b04b63f8bc27cca94b485684cc8 100644 (file)
@@ -152,6 +152,7 @@ ld_flags       = $(LDFLAGS) $(ldflags-y)
 dtc_cpp_flags  = -Wp,-MD,$(depfile).pre.tmp -nostdinc                    \
                 -I$(srctree)/arch/$(SRCARCH)/boot/dts                   \
                 -I$(srctree)/arch/$(SRCARCH)/boot/dts/include           \
+                -I$(srctree)/drivers/of/testcase-data                   \
                 -undef -D__DTS__
 
 # Finds the multi-part object the current object will be linked into
index 0ea2a1e24ade493ed22c6b817c91a07736b11563..464dcef79b353be5426115fb3fb8ba1f746546df 100755 (executable)
@@ -471,7 +471,7 @@ sub seed_camelcase_includes {
 
        $camelcase_seeded = 1;
 
-       if (-d ".git") {
+       if (-e ".git") {
                my $git_last_include_commit = `git log --no-merges --pretty=format:"%h%n" -1 -- include`;
                chomp $git_last_include_commit;
                $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit";
@@ -499,7 +499,7 @@ sub seed_camelcase_includes {
                return;
        }
 
-       if (-d ".git") {
+       if (-e ".git") {
                $files = `git ls-files "include/*.h"`;
                @include_files = split('\n', $files);
        }
index ef474098d9f1d1e2609221d3d3571c1f29d1b599..17fa901418ae6a491ba61f3814a1143e2a62bfde 100644 (file)
@@ -257,7 +257,7 @@ case "$arg" in
                 && compr="lzop -9 -f"
                echo "$output_file" | grep -q "\.lz4$" \
                 && [ -x "`which lz4 2> /dev/null`" ] \
-                && compr="lz4 -9 -f"
+                && compr="lz4 -l -9 -f"
                echo "$output_file" | grep -q "\.cpio$" && compr="cat"
                shift
                ;;
index 9c3986f4140c47c089f96bead3331a5b5d9d6cef..41987885bd31db413f484ada73556d90f59d9577 100755 (executable)
@@ -95,7 +95,7 @@ my %VCS_cmds;
 
 my %VCS_cmds_git = (
     "execute_cmd" => \&git_execute_cmd,
-    "available" => '(which("git") ne "") && (-d ".git")',
+    "available" => '(which("git") ne "") && (-e ".git")',
     "find_signers_cmd" =>
        "git log --no-color --follow --since=\$email_git_since " .
            '--numstat --no-merges ' .
index 23708636b05c873f78b1ef5911eb795ba7114497..25e5cb0aaef6fd68fd77d15037a66f046e6c72e6 100644 (file)
@@ -210,8 +210,8 @@ static void do_usb_entry(void *symval,
                                range_lo < 0x9 ? "[%X-9" : "[%X",
                                range_lo);
                        sprintf(alias + strlen(alias),
-                               range_hi > 0xA ? "a-%X]" : "%X]",
-                               range_lo);
+                               range_hi > 0xA ? "A-%X]" : "%X]",
+                               range_hi);
                }
        }
        if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1))
index 40610984a1b54b06c579f953dabeb5ddb1304525..99a45fdc1bbfa9a15e7bbd6e4f9ec14a8a8c2357 100644 (file)
@@ -1502,6 +1502,16 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 #define R_ARM_JUMP24   29
 #endif
 
+#ifndef        R_ARM_THM_CALL
+#define        R_ARM_THM_CALL          10
+#endif
+#ifndef        R_ARM_THM_JUMP24
+#define        R_ARM_THM_JUMP24        30
+#endif
+#ifndef        R_ARM_THM_JUMP19
+#define        R_ARM_THM_JUMP19        51
+#endif
+
 static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 {
        unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1515,6 +1525,9 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
        case R_ARM_PC24:
        case R_ARM_CALL:
        case R_ARM_JUMP24:
+       case R_ARM_THM_CALL:
+       case R_ARM_THM_JUMP24:
+       case R_ARM_THM_JUMP19:
                /* From ARM ABI: ((S + A) | T) - P */
                r->r_addend = (int)(long)(elf->hdr +
                              sechdr->sh_offset +
index 8b4f24ae43381de05af67271edd9a8ddd57c651f..21e2b9cae685f01536ed159443707d5046c8c34c 100644 (file)
@@ -757,7 +757,8 @@ static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
-                                         struct xfrm_user_sec_ctx *sec_ctx)
+                                         struct xfrm_user_sec_ctx *sec_ctx,
+                                         gfp_t gfp)
 {
        return 0;
 }
index d46cbc5e335e9c330ccd74a08fcbf78aeafe8c96..2fb2576dc6448b3c1020dc311e0d81bfe77fb768 100644 (file)
@@ -1000,7 +1000,11 @@ static int keyring_detect_cycle_iterator(const void *object,
 
        kenter("{%d}", key->serial);
 
-       BUG_ON(key != ctx->match_data);
+       /* We might get a keyring with matching index-key that is nonetheless a
+        * different keyring. */
+       if (key != ctx->match_data)
+               return 0;
+
        ctx->result = ERR_PTR(-EDEADLK);
        return 1;
 }
index 15b6928592ef68aac565e3fc94daf4737b6adc54..919cad93ac82fa2fa7c017b5c85353ca8ac6818e 100644 (file)
@@ -1317,9 +1317,11 @@ void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 
-int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx)
+int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
+                              struct xfrm_user_sec_ctx *sec_ctx,
+                              gfp_t gfp)
 {
-       return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx);
+       return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx, gfp);
 }
 EXPORT_SYMBOL(security_xfrm_policy_alloc);
 
index 4b34847208cc9690284e9e7c7b6f9a960cfbead3..b332e2cc0954becf1fa365f9690fef63d52ba97c 100644 (file)
@@ -668,7 +668,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
                if (flags[i] == SBLABEL_MNT)
                        continue;
                rc = security_context_to_sid(mount_options[i],
-                                            strlen(mount_options[i]), &sid);
+                                            strlen(mount_options[i]), &sid, GFP_KERNEL);
                if (rc) {
                        printk(KERN_WARNING "SELinux: security_context_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2489,7 +2489,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
                if (flags[i] == SBLABEL_MNT)
                        continue;
                len = strlen(mount_options[i]);
-               rc = security_context_to_sid(mount_options[i], len, &sid);
+               rc = security_context_to_sid(mount_options[i], len, &sid,
+                                            GFP_KERNEL);
                if (rc) {
                        printk(KERN_WARNING "SELinux: security_context_to_sid"
                               "(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2893,7 +2894,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
        if (rc)
                return rc;
 
-       rc = security_context_to_sid(value, size, &newsid);
+       rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
        if (rc == -EINVAL) {
                if (!capable(CAP_MAC_ADMIN)) {
                        struct audit_buffer *ab;
@@ -3050,7 +3051,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
        if (!value || !size)
                return -EACCES;
 
-       rc = security_context_to_sid((void *)value, size, &newsid);
+       rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
        if (rc)
                return rc;
 
@@ -5529,7 +5530,7 @@ static int selinux_setprocattr(struct task_struct *p,
                        str[size-1] = 0;
                        size--;
                }
-               error = security_context_to_sid(value, size, &sid);
+               error = security_context_to_sid(value, size, &sid, GFP_KERNEL);
                if (error == -EINVAL && !strcmp(name, "fscreate")) {
                        if (!capable(CAP_MAC_ADMIN)) {
                                struct audit_buffer *ab;
@@ -5638,7 +5639,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 
 static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
-       return security_context_to_sid(secdata, seclen, secid);
+       return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
 }
 
 static void selinux_release_secctx(char *secdata, u32 seclen)
index 8ed8daf7f1eed9df82f963294e89e849b0da4b1d..ce7852cf526b8e564f69a20c005da00a19a941ca 100644 (file)
@@ -134,7 +134,7 @@ int security_sid_to_context(u32 sid, char **scontext,
 int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
 
 int security_context_to_sid(const char *scontext, u32 scontext_len,
-       u32 *out_sid);
+                           u32 *out_sid, gfp_t gfp);
 
 int security_context_to_sid_default(const char *scontext, u32 scontext_len,
                                    u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
index 48c3cc94c1681718a78e6793c7e961e2d404f3fb..1450f85b946da462e5ef3576a50d979d15574b8f 100644 (file)
@@ -10,7 +10,8 @@
 #include <net/flow.h>
 
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
-                             struct xfrm_user_sec_ctx *uctx);
+                             struct xfrm_user_sec_ctx *uctx,
+                             gfp_t gfp);
 int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
                              struct xfrm_sec_ctx **new_ctxp);
 void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
@@ -45,10 +46,11 @@ static inline void selinux_xfrm_notify_policyload(void)
 {
        struct net *net;
 
-       atomic_inc(&flow_cache_genid);
        rtnl_lock();
-       for_each_net(net)
+       for_each_net(net) {
+               atomic_inc(&net->xfrm.flow_cache_genid);
                rt_genid_bump_all(net);
+       }
        rtnl_unlock();
 }
 #else
index 5122affe06a8840e193150d62bd9b2f996fe67fe..d60c0ee66387d8078055414992ad36d7a2d31fa8 100644 (file)
@@ -576,7 +576,7 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
        if (length)
                goto out;
 
-       length = security_context_to_sid(buf, size, &sid);
+       length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -731,11 +731,13 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
@@ -817,11 +819,13 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
                objname = namebuf;
        }
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
@@ -878,11 +882,13 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
@@ -934,7 +940,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s", con, user) != 2)
                goto out;
 
-       length = security_context_to_sid(con, strlen(con) + 1, &sid);
+       length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
        if (length)
                goto out;
 
@@ -994,11 +1000,13 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
        if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
                goto out;
 
-       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
+       length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
-       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid);
+       length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
+                                        GFP_KERNEL);
        if (length)
                goto out;
 
index c0f4988421292f0ab6610421704ee21381b59a0f..9c5cdc2caaef7637b4bf9178a8efcbe69558c6b9 100644 (file)
@@ -3338,10 +3338,10 @@ static int filename_write_helper(void *key, void *data, void *ptr)
        if (rc)
                return rc;
 
-       buf[0] = ft->stype;
-       buf[1] = ft->ttype;
-       buf[2] = ft->tclass;
-       buf[3] = otype->otype;
+       buf[0] = cpu_to_le32(ft->stype);
+       buf[1] = cpu_to_le32(ft->ttype);
+       buf[2] = cpu_to_le32(ft->tclass);
+       buf[3] = cpu_to_le32(otype->otype);
 
        rc = put_entry(buf, sizeof(u32), 4, fp);
        if (rc)
index 5d0144ee8ed6d58e1f75043edcd7995cf1ca3a0e..4bca49414a40e5a40c4369415f5c5b0aecba6347 100644 (file)
@@ -1289,16 +1289,18 @@ out:
  * @scontext: security context
  * @scontext_len: length in bytes
  * @sid: security identifier, SID
+ * @gfp: context for the allocation
  *
  * Obtains a SID associated with the security context that
  * has the string representation specified by @scontext.
  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
  * memory is available, or 0 on success.
  */
-int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
+int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
+                           gfp_t gfp)
 {
        return security_context_to_sid_core(scontext, scontext_len,
-                                           sid, SECSID_NULL, GFP_KERNEL, 0);
+                                           sid, SECSID_NULL, gfp, 0);
 }
 
 /**
index 0462cb3ff0a741a36b279dcef37ee784e8520c5c..98b042630a9eafcfa982a469461ee5fd4da362b7 100644 (file)
@@ -78,7 +78,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
  * xfrm_user_sec_ctx context.
  */
 static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
-                                  struct xfrm_user_sec_ctx *uctx)
+                                  struct xfrm_user_sec_ctx *uctx,
+                                  gfp_t gfp)
 {
        int rc;
        const struct task_security_struct *tsec = current_security();
@@ -94,7 +95,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
        if (str_len >= PAGE_SIZE)
                return -ENOMEM;
 
-       ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
+       ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
        if (!ctx)
                return -ENOMEM;
 
@@ -103,7 +104,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
        ctx->ctx_len = str_len;
        memcpy(ctx->ctx_str, &uctx[1], str_len);
        ctx->ctx_str[str_len] = '\0';
-       rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid);
+       rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp);
        if (rc)
                goto err;
 
@@ -282,9 +283,10 @@ int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
  * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
  */
 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
-                             struct xfrm_user_sec_ctx *uctx)
+                             struct xfrm_user_sec_ctx *uctx,
+                             gfp_t gfp)
 {
-       return selinux_xfrm_alloc_user(ctxp, uctx);
+       return selinux_xfrm_alloc_user(ctxp, uctx, gfp);
 }
 
 /*
@@ -332,7 +334,7 @@ int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
 int selinux_xfrm_state_alloc(struct xfrm_state *x,
                             struct xfrm_user_sec_ctx *uctx)
 {
-       return selinux_xfrm_alloc_user(&x->security, uctx);
+       return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
 }
 
 /*
index 7a20897d33dbc1147b381ca6884f87dc88eb7ff1..7403f348ed1425733ce77735c8dff37d1610ad4d 100644 (file)
@@ -133,7 +133,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
                kfree(data);
        }
        snd_card_unref(compr->card);
-       return 0;
+       return ret;
 }
 
 static int snd_compr_free(struct inode *inode, struct file *f)
index ec4536c8d8d43c0987d43fd0ef9d07fe9a417ef4..dafcf82139e2bbdcdb4bad0539ad6c616661d892 100644 (file)
@@ -932,7 +932,7 @@ int snd_hda_bus_new(struct snd_card *card,
 }
 EXPORT_SYMBOL_GPL(snd_hda_bus_new);
 
-#ifdef CONFIG_SND_HDA_GENERIC
+#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
 #define is_generic_config(codec) \
        (codec->modelname && !strcmp(codec->modelname, "generic"))
 #else
@@ -1339,23 +1339,15 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid)
 /*
  * Dynamic symbol binding for the codec parsers
  */
-#ifdef MODULE
-#define load_parser_sym(sym)           ((int (*)(struct hda_codec *))symbol_request(sym))
-#define unload_parser_addr(addr)       symbol_put_addr(addr)
-#else
-#define load_parser_sym(sym)           (sym)
-#define unload_parser_addr(addr)       do {} while (0)
-#endif
 
 #define load_parser(codec, sym) \
-       ((codec)->parser = load_parser_sym(sym))
+       ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym))
 
 static void unload_parser(struct hda_codec *codec)
 {
-       if (codec->parser) {
-               unload_parser_addr(codec->parser);
-               codec->parser = NULL;
-       }
+       if (codec->parser)
+               symbol_put_addr(codec->parser);
+       codec->parser = NULL;
 }
 
 /*
@@ -1570,7 +1562,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec)
 EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets);
 
 
-#ifdef CONFIG_SND_HDA_CODEC_HDMI
+#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
 /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */
 static bool is_likely_hdmi_codec(struct hda_codec *codec)
 {
@@ -1620,12 +1612,20 @@ int snd_hda_codec_configure(struct hda_codec *codec)
                patch = codec->preset->patch;
        if (!patch) {
                unload_parser(codec); /* to be sure */
-               if (is_likely_hdmi_codec(codec))
+               if (is_likely_hdmi_codec(codec)) {
+#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI)
                        patch = load_parser(codec, snd_hda_parse_hdmi_codec);
-#ifdef CONFIG_SND_HDA_GENERIC
-               if (!patch)
+#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI)
+                       patch = snd_hda_parse_hdmi_codec;
+#endif
+               }
+               if (!patch) {
+#if IS_MODULE(CONFIG_SND_HDA_GENERIC)
                        patch = load_parser(codec, snd_hda_parse_generic_codec);
+#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC)
+                       patch = snd_hda_parse_generic_codec;
 #endif
+               }
                if (!patch) {
                        printk(KERN_ERR "hda-codec: No codec parser is available\n");
                        return -ENODEV;
index 8321a97d5c05047ab2312f8c62603826041a1897..d9a09bdd09db656891aa51f910753b686dc79964 100644 (file)
@@ -3269,7 +3269,7 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol,
        mutex_unlock(&codec->control_mutex);
        snd_hda_codec_flush_cache(codec); /* flush the updates */
        if (err >= 0 && spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, ucontrol);
+               spec->cap_sync_hook(codec, kcontrol, ucontrol);
        return err;
 }
 
@@ -3390,7 +3390,7 @@ static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
                return ret;
 
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, ucontrol);
+               spec->cap_sync_hook(codec, kcontrol, ucontrol);
 
        return ret;
 }
@@ -3795,7 +3795,7 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
                return 0;
        snd_hda_activate_path(codec, path, true, false);
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, NULL);
+               spec->cap_sync_hook(codec, NULL, NULL);
        path_power_down_sync(codec, old_path);
        return 1;
 }
@@ -5270,7 +5270,7 @@ static void init_input_src(struct hda_codec *codec)
        }
 
        if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, NULL);
+               spec->cap_sync_hook(codec, NULL, NULL);
 }
 
 /* set right pin controls for digital I/O */
index 07f767231c9f439bef66a950f6a5cab3ce957156..c908afbe4d94662fcaa92cf4009efc64b2114680 100644 (file)
@@ -274,6 +274,7 @@ struct hda_gen_spec {
        void (*init_hook)(struct hda_codec *codec);
        void (*automute_hook)(struct hda_codec *codec);
        void (*cap_sync_hook)(struct hda_codec *codec,
+                             struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol);
 
        /* PCM hooks */
index fa2879a21a50a51beed9fdc1bcc77ea607b00b27..e354ab1ec20f2dcd942931582761cc10b5543648 100644 (file)
@@ -198,7 +198,7 @@ MODULE_DESCRIPTION("Intel HDA driver");
 #endif
 
 #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO)
-#ifdef CONFIG_SND_HDA_CODEC_HDMI
+#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI)
 #define SUPPORT_VGA_SWITCHEROO
 #endif
 #endif
index df3652ad15ef36224fdbc121ee1018116bab28c0..8ed0bcc0138637e69e19ff7056b99a86fac09fa6 100644 (file)
@@ -1026,6 +1026,9 @@ static void ad1884_fixup_thinkpad(struct hda_codec *codec,
                spec->gen.keep_eapd_on = 1;
                spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
                spec->eapd_nid = 0x12;
+               /* Analog PC Beeper - allow firmware/ACPI beeps */
+               spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
+               spec->gen.beep_nid = 0; /* no digital beep */
        }
 }
 
@@ -1092,6 +1095,7 @@ static int patch_ad1884(struct hda_codec *codec)
        spec = codec->spec;
 
        spec->gen.mixer_nid = 0x20;
+       spec->gen.mixer_merge_nid = 0x21;
        spec->gen.beep_nid = 0x10;
        set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
 
index 54d14793725a7dd93623083d29f72f41a5ddc4bd..46ecdbb9053f337ee6f1b199d9babdeb043d72d5 100644 (file)
@@ -2661,60 +2661,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec)
        return false;
 }
 
-/*
- * PCM stuffs
- */
-static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid,
-                                u32 stream_tag,
-                                int channel_id, int format)
-{
-       unsigned int oldval, newval;
-
-       if (!nid)
-               return;
-
-       snd_printdd(
-                  "ca0132_setup_stream: NID=0x%x, stream=0x%x, "
-                  "channel=%d, format=0x%x\n",
-                  nid, stream_tag, channel_id, format);
-
-       /* update the format-id if changed */
-       oldval = snd_hda_codec_read(codec, nid, 0,
-                                   AC_VERB_GET_STREAM_FORMAT,
-                                   0);
-       if (oldval != format) {
-               msleep(20);
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_STREAM_FORMAT,
-                                   format);
-       }
-
-       oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-       newval = (stream_tag << 4) | channel_id;
-       if (oldval != newval) {
-               snd_hda_codec_write(codec, nid, 0,
-                                   AC_VERB_SET_CHANNEL_STREAMID,
-                                   newval);
-       }
-}
-
-static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int val;
-
-       if (!nid)
-               return;
-
-       snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid);
-
-       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0);
-       if (!val)
-               return;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-}
-
 /*
  * PCM callbacks
  */
@@ -2726,7 +2672,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 {
        struct ca0132_spec *spec = codec->spec;
 
-       ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
+       snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
 
        return 0;
 }
@@ -2745,7 +2691,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
        if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
                msleep(50);
 
-       ca0132_cleanup_stream(codec, spec->dacs[0]);
+       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
 
        return 0;
 }
@@ -2822,10 +2768,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
                                        unsigned int format,
                                        struct snd_pcm_substream *substream)
 {
-       struct ca0132_spec *spec = codec->spec;
-
-       ca0132_setup_stream(codec, spec->adcs[substream->number],
-                           stream_tag, 0, format);
+       snd_hda_codec_setup_stream(codec, hinfo->nid,
+                                  stream_tag, 0, format);
 
        return 0;
 }
@@ -2839,7 +2783,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
        if (spec->dsp_state == DSP_DOWNLOADING)
                return 0;
 
-       ca0132_cleanup_stream(codec, hinfo->nid);
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
        return 0;
 }
 
@@ -4742,6 +4686,8 @@ static int patch_ca0132(struct hda_codec *codec)
                return err;
 
        codec->patch_ops = ca0132_patch_ops;
+       codec->pcm_format_first = 1;
+       codec->no_sticky_stream = 1;
 
        return 0;
 }
index 4e0ec146553dadebda31c7ea996a4583dc296764..bcf91bea33179ce50b9485fd1db59caf1349b64c 100644 (file)
@@ -3291,7 +3291,8 @@ static void cxt_update_headset_mode(struct hda_codec *codec)
 }
 
 static void cxt_update_headset_mode_hook(struct hda_codec *codec,
-                            struct snd_ctl_elem_value *ucontrol)
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
 {
        cxt_update_headset_mode(codec);
 }
index d9693ca9546f1a1bfa63685cb6126657fae58c3b..8d0a84436674bf893ec871173a53b00b89f92c68 100644 (file)
@@ -708,7 +708,8 @@ static void alc_inv_dmic_sync(struct hda_codec *codec, bool force)
 }
 
 static void alc_inv_dmic_hook(struct hda_codec *codec,
-                            struct snd_ctl_elem_value *ucontrol)
+                             struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
 {
        alc_inv_dmic_sync(codec, false);
 }
@@ -3218,7 +3219,8 @@ static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
 
 /* turn on/off mic-mute LED per capture hook */
 static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
-                              struct snd_ctl_elem_value *ucontrol)
+                                              struct snd_kcontrol *kcontrol,
+                                              struct snd_ctl_elem_value *ucontrol)
 {
        struct alc_spec *spec = codec->spec;
        unsigned int oldval = spec->gpio_led;
@@ -3528,7 +3530,8 @@ static void alc_update_headset_mode(struct hda_codec *codec)
 }
 
 static void alc_update_headset_mode_hook(struct hda_codec *codec,
-                            struct snd_ctl_elem_value *ucontrol)
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
 {
        alc_update_headset_mode(codec);
 }
@@ -3613,6 +3616,19 @@ static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
        }
 }
 
+static void alc_no_shutup(struct hda_codec *codec)
+{
+}
+
+static void alc_fixup_no_shutup(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->shutup = alc_no_shutup;
+       }
+}
+
 static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
@@ -3841,6 +3857,7 @@ enum {
        ALC269_FIXUP_HP_GPIO_LED,
        ALC269_FIXUP_INV_DMIC,
        ALC269_FIXUP_LENOVO_DOCK,
+       ALC269_FIXUP_NO_SHUTUP,
        ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
        ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
        ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
@@ -4017,6 +4034,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc_fixup_inv_dmic_0x12,
        },
+       [ALC269_FIXUP_NO_SHUTUP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_shutup,
+       },
        [ALC269_FIXUP_LENOVO_DOCK] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -4250,6 +4271,7 @@ static const struct hda_fixup alc269_fixups[] = {
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
@@ -4305,7 +4327,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
@@ -4314,6 +4338,54 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+       /* ALC282 */
+       SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       /* ALC290 */
+       SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -4329,6 +4401,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
+       SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
        SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
@@ -4350,6 +4423,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
        SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
        SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -4434,9 +4508,6 @@ static void alc269_fill_coef(struct hda_codec *codec)
 
        if (spec->codec_variant != ALC269_TYPE_ALC269VB)
                return;
-       /* ALC271X doesn't seem to support these COEFs (bko#52181) */
-       if (!strcmp(codec->chip_name, "ALC271X"))
-               return;
 
        if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
                alc_write_coef_idx(codec, 0xf, 0x960b);
@@ -5106,12 +5177,13 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_AUTO_MUTE),
        SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_AUTO_MUTE),
        SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE),
-       SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE),
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP),
        SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP),
index 6998cf29b9bc34016e2d2ee1574b6b3d02ce8ef2..3bc29c9b25296d6ed058eaf552bf71bdba356cab 100644 (file)
@@ -83,6 +83,7 @@ enum {
        STAC_DELL_M6_BOTH,
        STAC_DELL_EQ,
        STAC_ALIENWARE_M17X,
+       STAC_92HD89XX_HP_FRONT_JACK,
        STAC_92HD73XX_MODELS
 };
 
@@ -97,6 +98,7 @@ enum {
        STAC_92HD83XXX_HP_LED,
        STAC_92HD83XXX_HP_INV_LED,
        STAC_92HD83XXX_HP_MIC_LED,
+       STAC_HP_LED_GPIO10,
        STAC_92HD83XXX_HEADSET_JACK,
        STAC_92HD83XXX_HP,
        STAC_HP_ENVY_BASS,
@@ -194,7 +196,7 @@ struct sigmatel_spec {
        int default_polarity;
 
        unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
-       bool mic_mute_led_on; /* current mic mute state */
+       unsigned int mic_enabled; /* current mic mute state (bitmask) */
 
        /* stream */
        unsigned int stream_delay;
@@ -324,19 +326,26 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
 
 /* hook for controlling mic-mute LED GPIO */
 static void stac_capture_led_hook(struct hda_codec *codec,
-                              struct snd_ctl_elem_value *ucontrol)
+                                 struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
 {
        struct sigmatel_spec *spec = codec->spec;
-       bool mute;
+       unsigned int mask;
+       bool cur_mute, prev_mute;
 
-       if (!ucontrol)
+       if (!kcontrol || !ucontrol)
                return;
 
-       mute = !(ucontrol->value.integer.value[0] ||
-                ucontrol->value.integer.value[1]);
-       if (spec->mic_mute_led_on != mute) {
-               spec->mic_mute_led_on = mute;
-               if (mute)
+       mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       prev_mute = !spec->mic_enabled;
+       if (ucontrol->value.integer.value[0] ||
+           ucontrol->value.integer.value[1])
+               spec->mic_enabled |= mask;
+       else
+               spec->mic_enabled &= ~mask;
+       cur_mute = !spec->mic_enabled;
+       if (cur_mute != prev_mute) {
+               if (cur_mute)
                        spec->gpio_data |= spec->mic_mute_led_gpio;
                else
                        spec->gpio_data &= ~spec->mic_mute_led_gpio;
@@ -1788,6 +1797,12 @@ static const struct hda_pintbl intel_dg45id_pin_configs[] = {
        {}
 };
 
+static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x02A19010 },
+       {}
+};
+
 static void stac92hd73xx_fixup_ref(struct hda_codec *codec,
                                   const struct hda_fixup *fix, int action)
 {
@@ -1906,6 +1921,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = {
        [STAC_92HD73XX_NO_JD] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = stac92hd73xx_fixup_no_jd,
+       },
+       [STAC_92HD89XX_HP_FRONT_JACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac92hd89xx_hp_front_jack_pin_configs,
        }
 };
 
@@ -1966,6 +1985,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = {
                      "Alienware M17x", STAC_ALIENWARE_M17X),
        SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
                      "Alienware M17x R3", STAC_DELL_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
+                               "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
        {} /* terminator */
 };
 
@@ -2110,6 +2131,17 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
        }
 }
 
+static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gpio_led = 0x10; /* GPIO4 */
+               spec->default_polarity = 0;
+       }
+}
+
 static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
                                   const struct hda_fixup *fix, int action)
 {
@@ -2604,6 +2636,12 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = {
                .chained = true,
                .chain_id = STAC_92HD83XXX_HP,
        },
+       [STAC_HP_LED_GPIO10] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_led_gpio10,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
        [STAC_92HD83XXX_HEADSET_JACK] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = stac92hd83xxx_fixup_headset_jack,
@@ -2682,6 +2720,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = {
                          "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888,
                          "HP Envy Spectre", STAC_HP_ENVY_BASS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899,
+                         "HP Folio 13", STAC_HP_LED_GPIO10),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
                          "HP Folio", STAC_HP_BNB13_EQ),
        SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8,
@@ -4462,7 +4502,7 @@ static void stac_setup_gpio(struct hda_codec *codec)
        if (spec->mic_mute_led_gpio) {
                spec->gpio_mask |= spec->mic_mute_led_gpio;
                spec->gpio_dir |= spec->mic_mute_led_gpio;
-               spec->mic_mute_led_on = true;
+               spec->mic_enabled = 0;
                spec->gpio_data |= spec->mic_mute_led_gpio;
 
                spec->gen.cap_sync_hook = stac_capture_led_hook;
index 5799fbc24c28a20a8a19fc6b93acaca53528887a..8fe3b8c18ed4b2c25c00b4963ec766b7671829d9 100644 (file)
@@ -39,6 +39,7 @@ static void update_tpacpi_mute_led(void *private_data, int enabled)
 }
 
 static void update_tpacpi_micmute_led(struct hda_codec *codec,
+                                     struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
        if (!ucontrol || !led_set_func)
index ed6f199f8a38ac3d1412fc8efa4010ba23ecee4d..4cf3200e988b03adf40129af71cfe1c9bb51bb69 100644 (file)
@@ -238,11 +238,21 @@ void set_cs4245_adc_params(struct oxygen *chip,
        cs4245_write_spi(chip, CS4245_MCLK_FREQ);
 }
 
+static inline unsigned int shift_bits(unsigned int value,
+                                     unsigned int shift_from,
+                                     unsigned int shift_to,
+                                     unsigned int mask)
+{
+       if (shift_from < shift_to)
+               return (value << (shift_to - shift_from)) & mask;
+       else
+               return (value >> (shift_from - shift_to)) & mask;
+}
+
 unsigned int adjust_dg_dac_routing(struct oxygen *chip,
                                          unsigned int play_routing)
 {
        struct dg *data = chip->model_data;
-       unsigned int routing = 0;
 
        switch (data->output_sel) {
        case PLAYBACK_DST_HP:
@@ -252,15 +262,23 @@ unsigned int adjust_dg_dac_routing(struct oxygen *chip,
                        OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
                break;
        case PLAYBACK_DST_MULTICH:
-               routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
-                         (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
-                         (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
-                         (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
                oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
                        OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
                break;
        }
-       return routing;
+       return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC1_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC2_SOURCE_MASK) |
+              shift_bits(play_routing,
+                         OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
+                         OXYGEN_PLAY_DAC3_SOURCE_MASK);
 }
 
 void dump_cs4245_registers(struct oxygen *chip,
index 54f74f8cbb754a0e66aecc3953fff0c8ba63966c..4544d8eb1452b24638c969ed15432a6f41e98ef8 100644 (file)
@@ -11,7 +11,7 @@ config SND_BF5XX_I2S
 
 config SND_BF5XX_SOC_SSM2602
        tristate "SoC SSM2602 Audio Codec Add-On Card support"
-       depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+       depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S if !BF60x
        select SND_BF6XX_SOC_I2S if BF60x
        select SND_SOC_SSM2602
@@ -21,10 +21,9 @@ config SND_BF5XX_SOC_SSM2602
 
 config SND_SOC_BFIN_EVAL_ADAU1701
        tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && I2C
        select SND_BF5XX_SOC_I2S
        select SND_SOC_ADAU1701
-       select I2C
        help
          Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ
          board connected to one of the Blackfin evaluation boards like the
@@ -45,7 +44,7 @@ config SND_SOC_BFIN_EVAL_ADAU1373
 
 config SND_SOC_BFIN_EVAL_ADAV80X
        tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
-       depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
+       depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S
        select SND_SOC_ADAV80X
        help
@@ -58,7 +57,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X
 
 config SND_BF5XX_SOC_AD1836
        tristate "SoC AD1836 Audio support for BF5xx"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && SPI_MASTER
        select SND_BF5XX_SOC_I2S
        select SND_SOC_AD1836
        help
@@ -66,7 +65,7 @@ config SND_BF5XX_SOC_AD1836
 
 config SND_BF5XX_SOC_AD193X
        tristate "SoC AD193X Audio support for Blackfin"
-       depends on SND_BF5XX_I2S
+       depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI
        select SND_BF5XX_SOC_I2S
        select SND_SOC_AD193X
        help
index 75d0ad5d2dcb38107934536ba7ef93410025c2f6..647a72cda005a5cc4f8b362fefe8aa1ad3f68a76 100644 (file)
@@ -1328,6 +1328,9 @@ static int pm860x_probe(struct snd_soc_codec *codec)
        pm860x->codec = codec;
 
        codec->control_data = pm860x->regmap;
+       ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
+       if (ret)
+               return ret;
 
        for (i = 0; i < 4; i++) {
                ret = request_threaded_irq(pm860x->irq[i], NULL,
index 7257a8885f426d7cf05b017fbda1aa3f01abe236..34d965a4a040c91d861a8d2f8a3ef183b95bc5e8 100644 (file)
@@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = {
 static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
                "Stereo Mix", "Mono Mix", "Phone"};
 
-static const struct soc_enum ad1980_cap_src =
-       SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel);
+static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src,
+                           AC97_REC_SEL, 8, 0, ad1980_rec_sel);
 
 static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = {
 SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1),
index f295b65699105897743fad1ecbc4439a71e58f0e..f4d965ebc29e8320469becd09a3ac58a2668e8de 100644 (file)
@@ -1268,11 +1268,23 @@ static struct snd_soc_dai_driver da732x_dai[] = {
        },
 };
 
+static bool da732x_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case DA732X_REG_HPL_DAC_OFF_CNTL:
+       case DA732X_REG_HPR_DAC_OFF_CNTL:
+               return true;
+       default:
+               return false;
+       }
+}
+
 static const struct regmap_config da732x_regmap = {
        .reg_bits               = 8,
        .val_bits               = 8,
 
        .max_register           = DA732X_MAX_REG,
+       .volatile_reg           = da732x_volatile,
        .reg_defaults           = da732x_reg_cache,
        .num_reg_defaults       = ARRAY_SIZE(da732x_reg_cache),
        .cache_type             = REGCACHE_RBTREE,
index 52b79a487ac7db318dd252fe30befd6a3c56b2ec..422812613a28b1cff117b1adfee2029b69e6049b 100644 (file)
@@ -1523,8 +1523,15 @@ static int da9055_remove(struct i2c_client *client)
        return 0;
 }
 
+/*
+ * DO NOT change the device Ids. The naming is intentionally specific as both
+ * the CODEC and PMIC parts of this chip are instantiated separately as I2C
+ * devices (both have configurable I2C addresses, and are to all intents and
+ * purposes separate). As a result there are specific DA9055 Ids for CODEC
+ * and PMIC, which must be different to operate together.
+ */
 static const struct i2c_device_id da9055_i2c_id[] = {
-       { "da9055", 0 },
+       { "da9055-codec", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
@@ -1532,7 +1539,7 @@ MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 /* I2C codec control layer */
 static struct i2c_driver da9055_i2c_driver = {
        .driver = {
-               .name = "da9055",
+               .name = "da9055-codec",
                .owner = THIS_MODULE,
        },
        .probe          = da9055_i2c_probe,
index 5839048ec4674e5d20cc5f06e206c2210977999e..cb736ddc446dc0bc5a387dc3ebc28e4bb0fee9aa 100644 (file)
@@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"};
 static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"};
 
 static const struct soc_enum isabelle_rx1_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts),
-       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts),
+       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3,
+                       ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5,
+                       ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts),
 };
 
 static const struct soc_enum isabelle_rx2_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts),
-       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts),
+       SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2,
+                       ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4,
+                       ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts),
 };
 
 /* Headset DAC playback switches */
@@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"};
 static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"};
 
 static const struct soc_enum isabelle_atx_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts),
-       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+                       ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts),
 };
 
 static const struct soc_enum isabelle_vtx_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts),
-       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6,
+                       ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
+       SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0,
+                       ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts),
 };
 
 static const struct snd_kcontrol_new atx_mux_controls =
@@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = {
 /* Left analog microphone selection */
 static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"};
 
-static const struct soc_enum isabelle_amic1_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5,
-                       ARRAY_SIZE(isabelle_amic1_texts),
-                       isabelle_amic1_texts),
-};
+static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum,
+                           ISABELLE_AMIC_CFG_REG, 5,
+                           isabelle_amic1_texts);
 
-static const struct soc_enum isabelle_amic2_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4,
-                       ARRAY_SIZE(isabelle_amic2_texts),
-                       isabelle_amic2_texts),
-};
+static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum,
+                           ISABELLE_AMIC_CFG_REG, 4,
+                           isabelle_amic2_texts);
 
 static const struct snd_kcontrol_new amic1_control =
        SOC_DAPM_ENUM("Route", isabelle_amic1_enum);
@@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"};
 static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"};
 
 static const struct soc_enum isabelle_st_audio_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_audio_texts),
                        isabelle_st_audio_texts),
-       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_audio_texts),
                        isabelle_st_audio_texts),
 };
 
 static const struct soc_enum isabelle_st_voice_enum[] = {
-       SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_voice_texts),
                        isabelle_st_voice_texts),
-       SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1,
+       SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7,
+                       ARRAY_SIZE(isabelle_st_voice_texts),
                        isabelle_st_voice_texts),
 };
 
index 51f9b3d16b41dbf4cc80dddc6d0a081ccb83fe90..9f714ea86613cc6939c62c3a420dc0c2ce07bb17 100644 (file)
@@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg)
        case M98090_REG_RECORD_TDM_SLOT:
        case M98090_REG_SAMPLE_RATE:
        case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E:
+       case M98090_REG_REVISION_ID:
                return true;
        default:
                return false;
@@ -1769,16 +1770,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
-                       ret = regcache_sync(max98090->regmap);
-
-                       if (ret != 0) {
-                               dev_err(codec->dev,
-                                       "Failed to sync cache: %d\n", ret);
-                               return ret;
-                       }
-               }
-
                if (max98090->jack_state == M98090_JACK_STATE_HEADSET) {
                        /*
                         * Set to normal bias level.
@@ -1792,6 +1783,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
                break;
 
        case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       ret = regcache_sync(max98090->regmap);
+                       if (ret != 0) {
+                               dev_err(codec->dev,
+                                       "Failed to sync cache: %d\n", ret);
+                               return ret;
+                       }
+               }
+               break;
+
        case SND_SOC_BIAS_OFF:
                /* Set internal pull-up to lowest power mode */
                snd_soc_update_bits(codec, M98090_REG_JACK_DETECT,
index a3fb411796364a683d554b6278ba9bda6b942326..886924934aa5c7db067f352aafc4113d5ab97c06 100644 (file)
@@ -2093,6 +2093,7 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
 #ifdef CONFIG_ACPI
 static struct acpi_device_id rt5640_acpi_match[] = {
        { "INT33CA", 0 },
+       { "10EC5640", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
index 52e7cb08434bd281354c4a34f520f16c38b0446f..fa2b8e07f420dd9c14ac0dc944babfe66dfbe2b2 100644 (file)
@@ -210,7 +210,7 @@ out:
 static int si476x_codec_probe(struct snd_soc_codec *codec)
 {
        codec->control_data = dev_get_regmap(codec->dev->parent, NULL);
-       return 0;
+       return snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
 }
 
 static struct snd_soc_dai_ops si476x_dai_ops = {
index 06edb396e733f1ad2ef26698a41b4eb1fdc18ea6..2735361a4c3cfc5fbc652ee10d62ec2728626184 100644 (file)
@@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = {
        13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
 };
 
-static const struct soc_enum sta32x_drc_ac_enum =
-       SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
-                       2, sta32x_drc_ac);
-static const struct soc_enum sta32x_auto_eq_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
-                       3, sta32x_auto_eq_mode);
-static const struct soc_enum sta32x_auto_gc_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
-                       4, sta32x_auto_gc_mode);
-static const struct soc_enum sta32x_auto_xo_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
-                       16, sta32x_auto_xo_mode);
-static const struct soc_enum sta32x_preset_eq_enum =
-       SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
-                       32, sta32x_preset_eq_mode);
-static const struct soc_enum sta32x_limiter_ch1_enum =
-       SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
-                       3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter_ch2_enum =
-       SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
-                       3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter_ch3_enum =
-       SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
-                       3, sta32x_limiter_select);
-static const struct soc_enum sta32x_limiter1_attack_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT,
-                       16, sta32x_limiter_attack_rate);
-static const struct soc_enum sta32x_limiter2_attack_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT,
-                       16, sta32x_limiter_attack_rate);
-static const struct soc_enum sta32x_limiter1_release_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT,
-                       16, sta32x_limiter_release_rate);
-static const struct soc_enum sta32x_limiter2_release_rate_enum =
-       SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT,
-                       16, sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
+                           STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
+                           sta32x_drc_ac);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum,
+                           STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT,
+                           sta32x_auto_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum,
+                           STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT,
+                           sta32x_auto_gc_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum,
+                           STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT,
+                           sta32x_auto_xo_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum,
+                           STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT,
+                           sta32x_preset_eq_mode);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum,
+                           STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT,
+                           sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum,
+                           STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT,
+                           sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum,
+                           STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT,
+                           sta32x_limiter_select);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum,
+                           STA32X_L1AR, STA32X_LxA_SHIFT,
+                           sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum,
+                           STA32X_L2AR, STA32X_LxA_SHIFT,
+                           sta32x_limiter_attack_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum,
+                           STA32X_L1AR, STA32X_LxR_SHIFT,
+                           sta32x_limiter_release_rate);
+static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum,
+                           STA32X_L2AR, STA32X_LxR_SHIFT,
+                           sta32x_limiter_release_rate);
 
 /* byte array controls for setting biquad, mixer, scaling coefficients;
  * for biquads all five coefficients need to be set in one go,
@@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
 
 static int sta32x_cache_sync(struct snd_soc_codec *codec)
 {
-       struct sta32x_priv *sta32x = codec->control_data;
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        unsigned int mute;
        int rc;
 
@@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0,
 SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum),
 SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum),
 SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
-SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum),
+SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum),
 
 /* depending on mode, the attack/release thresholds have
  * two different enum definitions; provide both
index 48dc7d2fee36fc07c236f6e9a09ea74cdb38d824..6d684d934f4de1e2b2c43dfc18d5659ada570cf1 100644 (file)
@@ -117,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
 static const char *wm8400_digital_sidetone[] =
        {"None", "Left ADC", "Right ADC", "Reserved"};
 
-static const struct soc_enum wm8400_left_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
-               WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum,
+                           WM8400_DIGITAL_SIDE_TONE,
+                           WM8400_ADC_TO_DACL_SHIFT,
+                           wm8400_digital_sidetone);
 
-static const struct soc_enum wm8400_right_digital_sidetone_enum =
-SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE,
-               WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone);
+static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum,
+                           WM8400_DIGITAL_SIDE_TONE,
+                           WM8400_ADC_TO_DACR_SHIFT,
+                           wm8400_digital_sidetone);
 
 static const char *wm8400_adcmode[] =
        {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"};
 
-static const struct soc_enum wm8400_right_adcmode_enum =
-SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode);
+static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum,
+                           WM8400_ADC_CTRL,
+                           WM8400_ADC_HPF_CUT_SHIFT,
+                           wm8400_adcmode);
 
 static const struct snd_kcontrol_new wm8400_snd_controls[] = {
 /* INMIXL */
@@ -422,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT,
 static const char *wm8400_ainlmux[] =
        {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"};
 
-static const struct soc_enum wm8400_ainlmux_enum =
-SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT,
-       ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux);
+static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum,
+                           WM8400_INPUT_MIXER1,
+                           WM8400_AINLMODE_SHIFT,
+                           wm8400_ainlmux);
 
 static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls =
 SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
@@ -435,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum);
 static const char *wm8400_ainrmux[] =
        {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"};
 
-static const struct soc_enum wm8400_ainrmux_enum =
-SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT,
-       ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux);
+static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum,
+                           WM8400_INPUT_MIXER1,
+                           WM8400_AINRMODE_SHIFT,
+                           wm8400_ainrmux);
 
 static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls =
 SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum);
index 89a18d82f303e168f874a418840a9d33a4923910..5bce2101348514aa6508dc9dac7f895d176ae0d9 100644 (file)
@@ -196,8 +196,8 @@ static const char *ain_text[] = {
        "AIN5", "AIN6", "AIN7", "AIN8"
 };
 
-static const struct soc_enum ain_enum =
-       SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text);
+static SOC_ENUM_DOUBLE_DECL(ain_enum,
+                           WM8770_ADCMUX, 0, 4, ain_text);
 
 static const struct snd_kcontrol_new ain_mux =
        SOC_DAPM_ENUM("Capture Mux", ain_enum);
index e98bc7038a086b39231ecbb5196fb7a40fc92d1e..43c2201cb90131ebdb66e2f10326f4c904700011 100644 (file)
@@ -304,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1);
 
 static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" };
 
-static const struct soc_enum mic_bias_level =
-SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt);
+static SOC_ENUM_SINGLE_DECL(mic_bias_level,
+                           WM8900_REG_INCTL, 8, mic_bias_level_txt);
 
 static const char *dac_mute_rate_txt[] = { "Fast", "Slow" };
 
-static const struct soc_enum dac_mute_rate =
-SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt);
+static SOC_ENUM_SINGLE_DECL(dac_mute_rate,
+                           WM8900_REG_DACCTRL, 7, dac_mute_rate_txt);
 
 static const char *dac_deemphasis_txt[] = {
        "Disabled", "32kHz", "44.1kHz", "48kHz"
 };
 
-static const struct soc_enum dac_deemphasis =
-SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt);
+static SOC_ENUM_SINGLE_DECL(dac_deemphasis,
+                           WM8900_REG_DACCTRL, 4, dac_deemphasis_txt);
 
 static const char *adc_hpf_cut_txt[] = {
        "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"
 };
 
-static const struct soc_enum adc_hpf_cut =
-SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt);
+static SOC_ENUM_SINGLE_DECL(adc_hpf_cut,
+                           WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt);
 
 static const char *lr_txt[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum aifl_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(aifl_src,
+                           WM8900_REG_AUDIO1, 15, lr_txt);
 
-static const struct soc_enum aifr_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(aifr_src,
+                           WM8900_REG_AUDIO1, 14, lr_txt);
 
-static const struct soc_enum dacl_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(dacl_src,
+                           WM8900_REG_AUDIO2, 15, lr_txt);
 
-static const struct soc_enum dacr_src =
-SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt);
+static SOC_ENUM_SINGLE_DECL(dacr_src,
+                           WM8900_REG_AUDIO2, 14, lr_txt);
 
 static const char *sidetone_txt[] = {
        "Disabled", "Left ADC", "Right ADC"
 };
 
-static const struct soc_enum dacl_sidetone =
-SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt);
+static SOC_ENUM_SINGLE_DECL(dacl_sidetone,
+                           WM8900_REG_SIDETONE, 2, sidetone_txt);
 
-static const struct soc_enum dacr_sidetone =
-SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt);
+static SOC_ENUM_SINGLE_DECL(dacr_sidetone,
+                           WM8900_REG_SIDETONE, 0, sidetone_txt);
 
 static const struct snd_kcontrol_new wm8900_snd_controls[] = {
 SOC_ENUM("Mic Bias Level", mic_bias_level),
@@ -496,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0),
 
 static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" };
 
-static const struct soc_enum wm8900_lineout2_lp_mux =
-SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux);
+static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux,
+                           WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux);
 
 static const struct snd_kcontrol_new wm8900_lineout2_lp =
 SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux);
index b7488f190d2bc9d5b86da537a560fc6be9f6ca0a..d4248e00160e35a0bede71fcfbd7db785d49de89 100644 (file)
@@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
 
                        data32 &= 0xffffff;
 
-                       wm8994_bulk_write(codec->control_data,
+                       wm8994_bulk_write(wm8994->wm8994,
                                          data32 & 0xffffff,
                                          block_len / 2,
                                          (void *)(data + 8));
index 433d59a0f3efa025598cf5c63f42640120893f90..2ee23a39622c14f2cdbc072cdcdb496e8291e9c0 100644 (file)
@@ -1562,7 +1562,6 @@ static int wm8993_remove(struct snd_soc_codec *codec)
        struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 
        wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
-       regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies);
        return 0;
 }
 
index b9be9cbc460391d4530e970e3c77a0521109c2a2..adb72063d44ef6a0a5c9da1e2a53bd0d16a67825 100644 (file)
@@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = {
        "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz"
 };
 
-static const struct soc_enum sidetone_hpf =
-       SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text);
+static SOC_ENUM_SINGLE_DECL(sidetone_hpf,
+                           WM8994_SIDETONE, 7, sidetone_hpf_text);
 
 static const char *adc_hpf_text[] = {
        "HiFi", "Voice 1", "Voice 2", "Voice 3"
 };
 
-static const struct soc_enum aif1adc1_hpf =
-       SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf,
+                           WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text);
 
-static const struct soc_enum aif1adc2_hpf =
-       SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf,
+                           WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text);
 
-static const struct soc_enum aif2adc_hpf =
-       SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text);
+static SOC_ENUM_SINGLE_DECL(aif2adc_hpf,
+                           WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text);
 
 static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0);
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
@@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = {
        "Left", "Right"
 };
 
-static const struct soc_enum aif1adcl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1adcl_src,
+                           WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text);
 
-static const struct soc_enum aif1adcr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1adcr_src,
+                           WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text);
 
-static const struct soc_enum aif2adcl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2adcl_src,
+                           WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text);
 
-static const struct soc_enum aif2adcr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2adcr_src,
+                           WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text);
 
-static const struct soc_enum aif1dacl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1dacl_src,
+                           WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text);
 
-static const struct soc_enum aif1dacr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif1dacr_src,
+                           WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text);
 
-static const struct soc_enum aif2dacl_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src,
+                           WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text);
 
-static const struct soc_enum aif2dacr_src =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src,
+                           WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text);
 
 static const char *osr_text[] = {
        "Low Power", "High Performance",
 };
 
-static const struct soc_enum dac_osr =
-       SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(dac_osr,
+                           WM8994_OVERSAMPLING, 0, osr_text);
 
-static const struct soc_enum adc_osr =
-       SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
+static SOC_ENUM_SINGLE_DECL(adc_osr,
+                           WM8994_OVERSAMPLING, 1, osr_text);
 
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
@@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = {
        "30ms", "125ms", "250ms", "500ms",
 };
 
-static const struct soc_enum wm8958_aif1dac1_ng_hold =
-       SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE,
-                       WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold,
+                           WM8958_AIF1_DAC1_NOISE_GATE,
+                           WM8958_AIF1DAC1_NG_THR_SHIFT,
+                           wm8958_ng_text);
 
-static const struct soc_enum wm8958_aif1dac2_ng_hold =
-       SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE,
-                       WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold,
+                           WM8958_AIF1_DAC2_NOISE_GATE,
+                           WM8958_AIF1DAC2_NG_THR_SHIFT,
+                           wm8958_ng_text);
 
-static const struct soc_enum wm8958_aif2dac_ng_hold =
-       SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE,
-                       WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold,
+                           WM8958_AIF2_DAC_NOISE_GATE,
+                           WM8958_AIF2DAC_NG_THR_SHIFT,
+                           wm8958_ng_text);
 
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
@@ -1341,8 +1344,8 @@ static const char *adc_mux_text[] = {
        "DMIC",
 };
 
-static const struct soc_enum adc_enum =
-       SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text);
+static SOC_ENUM_SINGLE_DECL(adc_enum,
+                           0, 0, adc_mux_text);
 
 static const struct snd_kcontrol_new adcl_mux =
        SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum);
@@ -1478,14 +1481,14 @@ static const char *sidetone_text[] = {
        "ADC/DMIC1", "DMIC2",
 };
 
-static const struct soc_enum sidetone1_enum =
-       SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone1_enum,
+                           WM8994_SIDETONE, 0, sidetone_text);
 
 static const struct snd_kcontrol_new sidetone1_mux =
        SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum);
 
-static const struct soc_enum sidetone2_enum =
-       SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text);
+static SOC_ENUM_SINGLE_DECL(sidetone2_enum,
+                           WM8994_SIDETONE, 1, sidetone_text);
 
 static const struct snd_kcontrol_new sidetone2_mux =
        SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum);
@@ -1498,22 +1501,24 @@ static const char *loopback_text[] = {
        "None", "ADCDAT",
 };
 
-static const struct soc_enum aif1_loopback_enum =
-       SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2,
-                       loopback_text);
+static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum,
+                           WM8994_AIF1_CONTROL_2,
+                           WM8994_AIF1_LOOPBACK_SHIFT,
+                           loopback_text);
 
 static const struct snd_kcontrol_new aif1_loopback =
        SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum);
 
-static const struct soc_enum aif2_loopback_enum =
-       SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2,
-                       loopback_text);
+static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum,
+                           WM8994_AIF2_CONTROL_2,
+                           WM8994_AIF2_LOOPBACK_SHIFT,
+                           loopback_text);
 
 static const struct snd_kcontrol_new aif2_loopback =
        SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum);
 
-static const struct soc_enum aif1dac_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text);
+static SOC_ENUM_SINGLE_DECL(aif1dac_enum,
+                           WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text);
 
 static const struct snd_kcontrol_new aif1dac_mux =
        SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum);
@@ -1522,8 +1527,8 @@ static const char *aif2dac_text[] = {
        "AIF2DACDAT", "AIF3DACDAT",
 };
 
-static const struct soc_enum aif2dac_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text);
+static SOC_ENUM_SINGLE_DECL(aif2dac_enum,
+                           WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text);
 
 static const struct snd_kcontrol_new aif2dac_mux =
        SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum);
@@ -1532,8 +1537,8 @@ static const char *aif2adc_text[] = {
        "AIF2ADCDAT", "AIF3DACDAT",
 };
 
-static const struct soc_enum aif2adc_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text);
+static SOC_ENUM_SINGLE_DECL(aif2adc_enum,
+                           WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text);
 
 static const struct snd_kcontrol_new aif2adc_mux =
        SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum);
@@ -1542,14 +1547,14 @@ static const char *aif3adc_text[] = {
        "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM",
 };
 
-static const struct soc_enum wm8994_aif3adc_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text);
+static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum,
+                           WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
 
 static const struct snd_kcontrol_new wm8994_aif3adc_mux =
        SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum);
 
-static const struct soc_enum wm8958_aif3adc_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text);
+static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum,
+                           WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text);
 
 static const struct snd_kcontrol_new wm8958_aif3adc_mux =
        SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
@@ -1558,8 +1563,8 @@ static const char *mono_pcm_out_text[] = {
        "None", "AIF2ADCL", "AIF2ADCR",
 };
 
-static const struct soc_enum mono_pcm_out_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text);
+static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum,
+                           WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text);
 
 static const struct snd_kcontrol_new mono_pcm_out_mux =
        SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum);
@@ -1569,14 +1574,14 @@ static const char *aif2dac_src_text[] = {
 };
 
 /* Note that these two control shouldn't be simultaneously switched to AIF3 */
-static const struct soc_enum aif2dacl_src_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum,
+                           WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text);
 
 static const struct snd_kcontrol_new aif2dacl_src_mux =
        SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum);
 
-static const struct soc_enum aif2dacr_src_enum =
-       SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text);
+static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum,
+                           WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text);
 
 static const struct snd_kcontrol_new aif2dacr_src_mux =
        SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum);
index 70ff3772079f2186cdf2967c1c050ff95f37350b..5e3bc3c6801a6bbf9512731f6cd094b2eb41511f 100644 (file)
@@ -399,6 +399,7 @@ static struct platform_driver davinci_evm_driver = {
        .driver         = {
                .name   = "davinci_evm",
                .owner  = THIS_MODULE,
+               .pm     = &snd_soc_pm_ops,
                .of_match_table = of_match_ptr(davinci_evm_dt_ids),
        },
 };
index b7858bfa0295357bc5d3ca6d1328932595167b9e..670afa29e30d0d5b97f7c60601d1e40793b5b499 100644 (file)
@@ -263,7 +263,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
        struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
 
+       pm_runtime_get_sync(mcasp->dev);
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_AC97:
@@ -317,7 +319,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                break;
 
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -354,10 +357,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                break;
 
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
-
-       return 0;
+out:
+       pm_runtime_put_sync(mcasp->dev);
+       return ret;
 }
 
 static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
@@ -448,7 +453,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
        return 0;
 }
 
-static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
+static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
                                    int channels)
 {
        int i;
@@ -524,12 +529,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream,
        return 0;
 }
 
-static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
 {
        int i, active_slots;
        u32 mask = 0;
        u32 busel = 0;
 
+       if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
+               dev_err(mcasp->dev, "tdm slot %d not supported\n",
+                       mcasp->tdm_slots);
+               return -EINVAL;
+       }
+
        active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
        for (i = 0; i < active_slots; i++)
                mask |= (1 << i);
@@ -539,35 +550,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream)
        if (!mcasp->dat_port)
                busel = TXSEL;
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               /* bit stream is MSB first  with no delay */
-               /* DSP_B mode */
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
-
-               if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
-                                      FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
-               else
-                       printk(KERN_ERR "playback tdm slot %d not supported\n",
-                               mcasp->tdm_slots);
-       } else {
-               /* bit stream is MSB first with no delay */
-               /* DSP_B mode */
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
-               mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
-
-               if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32))
-                       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
-                                      FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
-               else
-                       printk(KERN_ERR "capture tdm slot %d not supported\n",
-                               mcasp->tdm_slots);
-       }
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+                      FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
+
+       mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
+       mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
+       mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
+                      FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
+
+       return 0;
 }
 
 /* S/PDIF */
-static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
+static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp)
 {
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
@@ -589,6 +586,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp)
 
        /* Enable the DIT */
        mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);
+
+       return 0;
 }
 
 static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
@@ -605,13 +604,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
        u8 slots = mcasp->tdm_slots;
        u8 active_serializers;
        int channels;
+       int ret;
        struct snd_interval *pcm_channels = hw_param_interval(params,
                                        SNDRV_PCM_HW_PARAM_CHANNELS);
        channels = pcm_channels->min;
 
        active_serializers = (channels + slots - 1) / slots;
 
-       if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL)
+       if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL)
                return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                fifo_level = mcasp->txnumevt * active_serializers;
@@ -619,9 +619,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                fifo_level = mcasp->rxnumevt * active_serializers;
 
        if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
-               davinci_hw_dit_param(mcasp);
+               ret = mcasp_dit_hw_param(mcasp);
        else
-               davinci_hw_param(mcasp, substream->stream);
+               ret = mcasp_i2s_hw_param(mcasp, substream->stream);
+
+       if (ret)
+               return ret;
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_U8:
@@ -678,19 +681,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               ret = pm_runtime_get_sync(mcasp->dev);
-               if (IS_ERR_VALUE(ret))
-                       dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n");
                davinci_mcasp_start(mcasp, substream->stream);
                break;
-
        case SNDRV_PCM_TRIGGER_SUSPEND:
-               davinci_mcasp_stop(mcasp, substream->stream);
-               ret = pm_runtime_put_sync(mcasp->dev);
-               if (IS_ERR_VALUE(ret))
-                       dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n");
-               break;
-
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                davinci_mcasp_stop(mcasp, substream->stream);
index d0c72ed261e74c37f9d2b7cde738b34aab303ad4..c84026c991347f99014dad7df74c57731b789e24 100644 (file)
@@ -326,7 +326,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
        regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
                           ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
        regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
-                          ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
+                          ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask));
 
        regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
                           ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
@@ -334,7 +334,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
        regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
                           ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
        regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
-                          ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
+                          ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask));
 
        esai_priv->slot_width = slot_width;
 
index 9c9f957fcae179c2d3d5525161fdbb0a0e338204..75e14033e8d8f0a7da6b1db6387d543c5a9a1acc 100644 (file)
 #define ESAI_xSMB_xS_SHIFT     0
 #define ESAI_xSMB_xS_WIDTH     16
 #define ESAI_xSMB_xS_MASK      (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
-#define ESAI_xSMB_xS(v)                (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
+#define ESAI_xSMB_xS(v)                (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK)
 
 /* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
 #define ESAI_PRRC_PDC_SHIFT    0
index 79cee782dbbf9184264e69383b6d5a5ff1ba0fd7..a2fd7321b5a9a1bbd321f756af14fd9f071a372f 100644 (file)
@@ -160,7 +160,6 @@ static struct platform_driver imx_mc13783_audio_driver = {
        .driver = {
                .name = "imx_mc13783",
                .owner = THIS_MODULE,
-               .pm = &snd_soc_pm_ops,
        },
        .probe = imx_mc13783_probe,
        .remove = imx_mc13783_remove
index f2beae78969f6dd8e03125f92e3f288a8776f411..1cb22dd034eb63e98ac7e60e6d3ce5f719227db4 100644 (file)
@@ -33,8 +33,7 @@ struct imx_sgtl5000_data {
 
 static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct imx_sgtl5000_data *data = container_of(rtd->card,
-                                       struct imx_sgtl5000_data, card);
+       struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card);
        struct device *dev = rtd->card->dev;
        int ret;
 
@@ -159,13 +158,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
        data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
 
+       platform_set_drvdata(pdev, &data->card);
+       snd_soc_card_set_drvdata(&data->card, data);
+
        ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
                goto fail;
        }
 
-       platform_set_drvdata(pdev, data);
        of_node_put(ssi_np);
        of_node_put(codec_np);
 
@@ -184,7 +185,8 @@ fail:
 
 static int imx_sgtl5000_remove(struct platform_device *pdev)
 {
-       struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card);
 
        clk_put(data->codec_clk);
 
index 3fd76bc391de19a2431dd320d0abfbdcd9616cf5..3a3d17ce6ba40feea5dc6582693d7c1ee846ef13 100644 (file)
@@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card,
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
        struct imx_priv *priv = &card_priv;
-       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
        struct device *dev = &priv->pdev->dev;
        unsigned int pll_out;
        int ret;
@@ -137,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card)
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
        struct imx_priv *priv = &card_priv;
-       struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev);
+       struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
        struct device *dev = &priv->pdev->dev;
        int ret;
 
@@ -264,13 +264,15 @@ static int imx_wm8962_probe(struct platform_device *pdev)
        data->card.late_probe = imx_wm8962_late_probe;
        data->card.set_bias_level = imx_wm8962_set_bias_level;
 
+       platform_set_drvdata(pdev, &data->card);
+       snd_soc_card_set_drvdata(&data->card, data);
+
        ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
                goto clk_fail;
        }
 
-       platform_set_drvdata(pdev, data);
        of_node_put(ssi_np);
        of_node_put(codec_np);
 
@@ -289,7 +291,8 @@ fail:
 
 static int imx_wm8962_remove(struct platform_device *pdev)
 {
-       struct imx_wm8962_data *data = platform_get_drvdata(pdev);
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card);
 
        if (!IS_ERR(data->codec_clk))
                clk_disable_unprepare(data->codec_clk);
index 3fde9e402710f2bb16baf80b605da42772df69a0..d163e18d85d416b58be1dc5a905975c12623cfc9 100644 (file)
@@ -305,7 +305,9 @@ static int __init n810_soc_init(void)
        int err;
        struct device *dev;
 
-       if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax()))
+       if (!of_have_populated_dt() ||
+           (!of_machine_is_compatible("nokia,n810") &&
+            !of_machine_is_compatible("nokia,n810-wimax")))
                return -ENODEV;
 
        n810_snd_device = platform_device_alloc("soc-audio", -1);
index 454f41cfc82847e98a6297b2db5822db35d717a6..3507574003913b5023f66853a50bec809d6187bf 100644 (file)
@@ -59,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
        select SND_SOC_WM8750
        select SND_S3C2412_SOC_I2S
        help
-         Sat Y if you want to add support for SoC audio on the Jive.
+         Say Y if you want to add support for SoC audio on the Jive.
 
 config SND_SOC_SAMSUNG_SMDK_WM8580
        tristate "SoC I2S Audio support for WM8580 on SMDK"
@@ -145,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380
 
 config SND_SOC_SAMSUNG_SMDK_WM9713
        tristate "SoC AC97 Audio support for SMDK with WM9713"
-       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210)
+       depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
        select SND_SOC_WM9713
        select SND_SAMSUNG_AC97
        help
-         Sat Y if you want to add support for SoC audio on the SMDK.
+         Say Y if you want to add support for SoC audio on the SMDK.
 
 config SND_SOC_SMARTQ
        tristate "SoC I2S Audio support for SmartQ board"
index dc8ff13187f7ca91ef960312f48eac732c44d938..b9dc6acbba8c55661eb0cf423a02fb9b7dda1c87 100644 (file)
@@ -1218,7 +1218,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                        ret = regulator_allow_bypass(w->regulator, false);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
-                                        "ASoC: Failed to bypass %s: %d\n",
+                                        "ASoC: Failed to unbypass %s: %d\n",
                                         w->name, ret);
                }
 
@@ -1228,7 +1228,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
-                                        "ASoC: Failed to unbypass %s: %d\n",
+                                        "ASoC: Failed to bypass %s: %d\n",
                                         w->name, ret);
                }
 
@@ -3210,15 +3210,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
        const char *pin = (const char *)kcontrol->private_value;
 
-       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-
        if (ucontrol->value.integer.value[0])
                snd_soc_dapm_enable_pin(&card->dapm, pin);
        else
                snd_soc_dapm_disable_pin(&card->dapm, pin);
 
-       mutex_unlock(&card->dapm_mutex);
-
        snd_soc_dapm_sync(&card->dapm);
        return 0;
 }
@@ -3248,7 +3244,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
-                                        "ASoC: Failed to unbypass %s: %d\n",
+                                        "ASoC: Failed to bypass %s: %d\n",
                                         w->name, ret);
                }
                break;
@@ -3766,6 +3762,26 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
        mutex_unlock(&card->dapm_mutex);
 }
 
+/**
+ * snd_soc_dapm_enable_pin_unlocked - enable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Enables input/output pin and its parents or children widgets iff there is
+ * a valid audio route and active audio stream.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                  const char *pin)
+{
+       return snd_soc_dapm_set_pin(dapm, pin, 1);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked);
+
 /**
  * snd_soc_dapm_enable_pin - enable pin.
  * @dapm: DAPM context
@@ -3773,17 +3789,26 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
  *
  * Enables input/output pin and its parents or children widgets iff there is
  * a valid audio route and active audio stream.
+ *
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
 {
-       return snd_soc_dapm_set_pin(dapm, pin, 1);
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_set_pin(dapm, pin, 1);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
 
 /**
- * snd_soc_dapm_force_enable_pin - force a pin to be enabled
+ * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled
  * @dapm: DAPM context
  * @pin: pin name
  *
@@ -3791,11 +3816,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
  * intended for use with microphone bias supplies used in microphone
  * jack detection.
  *
+ * Requires external locking.
+ *
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
-int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
-                                 const char *pin)
+int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                        const char *pin)
 {
        struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
 
@@ -3811,24 +3838,102 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked);
+
+/**
+ * snd_soc_dapm_force_enable_pin - force a pin to be enabled
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Enables input/output pin regardless of any other state.  This is
+ * intended for use with microphone bias supplies used in microphone
+ * jack detection.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
+                                 const char *pin)
+{
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);
 
+/**
+ * snd_soc_dapm_disable_pin_unlocked - disable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Disables input/output pin and its parents or children widgets.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                                   const char *pin)
+{
+       return snd_soc_dapm_set_pin(dapm, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked);
+
 /**
  * snd_soc_dapm_disable_pin - disable pin.
  * @dapm: DAPM context
  * @pin: pin name
  *
  * Disables input/output pin and its parents or children widgets.
+ *
  * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  * do any widget power switching.
  */
 int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
                             const char *pin)
 {
-       return snd_soc_dapm_set_pin(dapm, pin, 0);
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_set_pin(dapm, pin, 0);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
 
+/**
+ * snd_soc_dapm_nc_pin_unlocked - permanently disable pin.
+ * @dapm: DAPM context
+ * @pin: pin name
+ *
+ * Marks the specified pin as being not connected, disabling it along
+ * any parent or child widgets.  At present this is identical to
+ * snd_soc_dapm_disable_pin() but in future it will be extended to do
+ * additional things such as disabling controls which only affect
+ * paths through the pin.
+ *
+ * Requires external locking.
+ *
+ * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
+ * do any widget power switching.
+ */
+int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm,
+                              const char *pin)
+{
+       return snd_soc_dapm_set_pin(dapm, pin, 0);
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked);
+
 /**
  * snd_soc_dapm_nc_pin - permanently disable pin.
  * @dapm: DAPM context
@@ -3845,7 +3950,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
  */
 int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
 {
-       return snd_soc_dapm_set_pin(dapm, pin, 0);
+       int ret;
+
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+
+       ret = snd_soc_dapm_set_pin(dapm, pin, 0);
+
+       mutex_unlock(&dapm->card->dapm_mutex);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);
 
index 47e1ce771e65e0403e1ab743c677083c98452a8c..28522bd03b8e05c7b1bf5fbf4af611efe109930d 100644 (file)
@@ -1989,6 +1989,7 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card)
 
                paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
                if (paths < 0) {
+                       dpcm_path_put(&list);
                        dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
                                        fe->dai_link->name,  "playback");
                        mutex_unlock(&card->mutex);
@@ -2018,6 +2019,7 @@ capture:
 
                paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
                if (paths < 0) {
+                       dpcm_path_put(&list);
                        dev_warn(fe->dev, "ASoC: %s no valid %s path\n",
                                        fe->dai_link->name,  "capture");
                        mutex_unlock(&card->mutex);
@@ -2082,6 +2084,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
        fe->dpcm[stream].runtime = fe_substream->runtime;
 
        if (dpcm_path_get(fe, stream, &list) <= 0) {
+               dpcm_path_put(&list);
                dev_dbg(fe->dev, "ASoC: %s no valid %s route\n",
                        fe->dai_link->name, stream ? "capture" : "playback");
        }
index e0305a1485680b18cbc85ba33a506bda799f47c1..9edd68db9f482e618e4e245a40dfbd0c94711e5d 100644 (file)
@@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        drvdata->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
 
-       drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
-       if (!drvdata)
-               return -ENOMEM;
        platform_set_drvdata(pdev, drvdata);
        drvdata->physbase = r->start;
        if (sizeof(drvdata->physbase) > sizeof(r->start) &&
index 44b0ba4feab3bd1b43100feb457e82e290ea26dc..1bed780e21d96945d1cf913ce23fe31409df0cc4 100644 (file)
@@ -883,6 +883,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
                }
                break;
 
+       case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
        case USB_ID(0x046d, 0x0808):
        case USB_ID(0x046d, 0x0809):
        case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
index 32af6b741ef5a8aff8581f90b0c5d583d151a6ee..d1d72ff50347a3118c2e90d5452457b8948ad0d6 100644 (file)
@@ -328,6 +328,11 @@ static struct usbmix_name_map gamecom780_map[] = {
        {}
 };
 
+static const struct usbmix_name_map kef_x300a_map[] = {
+       { 10, NULL }, /* firmware locks up (?) when we try to access this FU */
+       { 0 }
+};
+
 /*
  * Control map entries
  */
@@ -419,6 +424,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
                .id = USB_ID(0x200c, 0x1018),
                .map = ebox44_map,
        },
+       {
+               .id = USB_ID(0x27ac, 0x1000),
+               .map = kef_x300a_map,
+       },
        { 0 } /* terminator */
 };
 
index da8b7aa3d3518d1e52532af42974fc2e3981376f..07b0b7542511e9912e830b11885e1212bbf63a76 100644 (file)
@@ -87,8 +87,8 @@ endif # BUILD_SRC
 # We process the rest of the Makefile if this is the final invocation of make
 ifeq ($(skip-makefile),)
 
-srctree                := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
-objtree                := $(CURDIR)
+srctree                := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR)))
+objtree                := $(realpath $(CURDIR))
 src            := $(srctree)
 obj            := $(objtree)
 
@@ -112,7 +112,7 @@ export Q VERBOSE
 
 LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION)
 
-INCLUDES = -I. -I/usr/local/include -I./uinclude $(CONFIG_INCLUDES)
+INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES)
 
 # Set compile option CFLAGS if not set elsewhere
 CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g
index f8465a811aa554e6510477ac0c733b2eb02bb5f4..23bd69cb5ade7014e8630e87ad89a16e2d95be71 100644 (file)
@@ -418,7 +418,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
 
 __attribute__((constructor)) static void init_preload(void)
 {
-       if (__init_state != done)
+       if (__init_state == done)
                return;
 
 #ifndef __GLIBC__
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h
new file mode 100644 (file)
index 0000000..d82b170
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __ASM_GENERIC_HASH_H
+#define __ASM_GENERIC_HASH_H
+
+/* Stub */
+
+#endif /* __ASM_GENERIC_HASH_H */
index 4c99fcb5da2769ef48067b5e6adf05806e758396..042ee8e463c98bf03d9a92e4d18dd3c01ec32162 100644 (file)
@@ -13,4 +13,9 @@ static inline int rcu_is_cpu_idle(void)
        return 1;
 }
 
+static inline bool rcu_is_watching(void)
+{
+       return false;
+}
+
 #endif
index 004cd74734b62b941cf64db1634d2774f70f6e3c..ee577ea03ba50f05a4b14379ddcd17a3f73593c0 100644 (file)
@@ -12,7 +12,7 @@ YACC = bison
 
 all : bpf_jit_disasm bpf_dbg bpf_asm
 
-bpf_jit_disasm : CFLAGS = -Wall -O2
+bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
 bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
 bpf_jit_disasm : bpf_jit_disasm.o
 
index 65dc757f7f7b5c8d41bf49d95fe47df6b549c4fc..bb31813e43ddca8bd2bad4544e593d8c6df418f2 100644 (file)
@@ -87,9 +87,6 @@
        __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs))))
 #endif
 
-#define CMD(_name, _func) { .name = _name, .func = _func, }
-#define OP(_op, _name)      [_op] = _name
-
 enum {
        CMD_OK,
        CMD_ERR,
@@ -145,32 +142,32 @@ static size_t pcap_map_size = 0;
 static char *pcap_ptr_va_start, *pcap_ptr_va_curr;
 
 static const char * const op_table[] = {
-       OP(BPF_ST, "st"),
-       OP(BPF_STX, "stx"),
-       OP(BPF_LD_B, "ldb"),
-       OP(BPF_LD_H, "ldh"),
-       OP(BPF_LD_W, "ld"),
-       OP(BPF_LDX, "ldx"),
-       OP(BPF_LDX_B, "ldxb"),
-       OP(BPF_JMP_JA, "ja"),
-       OP(BPF_JMP_JEQ, "jeq"),
-       OP(BPF_JMP_JGT, "jgt"),
-       OP(BPF_JMP_JGE, "jge"),
-       OP(BPF_JMP_JSET, "jset"),
-       OP(BPF_ALU_ADD, "add"),
-       OP(BPF_ALU_SUB, "sub"),
-       OP(BPF_ALU_MUL, "mul"),
-       OP(BPF_ALU_DIV, "div"),
-       OP(BPF_ALU_MOD, "mod"),
-       OP(BPF_ALU_NEG, "neg"),
-       OP(BPF_ALU_AND, "and"),
-       OP(BPF_ALU_OR, "or"),
-       OP(BPF_ALU_XOR, "xor"),
-       OP(BPF_ALU_LSH, "lsh"),
-       OP(BPF_ALU_RSH, "rsh"),
-       OP(BPF_MISC_TAX, "tax"),
-       OP(BPF_MISC_TXA, "txa"),
-       OP(BPF_RET, "ret"),
+       [BPF_ST]        = "st",
+       [BPF_STX]       = "stx",
+       [BPF_LD_B]      = "ldb",
+       [BPF_LD_H]      = "ldh",
+       [BPF_LD_W]      = "ld",
+       [BPF_LDX]       = "ldx",
+       [BPF_LDX_B]     = "ldxb",
+       [BPF_JMP_JA]    = "ja",
+       [BPF_JMP_JEQ]   = "jeq",
+       [BPF_JMP_JGT]   = "jgt",
+       [BPF_JMP_JGE]   = "jge",
+       [BPF_JMP_JSET]  = "jset",
+       [BPF_ALU_ADD]   = "add",
+       [BPF_ALU_SUB]   = "sub",
+       [BPF_ALU_MUL]   = "mul",
+       [BPF_ALU_DIV]   = "div",
+       [BPF_ALU_MOD]   = "mod",
+       [BPF_ALU_NEG]   = "neg",
+       [BPF_ALU_AND]   = "and",
+       [BPF_ALU_OR]    = "or",
+       [BPF_ALU_XOR]   = "xor",
+       [BPF_ALU_LSH]   = "lsh",
+       [BPF_ALU_RSH]   = "rsh",
+       [BPF_MISC_TAX]  = "tax",
+       [BPF_MISC_TXA]  = "txa",
+       [BPF_RET]       = "ret",
 };
 
 static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...)
@@ -1127,7 +1124,6 @@ static int cmd_step(char *num)
 static int cmd_select(char *num)
 {
        unsigned int which, i;
-       struct pcap_pkthdr *hdr;
        bool have_next = true;
 
        if (!pcap_loaded() || strlen(num) == 0)
@@ -1144,7 +1140,7 @@ static int cmd_select(char *num)
 
        for (i = 0; i < which && (have_next = pcap_next_pkt()); i++)
                /* noop */;
-       if (!have_next || (hdr = pcap_curr_pkt()) == NULL) {
+       if (!have_next || pcap_curr_pkt() == NULL) {
                rl_printf("no packet #%u available!\n", which);
                pcap_reset_pkt();
                return CMD_ERR;
@@ -1177,9 +1173,8 @@ static int cmd_breakpoint(char *subcmd)
 static int cmd_run(char *num)
 {
        static uint32_t pass = 0, fail = 0;
-       struct pcap_pkthdr *hdr;
        bool has_limit = true;
-       int ret, pkts = 0, i = 0;
+       int pkts = 0, i = 0;
 
        if (!bpf_prog_loaded() || !pcap_loaded())
                return CMD_ERR;
@@ -1189,10 +1184,10 @@ static int cmd_run(char *num)
                has_limit = false;
 
        do {
-               hdr = pcap_curr_pkt();
-               ret = bpf_run_all(bpf_image, bpf_prog_len,
-                                 (uint8_t *) hdr + sizeof(*hdr),
-                                 hdr->caplen, hdr->len);
+               struct pcap_pkthdr *hdr = pcap_curr_pkt();
+               int ret = bpf_run_all(bpf_image, bpf_prog_len,
+                                     (uint8_t *) hdr + sizeof(*hdr),
+                                     hdr->caplen, hdr->len);
                if (ret > 0)
                        pass++;
                else if (ret == 0)
@@ -1245,14 +1240,14 @@ static int cmd_quit(char *dontcare)
 }
 
 static const struct shell_cmd cmds[] = {
-       CMD("load",             cmd_load),
-       CMD("select",           cmd_select),
-       CMD("step",             cmd_step),
-       CMD("run",              cmd_run),
-       CMD("breakpoint",       cmd_breakpoint),
-       CMD("disassemble",      cmd_disassemble),
-       CMD("dump",             cmd_dump),
-       CMD("quit",             cmd_quit),
+       { .name = "load", .func = cmd_load },
+       { .name = "select", .func = cmd_select },
+       { .name = "step", .func = cmd_step },
+       { .name = "run", .func = cmd_run },
+       { .name = "breakpoint", .func = cmd_breakpoint },
+       { .name = "disassemble", .func = cmd_disassemble },
+       { .name = "dump", .func = cmd_dump },
+       { .name = "quit", .func = cmd_quit },
 };
 
 static int execf(char *arg)
@@ -1280,7 +1275,6 @@ out:
 static char *shell_comp_gen(const char *buf, int state)
 {
        static int list_index, len;
-       const char *name;
 
        if (!state) {
                list_index = 0;
@@ -1288,9 +1282,9 @@ static char *shell_comp_gen(const char *buf, int state)
        }
 
        for (; list_index < array_size(cmds); ) {
-               name = cmds[list_index].name;
-               list_index++;
+               const char *name = cmds[list_index].name;
 
+               list_index++;
                if (strncmp(name, buf, len) == 0)
                        return strdup(name);
        }
@@ -1322,16 +1316,9 @@ static void init_shell(FILE *fin, FILE *fout)
 {
        char file[128];
 
-       memset(file, 0, sizeof(file));
-       snprintf(file, sizeof(file) - 1,
-                "%s/.bpf_dbg_history", getenv("HOME"));
-
+       snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME"));
        read_history(file);
 
-       memset(file, 0, sizeof(file));
-       snprintf(file, sizeof(file) - 1,
-                "%s/.bpf_dbg_init", getenv("HOME"));
-
        rl_instream = fin;
        rl_outstream = fout;
 
@@ -1348,37 +1335,41 @@ static void init_shell(FILE *fin, FILE *fout)
        rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap);
        rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap);
 
+       snprintf(file, sizeof(file), "%s/.bpf_dbg_init", getenv("HOME"));
        rl_read_init_file(file);
+
        rl_prep_terminal(0);
        rl_set_signals();
 
        signal(SIGINT, intr_shell);
 }
 
-static void exit_shell(void)
+static void exit_shell(FILE *fin, FILE *fout)
 {
        char file[128];
 
-       memset(file, 0, sizeof(file));
-       snprintf(file, sizeof(file) - 1,
-                "%s/.bpf_dbg_history", getenv("HOME"));
-
+       snprintf(file, sizeof(file), "%s/.bpf_dbg_history", getenv("HOME"));
        write_history(file);
+
        clear_history();
        rl_deprep_terminal();
 
        try_close_pcap();
+
+       if (fin != stdin)
+               fclose(fin);
+       if (fout != stdout)
+               fclose(fout);
 }
 
 static int run_shell_loop(FILE *fin, FILE *fout)
 {
        char *buf;
-       int ret;
 
        init_shell(fin, fout);
 
        while ((buf = readline("> ")) != NULL) {
-               ret = execf(buf);
+               int ret = execf(buf);
                if (ret == CMD_EX)
                        break;
                if (ret == CMD_OK && strlen(buf) > 0)
@@ -1387,7 +1378,7 @@ static int run_shell_loop(FILE *fin, FILE *fout)
                free(buf);
        }
 
-       exit_shell();
+       exit_shell(fin, fout);
        return 0;
 }
 
index d4c83c60b9b29fa7d6249de70e5f0673d2066287..97d86d828190950af7f133c1b8be72550070d3d1 100644 (file)
@@ -1593,6 +1593,7 @@ static void init_params(struct params *p, const char *name, int argc, const char
        p->data_rand_walk               = true;
        p->nr_loops                     = -1;
        p->init_random                  = true;
+       p->run_all                      = argc == 1;
 }
 
 static int run_bench_numa(const char *name, const char **argv)
index e47f90cc7b98cdde57079975bbd5637f3249ce44..8a987d2527803ff71f10314152162b29d61b486a 100644 (file)
@@ -76,7 +76,7 @@ static struct collection collections[] = {
 
 /* Iterate over all benchmarks within a collection: */
 #define for_each_bench(coll, bench) \
-       for (bench = coll->benchmarks; bench->name; bench++)
+       for (bench = coll->benchmarks; bench && bench->name; bench++)
 
 static void dump_benchmarks(struct collection *coll)
 {
index 3c53ec268fbc52a5298f390a83e3802eecd156a6..02f985f3a396916ff60e4fcd8123bc109fa0dab4 100644 (file)
@@ -113,14 +113,16 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati
        if (!he)
                return -ENOMEM;
 
-       err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
-       if (err)
-               goto out;
+       if (ui__has_annotation()) {
+               err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+               if (err)
+                       goto out;
 
-       mx = he->mem_info;
-       err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
-       if (err)
-               goto out;
+               mx = he->mem_info;
+               err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
+               if (err)
+                       goto out;
+       }
 
        evsel->hists.stats.total_period += cost;
        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -164,14 +166,18 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc
                he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
                                        1, 1, 0);
                if (he) {
-                       bx = he->branch_info;
-                       err = addr_map_symbol__inc_samples(&bx->from, evsel->idx);
-                       if (err)
-                               goto out;
-
-                       err = addr_map_symbol__inc_samples(&bx->to, evsel->idx);
-                       if (err)
-                               goto out;
+                       if (ui__has_annotation()) {
+                               bx = he->branch_info;
+                               err = addr_map_symbol__inc_samples(&bx->from,
+                                                                  evsel->idx);
+                               if (err)
+                                       goto out;
+
+                               err = addr_map_symbol__inc_samples(&bx->to,
+                                                                  evsel->idx);
+                               if (err)
+                                       goto out;
+                       }
 
                        evsel->hists.stats.total_period += 1;
                        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
@@ -205,7 +211,9 @@ static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evs
        if (err)
                goto out;
 
-       err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+       if (ui__has_annotation())
+               err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
+
        evsel->hists.stats.total_period += sample->period;
        hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
 out:
index 76cd510d34d023bf3c580ec2b3e2e217d8831cba..5f989a7d8bc2166e30d6bcbef710015f019ab252 100644 (file)
@@ -176,7 +176,7 @@ static void perf_top__record_precise_ip(struct perf_top *top,
 {
        struct annotation *notes;
        struct symbol *sym;
-       int err;
+       int err = 0;
 
        if (he == NULL || he->ms.sym == NULL ||
            ((top->sym_filter_entry == NULL ||
@@ -190,7 +190,9 @@ static void perf_top__record_precise_ip(struct perf_top *top,
                return;
 
        ip = he->ms.map->map_ip(he->ms.map, ip);
-       err = hist_entry__inc_addr_samples(he, counter, ip);
+
+       if (ui__has_annotation())
+               err = hist_entry__inc_addr_samples(he, counter, ip);
 
        pthread_mutex_unlock(&notes->lock);
 
index 896f27047ed6178fd6aed5566863fb4f4c251e84..f954c26de231d2860cf1b70a5ccb6597629137b8 100644 (file)
 # define MADV_UNMERGEABLE      13
 #endif
 
+#ifndef EFD_SEMAPHORE
+# define EFD_SEMAPHORE         1
+#endif
+
 struct tp_field {
        int offset;
        union {
@@ -279,6 +283,11 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
 
 #define SCA_STRARRAY syscall_arg__scnprintf_strarray
 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches as soon as the ioctl beautifier
+ *       gets rewritten to support all arches.
+ */
 static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
                                                 struct syscall_arg *arg)
 {
@@ -286,6 +295,7 @@ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
 }
 
 #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
+#endif /* defined(__i386__) || defined(__x86_64__) */
 
 static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
                                        struct syscall_arg *arg);
@@ -815,7 +825,6 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
        P_SIGNUM(PIPE);
        P_SIGNUM(ALRM);
        P_SIGNUM(TERM);
-       P_SIGNUM(STKFLT);
        P_SIGNUM(CHLD);
        P_SIGNUM(CONT);
        P_SIGNUM(STOP);
@@ -831,6 +840,15 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
        P_SIGNUM(IO);
        P_SIGNUM(PWR);
        P_SIGNUM(SYS);
+#ifdef SIGEMT
+       P_SIGNUM(EMT);
+#endif
+#ifdef SIGSTKFLT
+       P_SIGNUM(STKFLT);
+#endif
+#ifdef SIGSWI
+       P_SIGNUM(SWI);
+#endif
        default: break;
        }
 
@@ -839,6 +857,10 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal
 
 #define SCA_SIGNUM syscall_arg__scnprintf_signum
 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches.
+ */
 #define TCGETS         0x5401
 
 static const char *tioctls[] = {
@@ -860,6 +882,7 @@ static const char *tioctls[] = {
 };
 
 static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
+#endif /* defined(__i386__) || defined(__x86_64__) */
 
 #define STRARRAY(arg, name, array) \
          .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
@@ -941,9 +964,16 @@ static struct syscall_fmt {
        { .name     = "getrlimit",  .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
        { .name     = "ioctl",      .errmsg = true,
          .arg_scnprintf = { [0] = SCA_FD, /* fd */ 
+#if defined(__i386__) || defined(__x86_64__)
+/*
+ * FIXME: Make this available to all arches.
+ */
                             [1] = SCA_STRHEXARRAY, /* cmd */
                             [2] = SCA_HEX, /* arg */ },
          .arg_parm      = { [1] = &strarray__tioctls, /* cmd */ }, },
+#else
+                            [2] = SCA_HEX, /* arg */ }, },
+#endif
        { .name     = "kill",       .errmsg = true,
          .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
        { .name     = "linkat",     .errmsg = true,
index c48d44958172b7dd8f75634ece4d909ae2d5b15b..0331ea2701a380c536facf82b8306729f23d9de3 100644 (file)
@@ -478,7 +478,7 @@ else
 endif
 
 ifeq ($(feature-libbfd), 1)
-  EXTLIBS += -lbfd
+  EXTLIBS += -lbfd -lz -liberty
 endif
 
 ifdef NO_DEMANGLE
index 12e551346fa6414d7b85c69fcee0b224283fdc0c..523b7bc1055321051d62562f1f490165ea2872b5 100644 (file)
@@ -121,7 +121,7 @@ test-libpython-version.bin:
        $(BUILD) $(FLAGS_PYTHON_EMBED)
 
 test-libbfd.bin:
-       $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl
+       $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
 
 test-liberty.bin:
        $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty
index 469eb679fb9d09d9e96e8687cc2051fa44f86565..3aa555ff9d89e5d7ede4c6af067170197b9ce0e8 100644 (file)
@@ -8,6 +8,8 @@
  */
 
 #include "util.h"
+#include "ui/ui.h"
+#include "sort.h"
 #include "build-id.h"
 #include "color.h"
 #include "cache.h"
@@ -489,7 +491,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
 {
        struct annotation *notes;
 
-       if (sym == NULL || use_browser != 1 || !sort__has_sym)
+       if (sym == NULL)
                return 0;
 
        notes = symbol__annotation(sym);
@@ -1399,3 +1401,8 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize)
 {
        return symbol__annotate(he->ms.sym, he->ms.map, privsize);
 }
+
+bool ui__has_annotation(void)
+{
+       return use_browser == 1 && sort__has_sym;
+}
index b2aef59d6bb29741dff0dbee40fa0c1d04f1cf65..56ad4f5287dec04bf8e94fe15c814b6abc8b42ee 100644 (file)
@@ -151,6 +151,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
 void disasm__purge(struct list_head *head);
 
+bool ui__has_annotation(void);
+
 int symbol__tty_annotate(struct symbol *sym, struct map *map,
                         struct perf_evsel *evsel, bool print_lines,
                         bool full_paths, int min_pcnt, int max_lines);
index 45cf10a562bd7958c9edd160ab20a0725ecb0385..dadfa7e54287b9aaa46da7227d4b0f275717ddb2 100644 (file)
@@ -87,13 +87,15 @@ static __always_inline unsigned long __ffs(unsigned long word)
        return num;
 }
 
+typedef const unsigned long __attribute__((__may_alias__)) long_alias_t;
+
 /*
  * Find the first set bit in a memory region.
  */
 static inline unsigned long
 find_first_bit(const unsigned long *addr, unsigned long size)
 {
-       const unsigned long *p = addr;
+       long_alias_t *p = (long_alias_t *) addr;
        unsigned long result = 0;
        unsigned long tmp;
 
index c872991e0f655ba581443f0f413d81a5b910842f..620a1983b76b9921157c78f9ad3888851db1eb11 100644 (file)
@@ -1213,7 +1213,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
                 */
                thread__find_addr_location(thread, machine, m, MAP__FUNCTION,
                                ip, &al);
-               if (al.sym)
+               if (al.map)
                        goto found;
        }
 found:
index d248fca6d7ed7302c77d5500a79c853d3073ea07..1e15df10a88c2c1ff7b62dbfbcc05f39ffbe4cd1 100644 (file)
@@ -1091,12 +1091,12 @@ int is_valid_tracepoint(const char *event_string)
 static bool is_event_supported(u8 type, unsigned config)
 {
        bool ret = true;
+       int open_return;
        struct perf_evsel *evsel;
        struct perf_event_attr attr = {
                .type = type,
                .config = config,
                .disabled = 1,
-               .exclude_kernel = 1,
        };
        struct {
                struct thread_map map;
@@ -1108,7 +1108,20 @@ static bool is_event_supported(u8 type, unsigned config)
 
        evsel = perf_evsel__new(&attr);
        if (evsel) {
-               ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+               open_return = perf_evsel__open(evsel, NULL, &tmap.map);
+               ret = open_return >= 0;
+
+               if (open_return == -EACCES) {
+                       /*
+                        * This happens if the paranoid value
+                        * /proc/sys/kernel/perf_event_paranoid is set to 2
+                        * Re-run with exclude_kernel set; we don't do that
+                        * by default as some ARM machines do not support it.
+                        *
+                        */
+                       evsel->attr.exclude_kernel = 1;
+                       ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0;
+               }
                perf_evsel__delete(evsel);
        }
 
index a8a9b6cd93a8f080a968f1cd05e7f80bb0df0ca6..d8b048c20cdee51ac894b5394b15c70a1897c106 100644 (file)
@@ -336,8 +336,8 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
                return ret;
 
        for (i = 0; i < ntevs && ret >= 0; i++) {
+               /* point.address is the addres of point.symbol + point.offset */
                offset = tevs[i].point.address - stext;
-               offset += tevs[i].point.offset;
                tevs[i].point.offset = 0;
                zfree(&tevs[i].point.symbol);
                ret = e_snprintf(buf, 32, "0x%lx", offset);
index 0b39a48e5110a00dde5fa0408c725730ba5fe8ff..5da6ce74c676722ff13ae858c1bb579ba353edbf 100644 (file)
@@ -1008,6 +1008,12 @@ static int perf_session__process_user_event(struct perf_session *session, union
                if (err == 0)
                        perf_session__set_id_hdr_size(session);
                return err;
+       case PERF_RECORD_HEADER_EVENT_TYPE:
+               /*
+                * Depreceated, but we need to handle it for sake
+                * of old data files create in pipe mode.
+                */
+               return 0;
        case PERF_RECORD_HEADER_TRACING_DATA:
                /* setup for reading amidst mmap */
                lseek(fd, file_offset, SEEK_SET);
index 3e9f336740fa8699b2bdd16669e05cd8f8f6dede..516d19fb999bcfaddb6511e0292ea341a0e74aa6 100644 (file)
@@ -151,15 +151,15 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
 
                gelf_getshdr(sec, shp);
                str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
-               if (!strcmp(name, str)) {
+               if (str && !strcmp(name, str)) {
                        if (idx)
                                *idx = cnt;
-                       break;
+                       return sec;
                }
                ++cnt;
        }
 
-       return sec;
+       return NULL;
 }
 
 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
index a9d758a3b3719a0b8db5d7b5d239c7dea5ceb34e..e89afc097d8ad2d4b818f07e02321084110e6ddc 100644 (file)
@@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
 
                        if (syms_ss && runtime_ss)
                                break;
+               } else {
+                       symsrc__destroy(ss);
                }
 
        }
index d66418237d21522df42e33a316b808c1e5962ffd..aa290c0de6f56d9e3f142d46124ee5d0688dd68d 100644 (file)
@@ -201,6 +201,7 @@ int main(int argc, char **argv)
 
        msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
        if (msgque.msq_id == -1) {
+               err = -errno;
                printf("Can't create queue\n");
                goto err_out;
        }
index be456ce264d0b7cca15b61778f94f7290b33cf98..8ca405cd7c1afce8fbbf38a51bf5cd75b2f32168 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
+#include <linux/uaccess.h>
 
 #include <linux/irqchip/arm-gic.h>
 
index 88b2fe3ddf42a3c60bba0a3fbc1d7bd3172a8730..00d86427af0f8bae911c2e41a33303c2d02a3428 100644 (file)
@@ -154,17 +154,13 @@ int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
        list_add_tail(&dev->list, &kvm->coalesced_zones);
        mutex_unlock(&kvm->slots_lock);
 
-       return ret;
+       return 0;
 
 out_free_dev:
        mutex_unlock(&kvm->slots_lock);
-
        kfree(dev);
 
-       if (dev == NULL)
-               return -ENXIO;
-
-       return 0;
+       return ret;
 }
 
 int kvm_vm_ioctl_unregister_coalesced_mmio(struct kvm *kvm,